char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
f4a0f5b
main
1use serde_json:: Value ; 2 3use crate ::{ Error , syntax}; 4 5const WIDTH : usize =80 ; 6 7pub ( crate ) fn key ( text : & str ) ->String { 8let mut chars = text. chars (); 9if chars 10. next () 11. is_some_and ( |ch| ch. is_ascii_alphabetic () || ch =='_' || ch =='$' ) 12 && chars. all ( |ch| ch. is_ascii_alphanumeric () || ch =='_' || ch =='$' ) 13{ 14 text. to_owned () 15} else { 16 serde_json:: to_string ( text). unwrap () 17} 18} 19 20pub ( crate ) fn ( 21value : & Value , 22implicit : bool , 23options : & crate :: Options , 24) ->Result < String , Error > { 25check_depth ( value, 0 , options. max_depth ) ?; 26let mut output =String :: new (); 27write ( value, implicit, 0 , & mut output); 28Ok ( output) 29} 30 31fn check_depth ( value : & Value , depth : usize , limit : usize ) ->Result <(), Error > { 32if matches! ( value, Value :: Array ( _) |Value :: Object ( _)) && depth > limit{ 33return Err ( syntax:: nesting_limit ( 0 ..0 , limit)); 34} 35match value{ 36Value :: Array ( items) =>{ 37for valuein items{ 38check_depth ( value, depth +1 , limit) ?; 39} 40} 41Value :: Object ( map) =>{ 42for valuein map. values () { 43check_depth ( value, depth +1 , limit) ?; 44} 45} 46 _ =>{} 47} 48Ok (()) 49} 50 51fn flat ( value : & Value ) ->Option < String > { 52match value{ 53Value :: Object ( map) if map. is_empty () =>Some ( "{}" . into ()), 54Value :: Array ( items) if items. is_empty () =>Some ( "[]" . into ()), 55Value :: Object ( _) |Value :: Array ( _) =>None , 56 _ =>Some ( serde_json:: to_string ( value). unwrap ()), 57} 58} 59 60fn write ( value : & Value , implicit : bool , indent : usize , output : & mut String ) { 61if let Some ( text) =flat ( value) { 62 output. push_str ( & text); 63return ; 64} 65match value{ 66Value :: Object ( map) =>{ 67let child =if implicit{ indent} else { indent +2 }; 68if !implicit{ 69 output. push_str ( "{\n" ); 70} 71for ( index, ( name, value)) in map. iter (). enumerate () { 72if index >0 { 73 output. push ( '\n' ); 74} 75 output. push_str ( & " " . repeat ( child)); 76 output. push_str ( & key ( name)); 77 output. push_str ( ": " ); 78write ( value, false , child, output); 79} 80if !implicit{ 81 output. push ( '\n' ); 82 output. push_str ( & " " . repeat ( indent)); 83 output. push ( '}' ); 84} 85} 86Value :: Array ( items) =>{ 87let inline = items. iter (). map ( flat). collect ::< Option < Vec < _ >>>(); 88if let Some ( inline) = inline{ 89let text =format! ( "[{}]" , inline. join ( ", " )); 90let column = output. rsplit ( '\n' ). next (). unwrap (). chars (). count (); 91if column + text. chars (). count () <=WIDTH { 92 output. push_str ( & text); 93return ; 94} 95} 96 output. push_str ( "[\n" ); 97for ( index, value) in items. iter (). enumerate () { 98if index >0 { 99 output. push ( '\n' ); 100} 101 output. push_str ( & " " . repeat ( indent +2 )); 102write ( value, false , indent +2 , output); 103} 104 output. push ( '\n' ); 105 output. push_str ( & " " . repeat ( indent)); 106 output. push ( ']' ); 107} 108 _ =>unreachable! (), 109} 110}