@@ -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
///
@@ -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
+ tag_name : & str ,
274
+ content : & T ,
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
+ ) ;
288
+ serializer. set_indent_level ( 1 ) ;
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,14 +372,31 @@ 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
399
+ current_indent_len : usize ,
352
400
}
353
401
354
402
impl Indentation {
@@ -358,26 +406,37 @@ impl Indentation {
358
406
indent_char,
359
407
indent_size,
360
408
indents : vec ! [ indent_char; 128 ] ,
361
- indents_len : 0 ,
409
+ current_indent_len : 0 ,
410
+ }
411
+ }
412
+
413
+ /// Grow or shrink the indentation to the desired level
414
+ pub fn set_level ( & mut self , level : u8 ) {
415
+ self . current_indent_len = self . indent_size * level as usize ;
416
+ if self . current_indent_len > self . indents . len ( ) {
417
+ self . indents
418
+ . resize ( self . current_indent_len , self . indent_char ) ;
362
419
}
363
420
}
364
421
365
422
/// Increase indentation by one level
366
423
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 ) ;
424
+ self . current_indent_len += self . indent_size ;
425
+ if self . current_indent_len > self . indents . len ( ) {
426
+ self . indents
427
+ . resize ( self . current_indent_len , self . indent_char ) ;
370
428
}
371
429
}
372
430
373
431
/// Decrease indentation by one level. Do nothing, if level already zero
374
432
pub fn shrink ( & mut self ) {
375
- self . indents_len = self . indents_len . saturating_sub ( self . indent_size ) ;
433
+ self . current_indent_len = self . current_indent_len . saturating_sub ( self . indent_size ) ;
376
434
}
377
435
378
436
/// Returns indent string for current level
379
437
pub fn current ( & self ) -> & [ u8 ] {
380
- & self . indents [ ..self . indents_len ]
438
+ // todo: might be buggy if initialized > 128 without a call to grow() first
439
+ & self . indents [ ..self . current_indent_len ]
381
440
}
382
441
}
383
442
@@ -547,6 +606,71 @@ mod indentation {
547
606
) ;
548
607
}
549
608
609
+ #[ cfg( feature = "serialize" ) ]
610
+ #[ test]
611
+ fn serializable ( ) {
612
+ #[ derive( Serialize ) ]
613
+ struct Foo {
614
+ #[ serde( rename = "@attribute" ) ]
615
+ attribute : & ' static str ,
616
+
617
+ element : Bar ,
618
+ list : Vec < & ' static str > ,
619
+
620
+ #[ serde( rename = "$text" ) ]
621
+ text : & ' static str ,
622
+
623
+ val : String ,
624
+ }
625
+
626
+ #[ derive( Serialize ) ]
627
+ struct Bar {
628
+ baz : usize ,
629
+ bat : usize ,
630
+ }
631
+
632
+ let mut buffer = Vec :: new ( ) ;
633
+ let mut writer = Writer :: new_with_indent ( & mut buffer, b' ' , 4 ) ;
634
+
635
+ let content = Foo {
636
+ attribute : "attribute" ,
637
+ element : Bar { baz : 42 , bat : 43 } ,
638
+ list : vec ! [ "first element" , "second element" ] ,
639
+ text : "text" ,
640
+ val : "foo" . to_owned ( ) ,
641
+ } ;
642
+
643
+ let start = BytesStart :: new ( "paired" )
644
+ . with_attributes ( vec ! [ ( "attr1" , "value1" ) , ( "attr2" , "value2" ) ] . into_iter ( ) ) ;
645
+ let end = start. to_end ( ) ;
646
+
647
+ writer
648
+ . write_event ( Event :: Start ( start. clone ( ) ) )
649
+ . expect ( "write start tag failed" ) ;
650
+ writer
651
+ . write_serializable ( "foo_element" , & content)
652
+ . expect ( "write serializable inner contents failed" ) ;
653
+ writer
654
+ . write_event ( Event :: End ( end) )
655
+ . expect ( "write end tag failed" ) ;
656
+
657
+ assert_eq ! (
658
+ std:: str :: from_utf8( & buffer) . unwrap( ) ,
659
+ r#"<paired attr1="value1" attr2="value2">
660
+ <foo_element attribute="attribute">
661
+ <element>
662
+ <baz>42</baz>
663
+ <bat>43</bat>
664
+ </element>
665
+ <list>first element</list>
666
+ <list>second element</list>
667
+ text
668
+ <val>foo</val>
669
+ </foo_element>
670
+ </paired>"#
671
+ ) ;
672
+ }
673
+
550
674
#[ test]
551
675
fn element_writer_empty ( ) {
552
676
let mut buffer = Vec :: new ( ) ;
0 commit comments