sval_buffer/
fragments.rs

1use crate::{
2    std::fmt::{self, Write as _},
3    Error,
4};
5
6#[cfg(feature = "alloc")]
7use crate::std::{
8    borrow::{Cow, ToOwned},
9    mem,
10};
11
12/**
13Buffer text fragments into a single contiguous string.
14
15In no-std environments, this buffer only supports a single
16borrowed text fragment. Other methods will fail.
17*/
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct TextBuf<'sval> {
20    buf: FragmentBuf<'sval, str>,
21}
22
23impl<'sval> TextBuf<'sval> {
24    /**
25    Create a new empty text buffer.
26    */
27    #[inline(always)]
28    pub fn new() -> Self {
29        TextBuf {
30            buf: FragmentBuf::new(""),
31        }
32    }
33
34    /**
35    Buffer a text value into a contiguous string.
36    */
37    pub fn collect(value: &'sval (impl sval::Value + ?Sized)) -> Result<Self, Error> {
38        let mut collector = TextCollector {
39            buf: TextBuf::new(),
40            err: None,
41        };
42
43        value
44            .stream(&mut collector)
45            .map_err(|_| collector.err.unwrap())?;
46
47        Ok(collector.buf)
48    }
49
50    /**
51    Buffer a displayable value into a contiguous string.
52    */
53    pub fn collect_display(value: impl fmt::Display) -> Result<Self, Error> {
54        let mut buf = TextBuf::new();
55        buf.push_display(value)?;
56
57        Ok(buf)
58    }
59
60    /**
61    Clear the text buffer so it can be re-used.
62    */
63    #[inline(always)]
64    pub fn clear(&mut self) {
65        *self = Default::default();
66    }
67
68    /**
69    Push a borrowed text fragment onto the buffer.
70    */
71    #[inline(always)]
72    pub fn push_fragment(&mut self, fragment: &'sval str) -> Result<(), Error> {
73        self.buf.push(fragment)
74    }
75
76    /**
77    Push a computed text fragment onto the buffer.
78
79    If the `std` feature of this library is enabled, this method will
80    buffer the fragment. In no-std environments this method will fail.
81    */
82    #[inline(always)]
83    pub fn push_fragment_computed(&mut self, fragment: &str) -> Result<(), Error> {
84        self.buf.push_computed(fragment)
85    }
86
87    /**
88    Push a displayable value onto the buffer.
89
90    If the `std` feature of htis library is enabled, this method will
91    buffer the fragment. In no-std environments this method will fail.
92    */
93    pub fn push_display(&mut self, value: impl fmt::Display) -> Result<(), Error> {
94        struct Writer<'a, 'sval> {
95            buf: &'a mut TextBuf<'sval>,
96            err: Option<Error>,
97        }
98
99        impl<'a, 'sval> fmt::Write for Writer<'a, 'sval> {
100            fn write_str(&mut self, s: &str) -> fmt::Result {
101                match self.buf.push_fragment_computed(s) {
102                    Ok(()) => Ok(()),
103                    Err(e) => {
104                        self.err = Some(e);
105                        Err(fmt::Error)
106                    }
107                }
108            }
109        }
110
111        let mut writer = Writer {
112            buf: self,
113            err: None,
114        };
115
116        write!(&mut writer, "{}", value).map_err(|_| {
117            writer
118                .err
119                .unwrap_or_else(|| Error::invalid_value("formatting failed"))
120        })
121    }
122
123    /**
124    Try get the contents of the buffer as a string borrowed for the `'sval` lifetime.
125    */
126    #[inline(always)]
127    pub fn as_borrowed_str(&self) -> Option<&'sval str> {
128        self.buf.as_borrowed_inner()
129    }
130
131    /**
132    Get the contents of the buffer as a string.
133    */
134    #[inline(always)]
135    pub fn as_str(&self) -> &str {
136        self.buf.as_inner()
137    }
138
139    #[cfg(feature = "alloc")]
140    pub(crate) fn into_owned_in_place(&mut self) -> &mut TextBuf<'static> {
141        let TextBuf { ref mut buf } = self;
142
143        crate::assert_static(buf.into_owned_in_place());
144
145        // SAFETY: `self` no longer contains any data borrowed for `'sval`
146        unsafe { mem::transmute::<&mut TextBuf<'sval>, &mut TextBuf<'static>>(self) }
147    }
148}
149
150struct TextCollector<'a> {
151    buf: TextBuf<'a>,
152    err: Option<Error>,
153}
154
155impl<'a> TextCollector<'a> {
156    fn try_catch(&mut self, f: impl FnOnce(&mut TextBuf<'a>) -> Result<(), Error>) -> sval::Result {
157        match f(&mut self.buf) {
158            Ok(()) => Ok(()),
159            Err(e) => self.fail(e),
160        }
161    }
162
163    fn fail(&mut self, err: Error) -> sval::Result {
164        self.err = Some(err);
165        sval::error()
166    }
167}
168
169impl<'a> sval::Stream<'a> for TextCollector<'a> {
170    fn text_begin(&mut self, _: Option<usize>) -> sval::Result {
171        Ok(())
172    }
173
174    fn text_fragment(&mut self, fragment: &'a str) -> sval::Result {
175        self.try_catch(|buf| buf.push_fragment(fragment))
176    }
177
178    fn text_fragment_computed(&mut self, fragment: &str) -> sval::Result {
179        self.try_catch(|buf| buf.push_fragment_computed(fragment))
180    }
181
182    fn text_end(&mut self) -> sval::Result {
183        Ok(())
184    }
185
186    fn null(&mut self) -> sval::Result {
187        self.fail(Error::unsupported("text", "null"))
188    }
189
190    fn bool(&mut self, _: bool) -> sval::Result {
191        self.fail(Error::unsupported("text", "boolean"))
192    }
193
194    fn i64(&mut self, _: i64) -> sval::Result {
195        self.fail(Error::unsupported("text", "integer"))
196    }
197
198    fn f64(&mut self, _: f64) -> sval::Result {
199        self.fail(Error::unsupported("text", "floating point"))
200    }
201
202    fn seq_begin(&mut self, _: Option<usize>) -> sval::Result {
203        self.fail(Error::unsupported("text", "sequence"))
204    }
205
206    fn seq_value_begin(&mut self) -> sval::Result {
207        self.fail(Error::unsupported("text", "sequence"))
208    }
209
210    fn seq_value_end(&mut self) -> sval::Result {
211        self.fail(Error::unsupported("text", "sequence"))
212    }
213
214    fn seq_end(&mut self) -> sval::Result {
215        self.fail(Error::unsupported("text", "sequence"))
216    }
217}
218
219impl<'sval> fmt::Write for TextBuf<'sval> {
220    fn write_str(&mut self, s: &str) -> fmt::Result {
221        self.push_fragment_computed(s).map_err(|_| fmt::Error)
222    }
223}
224
225impl<'sval> Default for TextBuf<'sval> {
226    #[inline(always)]
227    fn default() -> Self {
228        TextBuf::new()
229    }
230}
231
232impl<'sval> From<&'sval str> for TextBuf<'sval> {
233    #[inline(always)]
234    fn from(fragment: &'sval str) -> Self {
235        TextBuf {
236            buf: FragmentBuf::new(fragment),
237        }
238    }
239}
240
241impl<'sval> AsRef<str> for TextBuf<'sval> {
242    #[inline(always)]
243    fn as_ref(&self) -> &str {
244        self.as_str()
245    }
246}
247
248impl<'a> sval::Value for TextBuf<'a> {
249    fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result {
250        self.as_str().stream(stream)
251    }
252}
253
254impl<'sval> sval_ref::ValueRef<'sval> for TextBuf<'sval> {
255    fn stream_ref<S: sval::Stream<'sval> + ?Sized>(&self, stream: &mut S) -> sval::Result {
256        match self.as_borrowed_str() {
257            Some(v) => stream.value(v),
258            None => {
259                let v = self.as_str();
260
261                stream.text_begin(Some(v.len()))?;
262                stream.text_fragment_computed(v)?;
263                stream.text_end()
264            }
265        }
266    }
267}
268
269/**
270Buffer binary fragments into a single contiguous slice.
271
272In no-std environments, this buffer only supports a single
273borrowed binary fragment. Other methods will fail.
274*/
275#[derive(Debug, Clone, PartialEq, Eq)]
276pub struct BinaryBuf<'sval> {
277    buf: FragmentBuf<'sval, [u8]>,
278}
279
280impl<'sval> BinaryBuf<'sval> {
281    /**
282    Create a new empty binary buffer.
283    */
284    #[inline(always)]
285    pub fn new() -> Self {
286        BinaryBuf {
287            buf: FragmentBuf::new(&[]),
288        }
289    }
290
291    /**
292    Buffer a binary value into a contiguous slice.
293    */
294    pub fn collect(value: &'sval (impl sval::Value + ?Sized)) -> Result<Self, Error> {
295        let mut collector = BinaryCollector {
296            buf: BinaryBuf::new(),
297            err: None,
298        };
299
300        value
301            .stream(&mut collector)
302            .map_err(|_| collector.err.unwrap())?;
303
304        Ok(collector.buf)
305    }
306
307    /**
308    Clear the binary buffer so it can be re-used.
309    */
310    #[inline(always)]
311    pub fn clear(&mut self) {
312        *self = Default::default();
313    }
314
315    /**
316    Push a borrowed binary fragment onto the buffer.
317    */
318    #[inline(always)]
319    pub fn push_fragment(&mut self, fragment: &'sval [u8]) -> Result<(), Error> {
320        self.buf.push(fragment)
321    }
322
323    /**
324    Push a computed binary fragment onto the buffer.
325
326    If the `std` feature of this library is enabled, this method will
327    buffer the fragment. In no-std environments this method will fail.
328    */
329    #[inline(always)]
330    pub fn push_fragment_computed(&mut self, fragment: &[u8]) -> Result<(), Error> {
331        self.buf.push_computed(fragment)
332    }
333
334    /**
335    Try get the contents of the buffer as a slice borrowed for the `'sval` lifetime.
336    */
337    #[inline(always)]
338    pub fn as_borrowed_slice(&self) -> Option<&'sval [u8]> {
339        self.buf.as_borrowed_inner()
340    }
341
342    /**
343    Get the contents of the buffer as a slice.
344    */
345    #[inline(always)]
346    pub fn as_slice(&self) -> &[u8] {
347        self.buf.as_inner()
348    }
349
350    #[cfg(feature = "alloc")]
351    pub(crate) fn into_owned_in_place(&mut self) -> &mut BinaryBuf<'static> {
352        let BinaryBuf { ref mut buf } = self;
353
354        crate::assert_static(buf.into_owned_in_place());
355
356        // SAFETY: `self` no longer contains any data borrowed for `'sval`
357        unsafe { mem::transmute::<&mut BinaryBuf<'sval>, &mut BinaryBuf<'static>>(self) }
358    }
359}
360
361struct BinaryCollector<'a> {
362    buf: BinaryBuf<'a>,
363    err: Option<Error>,
364}
365
366impl<'a> BinaryCollector<'a> {
367    fn try_catch(
368        &mut self,
369        f: impl FnOnce(&mut BinaryBuf<'a>) -> Result<(), Error>,
370    ) -> sval::Result {
371        match f(&mut self.buf) {
372            Ok(()) => Ok(()),
373            Err(e) => self.fail(e),
374        }
375    }
376
377    fn fail(&mut self, err: Error) -> sval::Result {
378        self.err = Some(err);
379        sval::error()
380    }
381}
382
383impl<'a> sval::Stream<'a> for BinaryCollector<'a> {
384    fn binary_begin(&mut self, _: Option<usize>) -> sval::Result {
385        Ok(())
386    }
387
388    fn binary_fragment(&mut self, fragment: &'a [u8]) -> sval::Result {
389        self.try_catch(|buf| buf.push_fragment(fragment))
390    }
391
392    fn binary_fragment_computed(&mut self, fragment: &[u8]) -> sval::Result {
393        self.try_catch(|buf| buf.push_fragment_computed(fragment))
394    }
395
396    fn binary_end(&mut self) -> sval::Result {
397        Ok(())
398    }
399
400    fn text_begin(&mut self, _: Option<usize>) -> sval::Result {
401        self.fail(Error::unsupported("binary", "text"))
402    }
403
404    fn text_fragment_computed(&mut self, _: &str) -> sval::Result {
405        self.fail(Error::unsupported("binary", "text"))
406    }
407
408    fn text_end(&mut self) -> sval::Result {
409        self.fail(Error::unsupported("binary", "text"))
410    }
411
412    fn null(&mut self) -> sval::Result {
413        self.fail(Error::unsupported("binary", "null"))
414    }
415
416    fn bool(&mut self, _: bool) -> sval::Result {
417        self.fail(Error::unsupported("binary", "boolean"))
418    }
419
420    fn u8(&mut self, value: u8) -> sval::Result {
421        self.try_catch(|buf| buf.push_fragment_computed(&[value]))
422    }
423
424    fn i64(&mut self, _: i64) -> sval::Result {
425        self.fail(Error::unsupported("binary", "integer"))
426    }
427
428    fn f64(&mut self, _: f64) -> sval::Result {
429        self.fail(Error::unsupported("binary", "floating point"))
430    }
431
432    fn map_begin(&mut self, _: Option<usize>) -> sval::Result {
433        self.fail(Error::unsupported("binary", "map"))
434    }
435
436    fn seq_begin(&mut self, _: Option<usize>) -> sval::Result {
437        Ok(())
438    }
439
440    fn seq_value_begin(&mut self) -> sval::Result {
441        Ok(())
442    }
443
444    fn seq_value_end(&mut self) -> sval::Result {
445        Ok(())
446    }
447
448    fn seq_end(&mut self) -> sval::Result {
449        Ok(())
450    }
451}
452
453impl<'sval> Default for BinaryBuf<'sval> {
454    #[inline(always)]
455    fn default() -> Self {
456        BinaryBuf::new()
457    }
458}
459
460impl<'sval> From<&'sval [u8]> for BinaryBuf<'sval> {
461    #[inline(always)]
462    fn from(fragment: &'sval [u8]) -> Self {
463        BinaryBuf {
464            buf: FragmentBuf::new(fragment),
465        }
466    }
467}
468
469impl<'sval, const N: usize> From<&'sval [u8; N]> for BinaryBuf<'sval> {
470    fn from(fragment: &'sval [u8; N]) -> Self {
471        BinaryBuf {
472            buf: FragmentBuf::new(fragment),
473        }
474    }
475}
476
477impl<'sval> AsRef<[u8]> for BinaryBuf<'sval> {
478    #[inline(always)]
479    fn as_ref(&self) -> &[u8] {
480        self.as_slice()
481    }
482}
483
484impl<'a> sval::Value for BinaryBuf<'a> {
485    fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result {
486        sval::BinarySlice::new(self.as_slice()).stream(stream)
487    }
488}
489
490impl<'sval> sval_ref::ValueRef<'sval> for BinaryBuf<'sval> {
491    fn stream_ref<S: sval::Stream<'sval> + ?Sized>(&self, stream: &mut S) -> sval::Result {
492        match self.as_borrowed_slice() {
493            Some(v) => stream.value(sval::BinarySlice::new(v)),
494            None => stream.value_computed(sval::BinarySlice::new(self.as_slice())),
495        }
496    }
497}
498
499#[cfg(not(feature = "alloc"))]
500trait Fragment {
501    #[inline(always)]
502    fn to_fragment<'sval>(&'sval self) -> &'sval Self {
503        self
504    }
505
506    fn can_replace(&self) -> bool;
507}
508
509#[cfg(feature = "alloc")]
510trait Fragment: ToOwned {
511    #[inline(always)]
512    fn to_fragment<'sval>(&'sval self) -> Cow<'sval, Self> {
513        Cow::Borrowed(self)
514    }
515
516    fn extend(buf: &mut Cow<Self>, fragment: &Self);
517
518    fn can_replace(&self) -> bool;
519
520    fn into_owned_in_place<'a, 'sval>(buf: &'a mut Cow<'sval, Self>) -> &'a mut Cow<'static, Self> {
521        if let Cow::Borrowed(v) = buf {
522            *buf = Cow::Owned(v.to_owned());
523        }
524
525        // SAFETY: `self` no longer contains any data borrowed for `'sval`
526        unsafe { mem::transmute::<&mut Cow<'_, Self>, &mut Cow<'static, Self>>(buf) }
527    }
528}
529
530impl Fragment for str {
531    #[cfg(feature = "alloc")]
532    #[inline(always)]
533    fn extend(buf: &mut Cow<Self>, fragment: &Self) {
534        buf.to_mut().push_str(fragment);
535    }
536
537    fn can_replace(&self) -> bool {
538        self.len() == 0
539    }
540}
541
542impl Fragment for [u8] {
543    #[cfg(feature = "alloc")]
544    #[inline(always)]
545    fn extend(buf: &mut Cow<Self>, fragment: &Self) {
546        buf.to_mut().extend(fragment);
547    }
548
549    fn can_replace(&self) -> bool {
550        self.len() == 0
551    }
552}
553
554struct FragmentBuf<'sval, T: ?Sized + Fragment> {
555    #[cfg(not(feature = "alloc"))]
556    value: &'sval T,
557    #[cfg(feature = "alloc")]
558    value: Cow<'sval, T>,
559}
560
561#[cfg(not(feature = "alloc"))]
562impl<'sval, T: ?Sized + Fragment> Clone for FragmentBuf<'sval, T> {
563    fn clone(&self) -> Self {
564        FragmentBuf { value: self.value }
565    }
566}
567
568#[cfg(feature = "alloc")]
569impl<'sval, T: ?Sized + Fragment> Clone for FragmentBuf<'sval, T>
570where
571    T::Owned: Clone,
572{
573    fn clone(&self) -> Self {
574        FragmentBuf {
575            value: self.value.clone(),
576        }
577    }
578}
579
580#[cfg(not(feature = "alloc"))]
581impl<'sval, T: ?Sized + Fragment + fmt::Debug> fmt::Debug for FragmentBuf<'sval, T> {
582    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
583        self.value.fmt(f)
584    }
585}
586
587#[cfg(feature = "alloc")]
588impl<'sval, T: ?Sized + Fragment + fmt::Debug> fmt::Debug for FragmentBuf<'sval, T>
589where
590    T::Owned: fmt::Debug,
591{
592    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
593        self.value.fmt(f)
594    }
595}
596
597#[cfg(not(feature = "alloc"))]
598impl<'sval, T: ?Sized + Fragment + PartialEq> PartialEq for FragmentBuf<'sval, T> {
599    fn eq(&self, other: &Self) -> bool {
600        self.value == other.value
601    }
602}
603
604#[cfg(feature = "alloc")]
605impl<'sval, T: ?Sized + Fragment + PartialEq> PartialEq for FragmentBuf<'sval, T>
606where
607    T::Owned: PartialEq,
608{
609    fn eq(&self, other: &Self) -> bool {
610        self.value == other.value
611    }
612}
613
614#[cfg(not(feature = "alloc"))]
615impl<'sval, T: ?Sized + Fragment + PartialEq> Eq for FragmentBuf<'sval, T> {}
616
617#[cfg(feature = "alloc")]
618impl<'sval, T: ?Sized + Fragment + Eq> Eq for FragmentBuf<'sval, T> where T::Owned: Eq {}
619
620impl<'sval, T: ?Sized + Fragment> FragmentBuf<'sval, T> {
621    #[inline(always)]
622    fn new(value: &'sval T) -> Self {
623        FragmentBuf {
624            value: value.to_fragment(),
625        }
626    }
627
628    #[inline(always)]
629    fn push(&mut self, fragment: &'sval T) -> Result<(), Error> {
630        if self.value.can_replace() {
631            self.value = fragment.to_fragment();
632
633            Ok(())
634        } else {
635            self.push_computed(fragment)
636        }
637    }
638
639    #[inline(always)]
640    fn push_computed(&mut self, fragment: &T) -> Result<(), Error> {
641        #[cfg(feature = "alloc")]
642        {
643            Fragment::extend(&mut self.value, fragment);
644
645            Ok(())
646        }
647
648        #[cfg(not(feature = "alloc"))]
649        {
650            let _ = fragment;
651            Err(Error::no_alloc("computed fragment"))
652        }
653    }
654
655    #[inline(always)]
656    fn as_borrowed_inner(&self) -> Option<&'sval T> {
657        #[cfg(feature = "alloc")]
658        {
659            match self.value {
660                Cow::Borrowed(value) => Some(value),
661                Cow::Owned(_) => None,
662            }
663        }
664
665        #[cfg(not(feature = "alloc"))]
666        {
667            Some(self.value)
668        }
669    }
670
671    #[inline(always)]
672    fn as_inner(&self) -> &T {
673        #[cfg(feature = "alloc")]
674        {
675            &*self.value
676        }
677
678        #[cfg(not(feature = "alloc"))]
679        {
680            self.value
681        }
682    }
683
684    #[cfg(feature = "alloc")]
685    pub(crate) fn into_owned_in_place(&mut self) -> &mut FragmentBuf<'static, T> {
686        crate::assert_static(Fragment::into_owned_in_place(&mut self.value));
687
688        // SAFETY: `self` no longer contains any data borrowed for `'sval`
689        unsafe { mem::transmute::<&mut FragmentBuf<'sval, T>, &mut FragmentBuf<'static, T>>(self) }
690    }
691}
692
693#[cfg(test)]
694mod tests {
695    use super::*;
696    use sval_ref::ValueRef;
697
698    #[test]
699    fn text_buf_empty() {
700        assert_eq!("", TextBuf::new().as_borrowed_str().unwrap());
701    }
702
703    #[test]
704    fn binary_buf_empty() {
705        assert_eq!(&[] as &[u8], BinaryBuf::new().as_borrowed_slice().unwrap());
706    }
707
708    #[test]
709    fn text_fragment_replace() {
710        let mut buf = TextBuf::new();
711
712        assert_eq!("", buf.as_str());
713        assert_eq!(Some(""), buf.as_borrowed_str());
714
715        buf.push_fragment("abc").unwrap();
716
717        assert_eq!("abc", buf.as_str());
718        assert_eq!(Some("abc"), buf.as_borrowed_str());
719    }
720
721    #[test]
722    fn text_fragment_clear() {
723        let mut buf = TextBuf::new();
724
725        buf.push_fragment("abc").unwrap();
726        buf.clear();
727
728        assert_eq!("", buf.as_str());
729    }
730
731    #[test]
732    fn binary_fragment_replace() {
733        let mut buf = BinaryBuf::new();
734
735        assert_eq!(b"" as &[u8], buf.as_slice());
736        assert_eq!(Some(b"" as &[u8]), buf.as_borrowed_slice());
737
738        buf.push_fragment(b"abc").unwrap();
739
740        assert_eq!(b"abc", buf.as_slice());
741        assert_eq!(Some(b"abc" as &[u8]), buf.as_borrowed_slice());
742    }
743
744    #[test]
745    fn binary_fragment_clear() {
746        let mut buf = BinaryBuf::new();
747
748        buf.push_fragment(b"abc").unwrap();
749        buf.clear();
750
751        assert_eq!(b"", buf.as_slice());
752    }
753
754    #[test]
755    #[cfg(feature = "alloc")]
756    fn text_fragment_computed() {
757        let mut buf = TextBuf::new();
758
759        buf.push_fragment_computed("abc").unwrap();
760
761        assert_eq!("abc", buf.as_str());
762        assert_eq!(None, buf.as_borrowed_str());
763    }
764
765    #[test]
766    #[cfg(feature = "alloc")]
767    fn binary_fragment_computed() {
768        let mut buf = BinaryBuf::new();
769
770        buf.push_fragment_computed(b"abc").unwrap();
771
772        assert_eq!(b"abc" as &[u8], buf.as_slice());
773        assert_eq!(None, buf.as_borrowed_slice());
774    }
775
776    #[test]
777    #[cfg(feature = "alloc")]
778    fn text_fragment_extend() {
779        let mut buf = TextBuf::new();
780
781        buf.push_fragment("abc").unwrap();
782        buf.push_fragment("def").unwrap();
783
784        assert_eq!("abcdef", buf.as_str());
785        assert_eq!(None, buf.as_borrowed_str());
786    }
787
788    #[test]
789    #[cfg(feature = "alloc")]
790    fn binary_fragment_extend() {
791        let mut buf = BinaryBuf::new();
792
793        buf.push_fragment(b"abc").unwrap();
794        buf.push_fragment(b"def").unwrap();
795
796        assert_eq!(b"abcdef" as &[u8], buf.as_slice());
797        assert_eq!(None, buf.as_borrowed_slice());
798    }
799
800    #[test]
801    #[cfg(feature = "alloc")]
802    fn collect_text_buf() {
803        let buf = TextBuf::collect("a string").unwrap();
804
805        assert_eq!(Some("a string"), buf.as_borrowed_str());
806    }
807
808    #[test]
809    #[cfg(feature = "alloc")]
810    fn collect_binary_buf() {
811        let buf = BinaryBuf::collect(sval::BinarySlice::new(b"a string")).unwrap();
812
813        assert_eq!(Some(b"a string" as &[u8]), buf.as_borrowed_slice());
814    }
815
816    #[test]
817    #[cfg(feature = "alloc")]
818    fn collect_binary_buf_seq() {
819        let buf = BinaryBuf::collect(b"a string").unwrap();
820
821        assert_eq!(b"a string" as &[u8], buf.as_slice());
822    }
823
824    #[test]
825    fn stream_text_buf() {
826        let mut buf = TextBuf::new();
827        buf.push_fragment("abc").unwrap();
828
829        sval_test::assert_tokens(&buf, {
830            use sval_test::Token::*;
831
832            &[TextBegin(Some(3)), TextFragment("abc"), TextEnd]
833        });
834    }
835
836    #[test]
837    #[cfg(feature = "alloc")]
838    fn stream_ref_text_buf_computed() {
839        let mut buf = TextBuf::new();
840        buf.push_fragment("123").unwrap();
841        buf.push_fragment("()").unwrap();
842        buf.push_fragment("data").unwrap();
843
844        let mut tokens = sval_test::TokenBuf::new();
845        buf.stream_ref(&mut tokens).unwrap();
846
847        assert_eq!(tokens.as_tokens(), {
848            use sval_test::Token::*;
849
850            &[
851                TextBegin(Some(9)),
852                TextFragmentComputed("123()data".to_owned()),
853                TextEnd,
854            ]
855        });
856    }
857
858    #[test]
859    fn stream_ref_text_buf_borrowed() {
860        let mut buf = TextBuf::new();
861        buf.push_fragment("123").unwrap();
862
863        let mut tokens = sval_test::TokenBuf::new();
864        buf.stream_ref(&mut tokens).unwrap();
865
866        assert_eq!(tokens.as_tokens(), {
867            use sval_test::Token::*;
868
869            &[TextBegin(Some(3)), TextFragment("123"), TextEnd]
870        });
871    }
872
873    #[test]
874    #[cfg(feature = "alloc")]
875    fn collect_text_buf_display() {
876        let buf = TextBuf::collect_display(true).unwrap();
877
878        assert_eq!("true", buf.as_str());
879        assert!(buf.as_borrowed_str().is_none());
880    }
881
882    #[test]
883    #[cfg(feature = "alloc")]
884    fn stream_text_buf_display() {
885        let mut buf = TextBuf::new();
886
887        buf.push_display(true).unwrap();
888        buf.push_display(false).unwrap();
889
890        assert_eq!("truefalse", buf.as_str());
891        assert!(buf.as_borrowed_str().is_none());
892    }
893
894    #[test]
895    #[cfg(feature = "alloc")]
896    fn stream_binary_buf_computed() {
897        let mut buf = BinaryBuf::new();
898        buf.push_fragment(b"abc").unwrap();
899        buf.push_fragment_computed(b"def").unwrap();
900
901        sval_test::assert_tokens(&buf, {
902            use sval_test::Token::*;
903
904            &[BinaryBegin(Some(6)), BinaryFragment(b"abcdef"), BinaryEnd]
905        });
906    }
907
908    #[test]
909    fn stream_ref_binary_buf_borrowed() {
910        let mut buf = BinaryBuf::new();
911        buf.push_fragment(b"abc").unwrap();
912
913        let mut tokens = sval_test::TokenBuf::new();
914        buf.stream_ref(&mut tokens).unwrap();
915
916        assert_eq!(tokens.as_tokens(), {
917            use sval_test::Token::*;
918
919            &[BinaryBegin(Some(3)), BinaryFragment(b"abc"), BinaryEnd]
920        });
921    }
922
923    #[test]
924    #[cfg(feature = "alloc")]
925    fn stream_ref_binary_buf_computed() {
926        let mut buf = BinaryBuf::new();
927        buf.push_fragment(b"abc").unwrap();
928        buf.push_fragment_computed(b"def").unwrap();
929
930        let mut tokens = sval_test::TokenBuf::new();
931        buf.stream_ref(&mut tokens).unwrap();
932
933        assert_eq!(tokens.as_tokens(), {
934            use sval_test::Token::*;
935
936            &[
937                BinaryBegin(Some(6)),
938                BinaryFragmentComputed(b"abcdef".to_vec()),
939                BinaryEnd,
940            ]
941        });
942    }
943}