@@ -10,6 +10,10 @@ use crate::events::{attributes::Attribute, BytesCData, BytesStart, BytesText, Ev
10
10
mod async_tokio;
11
11
12
12
/// XML writer. Writes XML [`Event`]s to a [`std::io::Write`] or [`tokio::io::AsyncWrite`] implementor.
13
+ #[ cfg( feature = "serialize" ) ]
14
+ use { crate :: de:: DeError , serde:: Serialize } ;
15
+
16
+ /// XML writer. Writes XML [`Event`]s to a [`std::io::Write`] implementor.
13
17
///
14
18
/// # Examples
15
19
///
@@ -75,7 +79,7 @@ impl<W> Writer<W> {
75
79
pub fn new_with_indent ( inner : W , indent_char : u8 , indent_size : usize ) -> Writer < W > {
76
80
Writer {
77
81
writer : inner,
78
- indent : Some ( Indentation :: new ( indent_char, indent_size) ) ,
82
+ indent : Some ( Indentation :: new ( indent_char, indent_size, 0 ) ) ,
79
83
}
80
84
}
81
85
@@ -261,6 +265,33 @@ impl<W: Write> Writer<W> {
261
265
start_tag : BytesStart :: new ( name. as_ref ( ) ) ,
262
266
}
263
267
}
268
+
269
+ /// Write an arbitrary serializable object
270
+ #[ cfg( feature = "serialize" ) ]
271
+ pub fn write_serializable < T : Serialize > (
272
+ & mut self ,
273
+ content : & T ,
274
+ tag_name : & str ,
275
+ ) -> std:: result:: Result < ( ) , DeError > {
276
+ use crate :: se:: Serializer ;
277
+
278
+ self . write_indent ( ) ?;
279
+ let indent = self . indent . clone ( ) ;
280
+ let mut fmt = ToFmtWrite ( self . get_mut ( ) ) ;
281
+ let mut serializer = Serializer :: with_root ( & mut fmt, Some ( tag_name) ) ?;
282
+
283
+ if let Some ( indent) = indent {
284
+ serializer. indent (
285
+ indent. indent_char as char ,
286
+ indent. indent_size ,
287
+ indent. current_indent_len ,
288
+ ) ;
289
+ }
290
+
291
+ content. serialize ( serializer) ?;
292
+
293
+ Ok ( ( ) )
294
+ }
264
295
}
265
296
266
297
/// A struct to write an element. Contains methods to add attributes and inner
@@ -341,43 +372,62 @@ impl<'a, W: Write> ElementWriter<'a, W> {
341
372
Ok ( self . writer )
342
373
}
343
374
}
375
+ #[ cfg( feature = "serialize" ) ]
376
+ struct ToFmtWrite < T > ( pub T ) ;
377
+
378
+ #[ cfg( feature = "serialize" ) ]
379
+ impl < T > std:: fmt:: Write for ToFmtWrite < T >
380
+ where
381
+ T : std:: io:: Write ,
382
+ {
383
+ fn write_str ( & mut self , s : & str ) -> std:: fmt:: Result {
384
+ self . 0 . write_all ( s. as_bytes ( ) ) . map_err ( |_| std:: fmt:: Error )
385
+ }
386
+ }
344
387
345
388
#[ derive( Clone ) ]
346
389
pub ( crate ) struct Indentation {
390
+ /// todo: does this even belong here? It has no impact on indentation logic.
347
391
should_line_break : bool ,
392
+ /// The character code to be used for indentations (e.g. ` ` or `\t`)
348
393
indent_char : u8 ,
394
+ /// How many instances of the indent character ought to be used for each level of indentation
349
395
indent_size : usize ,
396
+ /// Used as a cache for the bytes used for indentation
350
397
indents : Vec < u8 > ,
351
- indents_len : usize ,
398
+ /// The current amount of indentation - must be less than indents.len()
399
+ current_indent_len : usize ,
352
400
}
353
401
354
402
impl Indentation {
355
- pub fn new ( indent_char : u8 , indent_size : usize ) -> Self {
403
+ pub fn new ( indent_char : u8 , indent_size : usize , indents_len : usize ) -> Self {
356
404
Self {
357
405
should_line_break : false ,
358
406
indent_char,
359
407
indent_size,
360
408
indents : vec ! [ indent_char; 128 ] ,
361
- indents_len : 0 ,
409
+ current_indent_len : indents_len ,
362
410
}
363
411
}
364
412
365
413
/// Increase indentation by one level
366
414
pub fn grow ( & mut self ) {
367
- self . indents_len += self . indent_size ;
368
- if self . indents_len > self . indents . len ( ) {
369
- self . indents . resize ( self . indents_len , self . indent_char ) ;
415
+ self . current_indent_len += self . indent_size ;
416
+ if self . current_indent_len > self . indents . len ( ) {
417
+ self . indents
418
+ . resize ( self . current_indent_len , self . indent_char ) ;
370
419
}
371
420
}
372
421
373
422
/// Decrease indentation by one level. Do nothing, if level already zero
374
423
pub fn shrink ( & mut self ) {
375
- self . indents_len = self . indents_len . saturating_sub ( self . indent_size ) ;
424
+ self . current_indent_len = self . current_indent_len . saturating_sub ( self . indent_size ) ;
376
425
}
377
426
378
427
/// Returns indent string for current level
379
428
pub fn current ( & self ) -> & [ u8 ] {
380
- & self . indents [ ..self . indents_len ]
429
+ // todo: might be buggy if initialized > 128 without a call to grow() first
430
+ & self . indents [ ..self . current_indent_len ]
381
431
}
382
432
}
383
433
@@ -547,6 +597,71 @@ mod indentation {
547
597
) ;
548
598
}
549
599
600
+ #[ cfg( feature = "serialize" ) ]
601
+ #[ test]
602
+ fn serializable ( ) {
603
+ #[ derive( Serialize ) ]
604
+ struct Foo {
605
+ #[ serde( rename = "@attribute" ) ]
606
+ attribute : & ' static str ,
607
+
608
+ element : Bar ,
609
+ list : Vec < & ' static str > ,
610
+
611
+ #[ serde( rename = "$text" ) ]
612
+ text : & ' static str ,
613
+
614
+ val : String ,
615
+ }
616
+
617
+ #[ derive( Serialize ) ]
618
+ struct Bar {
619
+ baz : usize ,
620
+ bat : usize ,
621
+ }
622
+
623
+ let mut buffer = Vec :: new ( ) ;
624
+ let mut writer = Writer :: new_with_indent ( & mut buffer, b' ' , 4 ) ;
625
+
626
+ let content = Foo {
627
+ attribute : "attribute" ,
628
+ element : Bar { baz : 42 , bat : 43 } ,
629
+ list : vec ! [ "first element" , "second element" ] ,
630
+ text : "text" ,
631
+ val : "foo" . to_owned ( ) ,
632
+ } ;
633
+
634
+ let start = BytesStart :: new ( "paired" )
635
+ . with_attributes ( vec ! [ ( "attr1" , "value1" ) , ( "attr2" , "value2" ) ] . into_iter ( ) ) ;
636
+ let end = start. to_end ( ) ;
637
+
638
+ writer
639
+ . write_event ( Event :: Start ( start. clone ( ) ) )
640
+ . expect ( "write start tag failed" ) ;
641
+ writer
642
+ . write_serializable ( & content, "foo_element" )
643
+ . expect ( "write serializable inner contents failed" ) ;
644
+ writer
645
+ . write_event ( Event :: End ( end) )
646
+ . expect ( "write end tag failed" ) ;
647
+
648
+ assert_eq ! (
649
+ std:: str :: from_utf8( & buffer) . unwrap( ) ,
650
+ r#"<paired attr1="value1" attr2="value2">
651
+ <foo_element attribute="attribute">
652
+ <element>
653
+ <baz>42</baz>
654
+ <bat>43</bat>
655
+ </element>
656
+ <list>first element</list>
657
+ <list>second element</list>
658
+ text
659
+ <val>foo</val>
660
+ </foo_element>
661
+ </paired>"#
662
+ ) ;
663
+ }
664
+
550
665
#[ test]
551
666
fn element_writer_empty ( ) {
552
667
let mut buffer = Vec :: new ( ) ;
0 commit comments