@@ -36,77 +36,82 @@ impl FromStr for LispObject {
3636 }
3737}
3838
39- impl LispObject {
40- fn to_repl ( & self ) -> String {
39+ impl std :: fmt :: Display for LispObject {
40+ fn fmt ( & self , f : & mut std :: fmt :: Formatter < ' _ > ) -> std :: fmt :: Result {
4141 match self {
42- LispObject :: Symbol ( s) => s . clone ( ) ,
43- LispObject :: Keyword ( s) => format ! ( ":{}" , s ) ,
42+ LispObject :: Symbol ( s) => f . write_str ( s ) ,
43+ LispObject :: Keyword ( s) => write ! ( f , ":{s}" ) ,
4444 LispObject :: Str ( s) => {
45- let mut result = String :: new ( ) ;
46- result. reserve ( s. len ( ) * 2 + 2 ) ;
47- result. push ( '"' ) ;
45+ f. write_char ( '"' ) ?;
4846 for c in s. chars ( ) {
4947 if c == '\"' || c == '\\' {
50- result . push ( '\\' ) ;
51- result . push ( c) ;
48+ f . write_char ( '\\' ) ? ;
49+ f . write_char ( c) ? ;
5250 } else if ( c as u32 ) < 32 || ( c as u32 ) == 127 {
5351 // not printable
5452 // NOTE: cannot use escape for c in 128..=255, otherwise the string would become unibyte
55- write ! ( result , "\\ {:03o}" , c as u32 ) . unwrap ( ) ;
53+ write ! ( f , "\\ {:03o}" , c as u32 ) ? ;
5654 } else {
57- result . push ( c) ;
55+ f . write_char ( c) ? ;
5856 }
5957 }
60- result . push ( '"' ) ;
61- result
58+ f . write_char ( '"' ) ? ;
59+ Ok ( ( ) )
6260 } ,
6361 LispObject :: UnibyteStr ( vec) => {
64- let mut result = String :: new ( ) ;
65- result. reserve ( vec. len ( ) * 4 + 2 ) ;
66- result. push ( '"' ) ;
62+ f. write_char ( '"' ) ?;
6763 let mut last_oct_escape_not_full = false ;
6864 for c in vec {
6965 let mut oct_escape_not_full = false ;
7066 match * c {
71- 7 => result += "\\ a" ,
72- 8 => result += "\\ b" ,
73- 9 => result += "\\ t" ,
74- 10 => result += "\\ n" ,
75- 11 => result += "\\ v" ,
76- 12 => result += "\\ f" ,
77- 13 => result += "\\ r" ,
78- 127 => result += "\\ d" ,
79- 27 => result += "\\ e" ,
67+ 7 => f . write_str ( "\\ a" ) ? ,
68+ 8 => f . write_str ( "\\ b" ) ? ,
69+ 9 => f . write_str ( "\\ t" ) ? ,
70+ 10 => f . write_str ( "\\ n" ) ? ,
71+ 11 => f . write_str ( "\\ v" ) ? ,
72+ 12 => f . write_str ( "\\ f" ) ? ,
73+ 13 => f . write_str ( "\\ r" ) ? ,
74+ 127 => f . write_str ( "\\ d" ) ? ,
75+ 27 => f . write_str ( "\\ e" ) ? ,
8076 // NOTE: do not use 0..=7 in this branch, because it takes one more byte than the next branch
8177 8 ..=26 => { // \^@ \^A \^B ... \^Z
82- write ! ( & mut result , "\\ ^{}" , ( * c as u32 + 64 ) as u8 as char ) . unwrap ( ) ;
78+ write ! ( f , "\\ ^{}" , ( * c as u32 + 64 ) as u8 as char ) ? ;
8379 } ,
8480 0 ..=7 | 27 ..=31 | 128 ..=255 | 34 | 92 => { // oct, for unprintable and '"' and '\\'
85- let last_len = result. len ( ) ;
86- write ! ( result, "\\ {:o}" , * c as u32 ) . unwrap ( ) ;
87- if result. len ( ) - last_len < 4 {
81+ let oct_s = format ! ( "\\ {:o}" , * c as u32 ) ;
82+ if oct_s. len ( ) < 4 {
8883 oct_escape_not_full = true ;
8984 }
85+ f. write_str ( & oct_s) ?;
9086 } ,
9187 _ => { // printable
9288 // https://www.gnu.org/software/emacs/manual/html_node/elisp/Non_002dASCII-in-St
9389 if last_oct_escape_not_full && ( '0' ..='7' ) . contains ( & ( * c as char ) ) {
94- result += "\\ " ;
90+ f . write_str ( "\\ " ) ? ;
9591 }
96- result . push ( * c as char ) ;
92+ f . write_char ( * c as char ) ? ;
9793 } ,
9894 }
9995 last_oct_escape_not_full = oct_escape_not_full;
10096 }
101- result. push ( '"' ) ;
102- result
97+ f. write_char ( '"' )
10398 } ,
104- LispObject :: Int ( i) => i. to_string ( ) ,
105- LispObject :: Float ( s) => s. clone ( ) ,
106- LispObject :: Nil => "nil" . into ( ) ,
107- LispObject :: T => "t" . into ( ) ,
108- LispObject :: Vector ( v) =>
109- format ! ( "[{}]" , v. iter( ) . map( |x| x. to_repl( ) ) . collect:: <Vec <_>>( ) . join( " " ) )
99+ LispObject :: Int ( i) => write ! ( f, "{i}" ) ,
100+ LispObject :: Float ( s) => write ! ( f, "{s}" ) ,
101+ LispObject :: Nil => f. write_str ( "nil" ) ,
102+ LispObject :: T => f. write_str ( "t" ) ,
103+ LispObject :: Vector ( v) => {
104+ f. write_char ( '[' ) ?;
105+ let mut iter = v. iter ( ) ;
106+ if let Some ( first) = iter. next ( ) {
107+ write ! ( f, "{first}" ) ?;
108+ for x in iter {
109+ write ! ( f, " {x}" ) ?;
110+ }
111+ }
112+ f. write_char ( ']' ) ?;
113+ Ok ( ( ) )
114+ }
110115 }
111116 }
112117}
@@ -424,8 +429,8 @@ impl BytecodeCompiler {
424429 fn into_repl ( self ) -> Result < String > {
425430 let ( code, constants, max_stack_size) = self . into_bytecode ( ) ?;
426431 Ok ( format ! ( "#[0 {} {} {}]" ,
427- LispObject :: UnibyteStr ( code) . to_repl ( ) ,
428- LispObject :: Vector ( constants) . to_repl ( ) ,
432+ LispObject :: UnibyteStr ( code) ,
433+ LispObject :: Vector ( constants) ,
429434 max_stack_size) )
430435 }
431436}
@@ -443,9 +448,9 @@ pub fn generate_bytecode_repl(value: &json::Value, options: BytecodeOptions) ->
443448
444449#[ test]
445450fn test_string_repl ( ) {
446- assert_eq ! ( LispObject :: UnibyteStr ( "\x00 " . into( ) ) . to_repl ( ) , r#""\0""# ) ;
447- assert_eq ! ( LispObject :: UnibyteStr ( "\x1a " . into( ) ) . to_repl ( ) , r#""\^Z""# ) ;
448- assert_eq ! ( LispObject :: UnibyteStr ( "\x20 " . into( ) ) . to_repl ( ) , r#"" ""# ) ;
449- assert_eq ! ( LispObject :: UnibyteStr ( "\x7f " . into( ) ) . to_repl ( ) , r#""\d""# ) ;
450- assert_eq ! ( LispObject :: UnibyteStr ( vec![ 0xff ] ) . to_repl ( ) , r#""\377""# ) ;
451+ assert_eq ! ( format! ( "{}" , LispObject :: UnibyteStr ( "\x00 " . into( ) ) ) , r#""\0""# ) ;
452+ assert_eq ! ( format! ( "{}" , LispObject :: UnibyteStr ( "\x1a " . into( ) ) ) , r#""\^Z""# ) ;
453+ assert_eq ! ( format! ( "{}" , LispObject :: UnibyteStr ( "\x20 " . into( ) ) ) , r#"" ""# ) ;
454+ assert_eq ! ( format! ( "{}" , LispObject :: UnibyteStr ( "\x7f " . into( ) ) ) , r#""\d""# ) ;
455+ assert_eq ! ( format! ( "{}" , LispObject :: UnibyteStr ( vec![ 0xff ] ) ) , r#""\377""# ) ;
451456}
0 commit comments