char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
7325e8c
main
1use std:: convert:: Infallible ; 2 3use avril_core:: serde_v8:: U16String ; 4use avril_core::{ Extension , Op , PublicModule , v8}; 5use serde_fjson:: syntax:: ValueKind ; 6use serde_fjson::{ Document , PathSegment }; 7 8enum ErrorClass { 9Syntax , 10Type , 11Range , 12} 13 14fn fail < T >( scope : & mut v8:: PinScope < ' _ , ' _ >, class : ErrorClass , message : & str ) ->Option < T > { 15let message = v8:: String :: new ( scope, message) ?; 16let exception =match class{ 17ErrorClass :: Syntax => v8:: Exception :: syntax_error ( scope, message), 18ErrorClass :: Type => v8:: Exception :: type_error ( scope, message), 19ErrorClass :: Range => v8:: Exception :: range_error ( scope, message), 20}; 21 scope. throw_exception ( exception); 22None 23} 24 25struct Overrides < ' s > { 26document : Document , 27path : Vec < String >, 28ancestors : Vec < v8:: Local < ' s , v8:: Object >>, 29} 30 31impl < ' s > Overrides < ' s > { 32fn merge ( 33& mut self , 34scope : & mut v8:: PinScope < ' s , ' _ >, 35value : v8:: Local < ' s , v8:: Value >, 36) ->Option <()> { 37if !value. is_object () || value. is_array () || value. is_function () { 38return fail ( scope, ErrorClass :: Type , "fJSON overrides must be objects" ); 39} 40if self 41. ancestors 42. iter () 43. any ( |object| object. strict_equals ( value)) 44{ 45return fail ( scope, ErrorClass :: Type , "Cannot apply cyclic overrides" ); 46} 47if self . path . len () >128 { 48return fail ( 49 scope, 50ErrorClass :: Range , 51"fJSON nesting exceeds 128 levels below the root" , 52); 53} 54let object = v8:: Local ::< v8:: Object >:: try_from ( value). ok () ?; 55self . ancestors . push ( object); 56let keys = object. get_own_property_names ( 57 scope, 58 v8:: GetPropertyNamesArgs { 59key_conversion : v8:: KeyConversionMode :: ConvertToString , 60 ..Default :: default () 61}, 62) ?; 63for indexin 0 ..keys. length () { 64let key = keys. get_index ( scope, index) ?; 65let value = object. get ( scope, key) ?; 66let units = avril_core:: serde_v8:: from_v8 ::< U16String >( scope, key). ok () ?; 67let key =match String :: from_utf16 ( & units) { 68Ok ( key) => key, 69Err ( _) =>return fail ( scope, ErrorClass :: Type , "Unpaired Unicode surrogate" ), 70}; 71self . path . push ( key); 72let path: Vec < _ > =self . path . iter (). map ( |key|PathSegment :: Key ( key)). collect (); 73let merge = value. is_object () && !value. is_array () && !value. is_function (); 74let result =if value. is_undefined () { 75self . document . remove ( & path). map ( |_|()) 76} else if merge{ 77let existing =self 78. path 79. iter () 80. try_fold ( self . document . root (), |value, key|{ 81let ValueKind :: Object ( members) =& value. kind else { 82return None ; 83}; 84 members 85. iter () 86. find ( |member|& member. key == key) 87. map ( |member|& member. value ) 88}); 89if existing. is_some_and ( |value|matches! ( value. kind , ValueKind :: Object ( _))) { 90Ok (()) 91} else { 92self . document . set ( & path, & serde_json:: json!({})) 93} 94} else { 95let json = v8:: json:: stringify ( scope, value) ?. to_rust_string_lossy ( scope); 96// V8's JSON API returns the text "undefined" for unsupported roots. 97if json =="undefined" { 98Ok (()) 99} else { 100 serde_fjson:: parse ( & json). and_then ( |value|self . document . set ( & path, & value)) 101} 102}; 103if let Err ( error) = result{ 104let class =if error. kind == serde_fjson:: ErrorKind :: Nesting { 105ErrorClass :: Range 106} else { 107ErrorClass :: Type 108}; 109return fail ( scope, class, & error. message ); 110} 111if merge{ 112self . merge ( scope, value) ?; 113} 114self . path . pop (); 115} 116self . ancestors . pop (); 117Some (()) 118} 119} 120 121fn decode_source ( source : & U16String ) ->Result < String , String > { 122let mut text =String :: new (); 123for characterin char:: decode_utf16 ( source. iter (). copied ()) { 124match character{ 125Ok ( character) => text. push ( character), 126Err ( _) =>{ 127let error = serde_fjson:: Error { 128kind : serde_fjson:: ErrorKind :: Unicode , 129message : "Unpaired Unicode surrogate" . into (), 130span : text. len () ..text. len (), 131previous : None , 132}; 133return Err ( error. render ( "<fjson>" , & text)); 134} 135} 136} 137Ok ( text) 138} 139 140pub fn init () ->Extension { 141Extension { 142name : "ext:fjson" , 143dependencies : & [], 144ops : vec! [ 145Op :: new ( "op_fjson_parse" , |source : U16String |{ 146let text =match decode_source ( & source) { 147Ok ( text) => text, 148Err ( error) =>return Ok ::< _ , Infallible >(( None , Some ( error))), 149}; 150let result =match serde_fjson:: parse ( & text) { 151Ok ( value) =>( Some ( serde_json:: to_string ( & value). unwrap ()), None ), 152Err ( error) =>( None , Some ( error. render ( "<fjson>" , & text))), 153}; 154Ok ::< _ , Infallible >( result) 155}), 156Op :: new ( "op_fjson_stringify" , |source : String |{ 157let result =match serde_fjson:: parse ( & source) 158. and_then ( |value| serde_fjson:: stringify ( & value)) 159{ 160Ok ( text) =>( Some ( text), None , false ), 161Err ( error) =>( 162None , 163Some ( format! ( "Cannot stringify fJSON: {}" , error. message )), 164 error. kind == serde_fjson:: ErrorKind :: Nesting , 165), 166}; 167Ok ::< _ , Infallible >( result) 168}), 169Op :: raw ( "op_fjson_apply" , |scope, args|{ 170let source = args. get ( 0 ); 171let source = avril_core:: serde_v8:: from_v8 ::< U16String >( scope, source). ok () ?; 172let text =match decode_source ( & source) { 173Ok ( text) => text, 174Err ( error) =>return fail ( scope, ErrorClass :: Syntax , & error), 175}; 176let document =match Document :: parse_object ( text). and_then ( |document|{ 177 document. to_value () ?; 178Ok ( document) 179}) { 180Ok ( document) => document, 181Err ( error) =>{ 182// Only failed parses need a second copy for source diagnostics. 183let text =decode_source ( & source). expect ( "source was already validated" ); 184return fail ( scope, ErrorClass :: Syntax , & error. render ( "<fjson>" , & text)); 185} 186}; 187let values = v8:: Local ::< v8:: Array >:: try_from ( args. get ( 1 )). ok () ?; 188let mut overrides =Overrides { 189 document, 190path : Vec :: new (), 191ancestors : Vec :: new (), 192}; 193for indexin 0 ..values. length () { 194let value = values. get_index ( scope, index) ?; 195 overrides. merge ( scope, value) ?; 196} 197 v8:: String :: new ( scope, & overrides. document . into_source ()). map ( Into :: into) 198}), 199], 200modules : const { & [ PUBLIC_MODULES [ 0 ]. module ] }, 201entry_point : Some ( "ext:fjson/main.js" ), 202} 203} 204 205pub const PUBLIC_MODULES : & [ PublicModule ] =& [ avril_core:: public_module!( 206"avril:fjson" , 207"ext:fjson" , 208"main" 209)];