open Sexplib0.Sexp_conv type entry = Slug.t * Citation.t list [@@deriving sexp] type t = entry list [@@deriving sexp] let empty = [] let of_entries es = let sorted = List.stable_sort (fun (a, _) (b, _) -> Slug.compare a b) es in let rec dup = function | (a, _) :: ((b, _) :: _ as rest) -> if Slug.equal a b then Some a else dup rest | _ -> None in match dup sorted with | Some s -> Error (Printf.sprintf "lectionary: duplicate slug %S" (Slug.to_string s)) | None -> Ok sorted let find t s = List.assoc_opt s t let mem t s = List.mem_assoc s t let entries t = t let load path = match Sexplib.Sexp.load_sexp path with | exception Sexplib.Sexp.Parse_error e -> Error (Printf.sprintf "lectionary: %s: %s" path e.err_msg) | exception Sys_error e -> Error (Printf.sprintf "lectionary: %s" e) | sexp -> ( match t_of_sexp sexp with | exception Sexplib0.Sexp_conv_error.Of_sexp_error (exn, _) -> Error (Printf.sprintf "lectionary: %s: %s" path (Printexc.to_string exn)) | parsed -> of_entries parsed)