1use crate::MessageConformance;
2use bstr::{BStr, BString};
3use std::borrow::Cow;
4use std::str::Utf8Error;
5use std::sync::Arc;
6
7pub enum SharedString<'a> {
12 Owned(Arc<Vec<u8>>),
13 Borrowed(&'a [u8]),
14 Sliced {
15 other: Arc<Vec<u8>>,
16 range: std::ops::Range<usize>,
17 },
18}
19
20impl std::cmp::PartialEq<Self> for SharedString<'_> {
21 fn eq(&self, other: &Self) -> bool {
22 self.as_bytes().eq(other.as_bytes())
23 }
24}
25
26impl std::cmp::PartialEq<&str> for SharedString<'_> {
27 fn eq(&self, other: &&str) -> bool {
28 self.as_bytes().eq(other.as_bytes())
29 }
30}
31
32impl std::fmt::Display for SharedString<'_> {
33 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
34 let s = BStr::new(self.as_bytes());
35 (&s as &dyn std::fmt::Display).fmt(fmt)
36 }
37}
38
39impl std::fmt::Debug for SharedString<'_> {
40 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
41 let s = BStr::new(self.as_bytes());
42 (&s as &dyn std::fmt::Debug).fmt(fmt)
43 }
44}
45
46impl std::ops::Index<usize> for SharedString<'_> {
47 type Output = u8;
48 fn index(&self, index: usize) -> &u8 {
49 &self.as_bytes()[index]
50 }
51}
52
53impl Clone for SharedString<'_> {
54 fn clone(&self) -> Self {
55 match self {
56 Self::Owned(s) => Self::Sliced {
57 other: Arc::clone(s),
58 range: 0..s.len(),
59 },
60 Self::Borrowed(s) => Self::Borrowed(s),
61 Self::Sliced { other, range } => Self::Sliced {
62 other: Arc::clone(other),
63 range: range.clone(),
64 },
65 }
66 }
67}
68
69impl SharedString<'_> {
70 pub fn slice(&self, slice_range: std::ops::Range<usize>) -> Self {
71 self.assert_slice(slice_range.clone());
72 match self {
73 Self::Owned(s) => Self::Sliced {
74 other: Arc::clone(s),
75 range: slice_range,
76 },
77 Self::Borrowed(s) => Self::Borrowed(s.get(slice_range).unwrap()),
78 Self::Sliced { other, range } => {
79 let len = slice_range.end - slice_range.start;
80 Self::Sliced {
81 other: Arc::clone(other),
82 range: range.start + slice_range.start..range.start + slice_range.start + len,
83 }
84 }
85 }
86 }
87
88 fn assert_slice(&self, slice_range: std::ops::Range<usize>) {
89 if self.as_bytes().get(slice_range.clone()).is_none() {
90 panic!("slice range {slice_range:?} is invalid for {self:?}");
91 }
92 }
93
94 pub fn as_bytes(&self) -> &[u8] {
95 match self {
96 Self::Owned(s) => s,
97 Self::Borrowed(s) => s,
98 Self::Sliced { other, range } => other.get(range.clone()).unwrap(),
99 }
100 }
101
102 pub fn to_str(&self) -> Result<&str, Utf8Error> {
103 std::str::from_utf8(self.as_bytes())
104 }
105
106 pub fn to_str_lossy(&self) -> Cow<'_, str> {
107 String::from_utf8_lossy(self.as_bytes())
108 }
109
110 pub fn len(&self) -> usize {
111 match self {
112 Self::Owned(s) => s.len(),
113 Self::Borrowed(s) => s.len(),
114 Self::Sliced { range, .. } => range.len(),
115 }
116 }
117
118 pub fn to_owned(&'_ self) -> SharedString<'static> {
119 match self {
120 SharedString::Owned(s) => SharedString::Owned(Arc::clone(s)),
121 SharedString::Borrowed(s) => SharedString::Owned(Arc::new(s.to_vec())),
122 SharedString::Sliced { other, range } => SharedString::Sliced {
123 other: other.clone(),
124 range: range.clone(),
125 },
126 }
127 }
128}
129
130impl From<BString> for SharedString<'_> {
131 fn from(s: BString) -> Self {
132 let v: Vec<u8> = s.into();
133 v.into()
134 }
135}
136
137impl From<String> for SharedString<'_> {
138 fn from(s: String) -> Self {
139 Self::Owned(Arc::new(s.into_bytes()))
140 }
141}
142
143impl From<Vec<u8>> for SharedString<'_> {
144 fn from(s: Vec<u8>) -> Self {
145 Self::Owned(Arc::new(s))
146 }
147}
148
149impl<'a> From<&'a str> for SharedString<'a> {
150 fn from(s: &'a str) -> Self {
151 Self::Borrowed(s.as_bytes())
152 }
153}
154
155impl<'a> From<&'a [u8]> for SharedString<'a> {
156 fn from(s: &'a [u8]) -> Self {
157 Self::Borrowed(s)
158 }
159}
160
161pub trait IntoSharedString<'a> {
162 fn into_shared_string(self) -> (SharedString<'a>, MessageConformance);
163}
164
165impl<'a> IntoSharedString<'a> for SharedString<'a> {
166 fn into_shared_string(self) -> (SharedString<'a>, MessageConformance) {
167 (self, MessageConformance::default())
168 }
169}
170
171impl<'a> IntoSharedString<'a> for String {
172 fn into_shared_string(self) -> (SharedString<'a>, MessageConformance) {
173 (
174 SharedString::Owned(Arc::new(self.into_bytes())),
175 MessageConformance::default(),
176 )
177 }
178}
179
180impl<'a> IntoSharedString<'a> for &'a str {
181 fn into_shared_string(self) -> (SharedString<'a>, MessageConformance) {
182 (
183 SharedString::Borrowed(self.as_bytes()),
184 MessageConformance::default(),
185 )
186 }
187}
188
189impl<'a> IntoSharedString<'a> for &'a [u8] {
190 fn into_shared_string(self) -> (SharedString<'a>, MessageConformance) {
191 match std::str::from_utf8(self) {
192 Ok(s) => (
193 SharedString::Borrowed(s.as_bytes()),
194 MessageConformance::default(),
195 ),
196 Err(_) => (
197 SharedString::Borrowed(self),
198 MessageConformance::NEEDS_TRANSFER_ENCODING,
199 ),
200 }
201 }
202}
203
204impl<'a> IntoSharedString<'a> for BString {
205 fn into_shared_string(self) -> (SharedString<'a>, MessageConformance) {
206 let bytes: Vec<u8> = self.into();
207 match std::str::from_utf8(&bytes) {
208 Ok(_) => (bytes.into(), MessageConformance::default()),
209 Err(_) => (bytes.into(), MessageConformance::NEEDS_TRANSFER_ENCODING),
210 }
211 }
212}