Select the types of activity you want to include in your feed.
fix(ocaml-requests): update tests and fuzz for cstruct→Bytes migration
Test files still referenced Cstruct.t where the API now uses bytes. Fixed all H2 frame, HPACK, client, and connection tests. Fixed fuzz test. 330 tests pass.
···5566(** Fuzz tests for OEM parsing.
7788- Key properties:
99- 1. Parsing never crashes on arbitrary input
1010- 2. Successfully parsed OEM can always be interpolated without crash
1111- 3. Pretty-printer never crashes *)
88+ Key properties: 1. Parsing never crashes on arbitrary input 2. Successfully
99+ parsed OEM can always be interpolated without crash 3. Pretty-printer never
1010+ crashes *)
12111312open Alcobar
1413
+2-2
fuzz/fuzz_oem.mli
···11(** Fuzz tests for OEM parsing and interpolation.
2233- Tests crash safety on arbitrary KVN input and interpolation
44- with degenerate data. *)
33+ Tests crash safety on arbitrary KVN input and interpolation with degenerate
44+ data. *)
5566val suite : string * Alcobar.test_case list
77(** [suite] is the OEM fuzz test suite. *)
+97-106
lib/oem.ml
···1010(* ------------------------------------------------------------------ *)
11111212type vec3 = { x : float; y : float; z : float }
1313-1414-type state_vector = {
1515- epoch : Ptime.t;
1616- pos : vec3;
1717- vel : vec3;
1818-}
1919-2020-type covariance = {
2121- epoch : Ptime.t;
2222- ref_frame : string;
2323- matrix : float array;
2424-}
1313+type state_vector = { epoch : Ptime.t; pos : vec3; vel : vec3 }
1414+type covariance = { epoch : Ptime.t; ref_frame : string; matrix : float array }
25152616type metadata = {
2717 object_name : string;
···4131 covariances : covariance list;
4232}
43334444-type header = {
4545- version : string;
4646- creation_date : string;
4747- originator : string;
4848-}
4949-5050-type t = {
5151- header : header;
5252- segments : segment list;
5353-}
3434+type header = { version : string; creation_date : string; originator : string }
3535+type t = { header : header; segments : segment list }
54365537type error =
5638 | Unexpected_eof
···62446345let pp_error ppf = function
6446 | Unexpected_eof -> Fmt.pf ppf "Unexpected end of file"
6565- | Bad_keyword { line; got } ->
6666- Fmt.pf ppf "Line %d: bad keyword %S" line got
6767- | Bad_epoch { line; value } ->
6868- Fmt.pf ppf "Line %d: bad epoch %S" line value
6969- | Bad_float { line; value } ->
7070- Fmt.pf ppf "Line %d: bad float %S" line value
4747+ | Bad_keyword { line; got } -> Fmt.pf ppf "Line %d: bad keyword %S" line got
4848+ | Bad_epoch { line; value } -> Fmt.pf ppf "Line %d: bad epoch %S" line value
4949+ | Bad_float { line; value } -> Fmt.pf ppf "Line %d: bad float %S" line value
7150 | Missing_keyword kw -> Fmt.pf ppf "Missing required keyword %S" kw
7251 | Bad_state_vector { line; expected; got } ->
7352 Fmt.pf ppf "Line %d: expected %d fields, got %d" line expected got
···7655(* Epoch parsing *)
7756(* ------------------------------------------------------------------ *)
78577979-(** Parse CCSDS epoch: "YYYY-MM-DDThh:mm:ss.sss" or "YYYY-MM-DD hh:mm:ss.sss". *)
5858+(** Parse CCSDS epoch: "YYYY-MM-DDThh:mm:ss.sss" or "YYYY-MM-DD hh:mm:ss.sss".
5959+*)
8060let parse_epoch s =
8161 let s = String.trim s in
8262 let rfc =
···92729373type line_content =
9474 | Keyword of string * string (** KEY = VALUE *)
9595- | Data of string (** Epoch + numeric data *)
9696- | Blank (** Empty or comment *)
7575+ | Data of string (** Epoch + numeric data *)
7676+ | Blank (** Empty or comment *)
97779878let classify_line s =
9979 let s = String.trim s in
···10686 match String.index_opt s '=' with
10787 | Some i ->
10888 let key = String.trim (String.sub s 0 i) in
109109- let value = String.trim (String.sub s (i + 1) (String.length s - i - 1)) in
8989+ let value =
9090+ String.trim (String.sub s (i + 1) (String.length s - i - 1))
9191+ in
11092 Keyword (key, value)
11193 | None -> Data s
11294113113-type parser_state = {
114114- lines : (int * string) array;
115115- mutable pos : int;
116116-}
9595+type parser_state = { lines : (int * string) array; mutable pos : int }
1179611897let peek st =
119119- if st.pos >= Array.length st.lines then None
120120- else Some st.lines.(st.pos)
9898+ if st.pos >= Array.length st.lines then None else Some st.lines.(st.pos)
12199122100let advance st = st.pos <- st.pos + 1
123101···146124 let cont = ref true in
147125 while !cont do
148126 match peek st with
149149- | Some (_, s) ->
150150- (match classify_line s with
127127+ | Some (_, s) -> (
128128+ match classify_line s with
151129 | Keyword ("CCSDS_OEM_VERS", v) ->
152130 version := v;
153131 advance st
···162140 | _ -> cont := false)
163141 | None -> cont := false
164142 done;
165165- Ok { version = !version; creation_date = !creation_date;
166166- originator = !originator }
143143+ Ok
144144+ {
145145+ version = !version;
146146+ creation_date = !creation_date;
147147+ originator = !originator;
148148+ }
167149168168-(** Parse a metadata block (META_START ... META_STOP). *)
169150type meta_acc = {
170151 mutable m_object_name : string;
171152 mutable m_object_id : string;
···177158 mutable m_interpolation : string option;
178159 mutable m_interp_degree : int option;
179160}
161161+(** Parse a metadata block (META_START ... META_STOP). *)
180162181163let set_meta_field acc key value =
182164 match key with
···185167 | "CENTER_NAME" -> acc.m_center_name <- value
186168 | "REF_FRAME" -> acc.m_ref_frame <- value
187169 | "TIME_SYSTEM" -> acc.m_time_system <- value
188188- | "START_TIME" ->
189189- (match parse_epoch value with Some t -> acc.m_start_time <- t | None -> ())
190190- | "STOP_TIME" ->
191191- (match parse_epoch value with Some t -> acc.m_stop_time <- t | None -> ())
170170+ | "START_TIME" -> (
171171+ match parse_epoch value with
172172+ | Some t -> acc.m_start_time <- t
173173+ | None -> ())
174174+ | "STOP_TIME" -> (
175175+ match parse_epoch value with Some t -> acc.m_stop_time <- t | None -> ())
192176 | "INTERPOLATION" -> acc.m_interpolation <- Some value
193177 | "INTERPOLATION_DEGREE" ->
194178 acc.m_interp_degree <-
···216200 | _ -> ());
217201 let acc =
218202 {
219219- m_object_name = ""; m_object_id = ""; m_center_name = "EARTH";
220220- m_ref_frame = "EME2000"; m_time_system = "UTC";
221221- m_start_time = Ptime.epoch; m_stop_time = Ptime.epoch;
222222- m_interpolation = None; m_interp_degree = None;
203203+ m_object_name = "";
204204+ m_object_id = "";
205205+ m_center_name = "EARTH";
206206+ m_ref_frame = "EME2000";
207207+ m_time_system = "UTC";
208208+ m_start_time = Ptime.epoch;
209209+ m_stop_time = Ptime.epoch;
210210+ m_interpolation = None;
211211+ m_interp_degree = None;
223212 }
224213 in
225214 let cont = ref true in
226215 while !cont do
227216 match peek st with
228228- | Some (_, s) ->
229229- (match classify_line s with
230230- | Keyword ("META_STOP", _) -> advance st; cont := false
217217+ | Some (_, s) -> (
218218+ match classify_line s with
219219+ | Keyword ("META_STOP", _) ->
220220+ advance st;
221221+ cont := false
231222 | Keyword ("COMMENT", _) -> advance st
232232- | Keyword (k, v) -> set_meta_field acc k v; advance st
223223+ | Keyword (k, v) ->
224224+ set_meta_field acc k v;
225225+ advance st
233226 | Blank -> advance st
234227 | Data _ -> cont := false)
235228 | None -> cont := false
236229 done;
237230 meta_acc_to_metadata acc
238231239239-(** Parse state vector data lines until next META_START or COVARIANCE_START
240240- or end of file. *)
232232+(** Parse state vector data lines until next META_START or COVARIANCE_START or
233233+ end of file. *)
241234let parse_data st =
242235 skip_blanks st;
243236 let vectors = ref [] in
244237 let cont = ref true in
245238 while !cont do
246239 match peek st with
247247- | Some (n, s) ->
240240+ | Some (n, s) -> (
248241 let trimmed = String.trim s in
249249- if trimmed = "META_START" || trimmed = "COVARIANCE_START"
250250- || trimmed = "" then
251251- cont := false
242242+ if
243243+ trimmed = "META_START" || trimmed = "COVARIANCE_START" || trimmed = ""
244244+ then cont := false
252245 else
253253- (match classify_line s with
246246+ match classify_line s with
254247 | Keyword _ -> cont := false
255248 | Blank -> advance st
256256- | Data d ->
249249+ | Data d -> (
257250 let parts =
258251 String.split_on_char ' ' d
259252 |> List.filter (fun s -> String.length (String.trim s) > 0)
260253 in
261261- (match parts with
262262- | epoch_s :: nums when List.length nums >= 6 ->
263263- (match parse_epoch epoch_s with
254254+ match parts with
255255+ | epoch_s :: nums when List.length nums >= 6 -> (
256256+ match parse_epoch epoch_s with
264257 | Some epoch ->
265258 let floats =
266259 List.map
267267- (fun s -> try float_of_string s with Failure _ -> 0.)
260260+ (fun s ->
261261+ try float_of_string s with Failure _ -> 0.)
268262 nums
269263 in
270264 let a = Array.of_list floats in
···342336(* Hermite interpolation *)
343337(* ------------------------------------------------------------------ *)
344338345345-(** Hermite interpolation between two state vectors.
346346- Given (pos0, vel0) at t0 and (pos1, vel1) at t1,
347347- interpolate position and velocity at t in [t0, t1]. *)
339339+(** Hermite interpolation between two state vectors. Given (pos0, vel0) at t0
340340+ and (pos1, vel1) at t1, interpolate position and velocity at t in [t0, t1].
341341+*)
348342let hermite_interp (sv0 : state_vector) (sv1 : state_vector) t =
349343 let t0 = Ptime.to_float_s sv0.epoch in
350344 let t1 = Ptime.to_float_s sv1.epoch in
···364358 (h00 *. p0) +. (h10 *. dt *. v0) +. (h01 *. p1) +. (h11 *. dt *. v1)
365359 in
366360 let vel_component p0 v0 p1 v1 =
367367- let dh00 = (6. *. tau2 -. 6. *. tau) /. dt in
368368- let dh10 = (3. *. tau2 -. 4. *. tau +. 1.) in
369369- let dh01 = (-6. *. tau2 +. 6. *. tau) /. dt in
370370- let dh11 = (3. *. tau2 -. 2. *. tau) in
361361+ let dh00 = ((6. *. tau2) -. (6. *. tau)) /. dt in
362362+ let dh10 = (3. *. tau2) -. (4. *. tau) +. 1. in
363363+ let dh01 = ((-6. *. tau2) +. (6. *. tau)) /. dt in
364364+ let dh11 = (3. *. tau2) -. (2. *. tau) in
371365 (dh00 *. p0) +. (dh10 *. v0) +. (dh01 *. p1) +. (dh11 *. v1)
372366 in
373367 ({
374374- epoch = t;
375375- pos =
376376- {
377377- x = interp_component sv0.pos.x sv0.vel.x sv1.pos.x sv1.vel.x;
378378- y = interp_component sv0.pos.y sv0.vel.y sv1.pos.y sv1.vel.y;
379379- z = interp_component sv0.pos.z sv0.vel.z sv1.pos.z sv1.vel.z;
380380- };
381381- vel =
382382- {
383383- x = vel_component sv0.pos.x sv0.vel.x sv1.pos.x sv1.vel.x;
384384- y = vel_component sv0.pos.y sv0.vel.y sv1.pos.y sv1.vel.y;
385385- z = vel_component sv0.pos.z sv0.vel.z sv1.pos.z sv1.vel.z;
386386- };
387387- } : state_vector)
368368+ epoch = t;
369369+ pos =
370370+ {
371371+ x = interp_component sv0.pos.x sv0.vel.x sv1.pos.x sv1.vel.x;
372372+ y = interp_component sv0.pos.y sv0.vel.y sv1.pos.y sv1.vel.y;
373373+ z = interp_component sv0.pos.z sv0.vel.z sv1.pos.z sv1.vel.z;
374374+ };
375375+ vel =
376376+ {
377377+ x = vel_component sv0.pos.x sv0.vel.x sv1.pos.x sv1.vel.x;
378378+ y = vel_component sv0.pos.y sv0.vel.y sv1.pos.y sv1.vel.y;
379379+ z = vel_component sv0.pos.z sv0.vel.z sv1.pos.z sv1.vel.z;
380380+ };
381381+ }
382382+ : state_vector)
388383389384(** Binary search for the interval containing time [t]. *)
390385let interval (data : state_vector array) t =
···404399 else hi := mid
405400 done;
406401 (* Check which interval *)
407407- if Ptime.to_float_s data.(!lo).epoch <= t_s
408408- && t_s <= Ptime.to_float_s data.(!lo + 1).epoch then
409409- Some !lo
410410- else if !lo + 1 < n - 1
411411- && Ptime.to_float_s data.(!lo + 1).epoch <= t_s then
412412- Some (!lo + 1)
413413- else Some (Float.max 0. (Float.of_int (!lo)) |> Float.to_int)
402402+ if
403403+ Ptime.to_float_s data.(!lo).epoch <= t_s
404404+ && t_s <= Ptime.to_float_s data.(!lo + 1).epoch
405405+ then Some !lo
406406+ else if !lo + 1 < n - 1 && Ptime.to_float_s data.(!lo + 1).epoch <= t_s
407407+ then Some (!lo + 1)
408408+ else Some (Float.max 0. (Float.of_int !lo) |> Float.to_int)
414409415410let interpolate seg t =
416411 match interval seg.data t with
···446441 (min_t, max_t)
447442448443let object_name oem =
449449- match oem.segments with
450450- | seg :: _ -> seg.metadata.object_name
451451- | [] -> ""
444444+ match oem.segments with seg :: _ -> seg.metadata.object_name | [] -> ""
452445453446let object_id oem =
454454- match oem.segments with
455455- | seg :: _ -> seg.metadata.object_id
456456- | [] -> ""
447447+ match oem.segments with seg :: _ -> seg.metadata.object_id | [] -> ""
457448458449(* ------------------------------------------------------------------ *)
459450(* Pretty-printing *)
···462453let pp_vec3 ppf v = Fmt.pf ppf "(%.3f, %.3f, %.3f)" v.x v.y v.z
463454464455let pp_state_vector ppf (sv : state_vector) =
465465- Fmt.pf ppf "%a pos=%a vel=%a"
466466- (Ptime.pp_rfc3339 ()) sv.epoch pp_vec3 sv.pos pp_vec3 sv.vel
456456+ Fmt.pf ppf "%a pos=%a vel=%a" (Ptime.pp_rfc3339 ()) sv.epoch pp_vec3 sv.pos
457457+ pp_vec3 sv.vel
467458468459let pp_metadata ppf m =
469469- Fmt.pf ppf "%s [%s] %s %s %a–%a" m.object_name m.object_id
470470- m.ref_frame m.time_system (Ptime.pp_rfc3339 ()) m.start_time
471471- (Ptime.pp_rfc3339 ()) m.stop_time
460460+ Fmt.pf ppf "%s [%s] %s %s %a–%a" m.object_name m.object_id m.ref_frame
461461+ m.time_system (Ptime.pp_rfc3339 ()) m.start_time (Ptime.pp_rfc3339 ())
462462+ m.stop_time
472463473464let pp ppf oem =
474465 Fmt.pf ppf "OEM v%s by %s (%d segments)@," oem.header.version
+14-30
lib/oem.mli
···11(** CCSDS 502.0-B-3 Orbit Ephemeris Message (OEM) parser and interpolator.
2233- Parses the KVN (Keyword=Value Notation) text format for orbit
44- ephemeris data. Provides Hermite interpolation between state vectors
55- for smooth position queries at arbitrary times.
33+ Parses the KVN (Keyword=Value Notation) text format for orbit ephemeris
44+ data. Provides Hermite interpolation between state vectors for smooth
55+ position queries at arbitrary times.
6677- Reference: {{:https://public.ccsds.org/Pubs/502x0b3e1.pdf}
88- CCSDS 502.0-B-3} Orbit Data Messages. *)
77+ Reference: {{:https://public.ccsds.org/Pubs/502x0b3e1.pdf} CCSDS 502.0-B-3}
88+ Orbit Data Messages. *)
991010(** {1 Types} *)
11111212type vec3 = { x : float; y : float; z : float }
1313(** Position or velocity vector (km or km/s). *)
14141515-type state_vector = {
1616- epoch : Ptime.t;
1717- pos : vec3;
1818- vel : vec3;
1919-}
1515+type state_vector = { epoch : Ptime.t; pos : vec3; vel : vec3 }
2016(** A single ephemeris data point: position and velocity at an epoch. *)
21172222-type covariance = {
2323- epoch : Ptime.t;
2424- ref_frame : string;
2525- matrix : float array;
2626-}
1818+type covariance = { epoch : Ptime.t; ref_frame : string; matrix : float array }
2719(** Optional covariance matrix (upper triangle, 6x6 = 21 elements). *)
28202921type metadata = {
···4638}
4739(** One ephemeris segment (metadata + data + optional covariance). *)
48404949-type header = {
5050- version : string;
5151- creation_date : string;
5252- originator : string;
5353-}
4141+type header = { version : string; creation_date : string; originator : string }
5442(** OEM file header. *)
55435656-type t = {
5757- header : header;
5858- segments : segment list;
5959-}
4444+type t = { header : header; segments : segment list }
6045(** A complete OEM file with header and one or more segments. *)
61466247(** {1 Parsing} *)
···8469(** {1 Interpolation} *)
85708671val interpolate : segment -> Ptime.t -> state_vector option
8787-(** [interpolate seg t] returns the interpolated state vector at time [t]
8888- within segment [seg], or [None] if [t] is outside the segment's
8989- time range. Uses Hermite interpolation for position continuity. *)
7272+(** [interpolate seg t] returns the interpolated state vector at time [t] within
7373+ segment [seg], or [None] if [t] is outside the segment's time range. Uses
7474+ Hermite interpolation for position continuity. *)
90759176val interpolate_all : t -> Ptime.t -> state_vector option
9292-(** [interpolate_all oem t] searches all segments for one containing
9393- time [t] and interpolates. Returns the first matching segment's
9494- result. *)
7777+(** [interpolate_all oem t] searches all segments for one containing time [t]
7878+ and interpolates. Returns the first matching segment's result. *)
95799680(** {1 Queries} *)
9781