1use crate::{
2 std::fmt::{self, Write as _},
3 Error, Result, Stream, Tag, Value,
4};
5
6#[repr(transparent)]
10pub struct Display<V: ?Sized>(V);
11
12impl<V: fmt::Display> Display<V> {
13 pub fn new(value: V) -> Display<V> {
17 Display(value)
18 }
19
20 pub fn inner(&self) -> &V {
24 &self.0
25 }
26
27 pub fn into_inner(self) -> V {
31 self.0
32 }
33}
34
35impl<V: fmt::Display + ?Sized> Display<V> {
36 pub fn new_borrowed<'a>(value: &'a V) -> &'a Display<V> {
40 unsafe { &*(value as *const _ as *const Display<V>) }
42 }
43}
44
45impl<V: fmt::Display> Value for Display<V> {
46 fn stream<'sval, S: Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> Result {
47 stream.text_begin(None)?;
48 stream_display_fragments(stream, &self.0)?;
49 stream.text_end()
50 }
51}
52
53pub fn stream_display<'sval>(
59 stream: &mut (impl Stream<'sval> + ?Sized),
60 value: impl fmt::Display,
61) -> Result {
62 stream.value_computed(&Display::new(value))
63}
64
65pub fn stream_display_fragments<'sval>(
71 stream: &mut (impl Stream<'sval> + ?Sized),
72 value: impl fmt::Display,
73) -> Result {
74 write!(
75 Writer(|fragment: &str| stream
76 .text_fragment_computed(fragment)
77 .map_err(|_| fmt::Error)),
78 "{}",
79 value
80 )
81 .map_err(|_| Error::new())
82}
83
84struct Writer<F>(F);
85
86impl<F: FnMut(&str) -> fmt::Result> fmt::Write for Writer<F> {
87 fn write_str(&mut self, s: &str) -> fmt::Result {
88 (self.0)(s).map_err(|_| fmt::Error)
89 }
90}
91
92impl Value for char {
93 fn stream<'sval, S: Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> Result {
94 let mut buf = [0; 4];
95 let value = &*self.encode_utf8(&mut buf);
96
97 stream.text_begin(Some(value.len()))?;
98 stream.text_fragment_computed(value)?;
99 stream.text_end()
100 }
101}
102
103impl Value for str {
104 fn stream<'sval, S: Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> Result {
105 stream.text_begin(Some(self.len()))?;
106 stream.text_fragment(self)?;
107 stream.text_end()
108 }
109
110 fn tag(&self) -> Option<Tag> {
111 None
112 }
113
114 fn to_text(&self) -> Option<&str> {
115 Some(self)
116 }
117}
118
119#[cfg(feature = "alloc")]
120mod alloc_support {
121 use super::*;
122
123 use crate::std::string::String;
124
125 impl Value for String {
126 fn stream<'a, S: Stream<'a> + ?Sized>(&'a self, stream: &mut S) -> Result {
127 (&**self).stream(stream)
128 }
129
130 fn tag(&self) -> Option<Tag> {
131 None
132 }
133
134 #[inline]
135 fn to_text(&self) -> Option<&str> {
136 Some(self)
137 }
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 struct TextLike(&'static str);
146 struct TextLikeComputed(&'static str);
147
148 impl Value for TextLike {
149 fn stream<'sval, S: Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> Result {
150 self.0.stream(stream)
151 }
152 }
153
154 impl Value for TextLikeComputed {
155 fn stream<'sval, S: Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> Result {
156 stream.text_begin(Some(self.0.len()))?;
157 stream.text_fragment_computed(self.0)?;
158 stream.text_end()
159 }
160 }
161
162 #[test]
163 fn string_cast() {
164 assert_eq!(Some("a string"), "a string".to_text());
165 assert_eq!(Some("a string"), TextLike("a string").to_text());
166 assert_eq!(None, TextLikeComputed("123").to_text());
167 }
168
169 #[test]
170 fn string_tag() {
171 assert_eq!(None, TextLike("123").tag());
172 assert_eq!(None, TextLikeComputed("123").tag());
173 }
174}