lilliput_core/value/
string.rs1#[cfg(any(test, feature = "testing"))]
2use proptest::prelude::*;
3#[cfg(any(test, feature = "testing"))]
4use proptest_derive::Arbitrary;
5
6#[cfg_attr(any(test, feature = "testing"), derive(Arbitrary))]
8#[derive(Default, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
9pub struct StringValue(pub String);
10
11impl StringValue {
12 pub fn as_str(&self) -> &str {
14 &self.0
15 }
16
17 pub fn into_string(self) -> String {
19 self.0
20 }
21
22 pub fn len(&self) -> usize {
24 self.0.len()
25 }
26
27 pub fn is_empty(&self) -> bool {
29 self.0.is_empty()
30 }
31}
32
33impl From<String> for StringValue {
34 fn from(value: String) -> Self {
35 Self(value)
36 }
37}
38
39impl<'a> From<&'a StringValue> for &'a str {
40 fn from(value: &'a StringValue) -> Self {
41 &value.0
42 }
43}
44
45impl From<StringValue> for String {
46 fn from(value: StringValue) -> Self {
47 value.0
48 }
49}
50
51impl std::fmt::Debug for StringValue {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 if f.alternate() {
54 write!(f, "{:#?}", self.0)
55 } else {
56 write!(f, "{:?}", self.0)
57 }
58 }
59}
60
61impl std::fmt::Display for StringValue {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 write!(f, "{}", self.0)
64 }
65}
66
67#[cfg(feature = "serde")]
68impl serde::Serialize for StringValue {
69 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
70 where
71 S: serde::Serializer,
72 {
73 self.0.serialize(serializer)
74 }
75}
76
77#[cfg(feature = "serde")]
78impl<'de> serde::Deserialize<'de> for StringValue {
79 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
80 where
81 D: serde::Deserializer<'de>,
82 {
83 Ok(Self(String::deserialize(deserializer)?))
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use proptest::prelude::*;
90 use test_log::test;
91
92 use crate::{
93 config::EncoderConfig,
94 decoder::Decoder,
95 encoder::Encoder,
96 io::{SliceReader, VecWriter},
97 value::Value,
98 };
99
100 use super::*;
101
102 #[test]
103 fn display() {
104 assert_eq!(
105 format!("{}", StringValue::from("lorem ipsum".to_owned())),
106 "lorem ipsum"
107 );
108 }
109
110 #[test]
111 fn debug() {
112 assert_eq!(
113 format!("{:?}", StringValue::from("lorem ipsum".to_owned())),
114 "\"lorem ipsum\""
115 );
116
117 assert_eq!(
118 format!("{:#?}", StringValue::from("lorem ipsum".to_owned())),
119 "\"lorem ipsum\""
120 );
121 }
122
123 proptest! {
124 #[test]
125 fn encode_decode_roundtrip(value in StringValue::arbitrary(), config in EncoderConfig::arbitrary()) {
126 let mut encoded: Vec<u8> = Vec::new();
127 let writer = VecWriter::new(&mut encoded);
128 let mut encoder = Encoder::new(writer, config);
129 encoder.encode_str(value.as_str()).unwrap();
130
131 prop_assert!(encoded.len() <= 1 + 8 + value.len());
132
133 let reader = SliceReader::new(&encoded);
134 let mut decoder = Decoder::from_reader(reader);
135 let decoded = decoder.decode_string().unwrap();
136 prop_assert_eq!(&decoded, value.as_str());
137
138 let reader = SliceReader::new(&encoded);
139 let mut decoder = Decoder::from_reader(reader);
140 let decoded = decoder.decode_value().unwrap();
141 let Value::String(decoded) = decoded else {
142 panic!("expected string value");
143 };
144 prop_assert_eq!(&decoded, &value);
145 }
146 }
147}