(.module: {#.doc "Codecs for values in the JSON format."} [library [lux #* ["." debug] [abstract [monad (#+ Monad do)] [equivalence (#+ Equivalence)] ["." codec]] [control ["." try] ["<>" parser ["<.>" type] ["" json]]] [data ["." bit] maybe ["." sum] ["." product] ["." text ("#\." equivalence) ["%" format (#+ format)]] [collection ["." list ("#\." fold monad)] ["." row (#+ Row row) ("#\." monad)] ["d" dictionary]]] [macro [syntax (#+ syntax:)] ["." code] ["." poly (#+ poly:)]] [math [number ["." i64] ["n" nat ("#\." decimal)] ["." int] ["." frac ("#\." decimal)]]] [time ## ["." instant] ## ["." duration] ["." date] ["." day] ["." month]] ["." type ["." unit]]]] [\\library ["." / (#+ JSON)]]) (def: tag (-> Nat Frac) (|>> .int int.frac)) (def: (rec_encode non_rec) (All [a] (-> (-> (-> a JSON) (-> a JSON)) (-> a JSON))) (function (_ input) (non_rec (rec_encode non_rec) input))) (def: low_mask Nat (|> 1 (i64.left_shift 32) dec)) (def: high_mask Nat (|> low_mask (i64.left_shift 32))) (implementation: nat_codec (codec.Codec JSON Nat) (def: (encode input) (let [high (|> input (i64.and high_mask) (i64.right_shift 32)) low (i64.and low_mask input)] (#/.Array (row (|> high .int int.frac #/.Number) (|> low .int int.frac #/.Number))))) (def: decode (.run (.array (do <>.monad [high .number low .number] (wrap (n.+ (|> high frac.int .nat (i64.left_shift 32)) (|> low frac.int .nat)))))))) (implementation: int_codec (codec.Codec JSON Int) (def: encode (|>> .nat (\ nat_codec encode))) (def: decode (|>> (\ nat_codec decode) (\ try.functor map .int)))) (def: (nullable writer) {#.doc "Builds a JSON generator for potentially inexistent values."} (All [a] (-> (-> a JSON) (-> (Maybe a) JSON))) (function (_ elem) (case elem #.None #/.Null (#.Some value) (writer value)))) (implementation: qty_codec (All [unit] (codec.Codec JSON (unit.Qty unit))) (def: encode (|>> ((debug.private unit.out)) (\ ..int_codec encode))) (def: decode (|>> (\ ..int_codec decode) (\ try.functor map (debug.private unit.in))))) (poly: encode (with_expansions [ (template [ ] [(do ! [#let [g!_ (code.local_identifier "_______")] _ ] (wrap (` (: (~ (@JSON\encode inputT)) ))))] [(.exactly Any) (function ((~ g!_) (~ (code.identifier ["" "0"]))) #/.Null)] [(.sub Bit) (|>> #/.Boolean)] [(.sub Nat) (\ (~! ..nat_codec) (~' encode))] [(.sub Int) (\ (~! ..int_codec) (~' encode))] [(.sub Frac) (|>> #/.Number)] [(.sub Text) (|>> #/.String)])