cbor_core/text.rs
1use std::borrow::Cow;
2
3use crate::Value;
4
5/// Conversion helper for [`Value::text_string`].
6///
7/// Wraps a `Cow<'a, str>` so that [`Value::text_string`] can accept
8/// owned and borrowed string inputs through a single
9/// `impl Into<TextString>` bound. This mirrors how [`Array`](crate::Array)
10/// and [`Map`](crate::Map) abstract their input shapes.
11///
12/// Supported source types:
13///
14/// - `&'a str` (and any `&'a T` with `T: AsRef<str>`) borrows zero-copy.
15/// - Owned `String` is moved without copying.
16/// - `Cow<'a, str>` is preserved as-is.
17/// - `char` allocates a one-character `String`.
18///
19/// ```
20/// # use cbor_core::Value;
21/// // Borrows from the literal:
22/// let v = Value::text_string("hello");
23/// assert_eq!(v.as_str().unwrap(), "hello");
24///
25/// // Owns its storage:
26/// let v = Value::text_string(String::from("hello"));
27/// assert_eq!(v.as_str().unwrap(), "hello");
28/// ```
29#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
30pub struct TextString<'a>(Cow<'a, str>);
31
32impl<'a> TextString<'a> {
33 /// Create an empty text string.
34 ///
35 /// The result is `Cow::Borrowed("")` and lives for any lifetime.
36 pub const fn new() -> Self {
37 Self(Cow::Borrowed(""))
38 }
39
40 /// Borrow the contents as a `&str`.
41 pub fn as_str(&self) -> &str {
42 self.0.as_ref()
43 }
44
45 /// Borrow the contents as a mutable `String`, cloning if the
46 /// inner `Cow` is currently borrowed.
47 pub fn as_string_mut(&mut self) -> &mut String {
48 self.0.to_mut()
49 }
50
51 /// Detach from any borrow, returning a `TextString` with an
52 /// independent lifetime.
53 ///
54 /// A borrowed `TextString<'a>` is copied into an owned `String`;
55 /// an already-owned one is returned unchanged. The result can
56 /// be assigned to any lifetime, in particular `TextString<'static>`.
57 pub fn into_owned<'b>(self) -> TextString<'b> {
58 match self.0 {
59 Cow::Borrowed(text) => TextString(text.to_string().into()),
60 Cow::Owned(text) => TextString(text.into()),
61 }
62 }
63}
64
65impl<'a> From<char> for TextString<'a> {
66 fn from(value: char) -> Self {
67 Self(value.to_string().into())
68 }
69}
70
71impl<'a, T> From<&'a T> for TextString<'a>
72where
73 T: AsRef<str> + ?Sized,
74{
75 fn from(value: &'a T) -> Self {
76 Self(value.as_ref().into())
77 }
78}
79
80impl<'a> From<String> for TextString<'a> {
81 fn from(value: String) -> Self {
82 Self(value.into())
83 }
84}
85
86impl<'a> From<Cow<'a, str>> for TextString<'a> {
87 fn from(value: Cow<'a, str>) -> Self {
88 Self(value)
89 }
90}
91
92impl<'a> From<TextString<'a>> for Value<'a> {
93 fn from(value: TextString<'a>) -> Self {
94 Self::TextString(value.0)
95 }
96}