sark_json/bytes/
proofs.rs1use std::{ops, str};
2
3use o3::{buffer::storage, mem::Rejected};
4use sark_http::request;
5
6use crate::{Bytes, Token, bytes::seals, input::Input as _};
7
8#[doc(hidden)]
10pub trait Backing: seals::Owner + AsRef<[u8]> {}
11
12impl<T: seals::Owner + AsRef<[u8]>> Backing for T {}
13
14#[derive(Copy, Debug)]
16#[repr(transparent)]
17pub struct Text<T> {
18 owner: T,
19}
20
21#[derive(Copy, Debug)]
23#[repr(transparent)]
24pub struct Plain<T> {
25 text: Text<T>,
26}
27
28#[derive(Copy, Debug)]
30#[repr(transparent)]
31pub struct Raw<T> {
32 text: Text<T>,
33}
34
35impl<T: Copy> Clone for Text<T> {
36 fn clone(&self) -> Self {
37 *self
38 }
39}
40
41impl<T: Copy> Clone for Plain<T> {
42 fn clone(&self) -> Self {
43 *self
44 }
45}
46
47impl<T: Copy> Clone for Raw<T> {
48 fn clone(&self) -> Self {
49 *self
50 }
51}
52
53#[derive(Clone, Copy, Debug, PartialEq, Eq)]
54pub enum PlainError {
55 Utf8(str::Utf8Error),
56 Escape { index: usize, byte: u8 },
57}
58
59impl<T: Backing> Text<T> {
60 pub fn try_new(owner: T) -> Result<Self, Rejected<T, str::Utf8Error>> {
61 if let Err(error) = str::from_utf8(owner.as_ref()) {
62 return Err(Rejected::new(owner, error));
63 }
64 Ok(Self::admitted(owner))
65 }
66}
67
68impl<T: Backing> Plain<T> {
69 pub fn try_new(owner: T) -> Result<Self, Rejected<T, PlainError>> {
70 if let Err(error) = str::from_utf8(owner.as_ref()) {
71 return Err(Rejected::new(owner, PlainError::Utf8(error)));
72 }
73 for (index, &byte) in owner.as_ref().iter().enumerate() {
74 if byte < 0x20 || matches!(byte, b'"' | b'\\') {
75 return Err(Rejected::new(owner, PlainError::Escape { index, byte }));
76 }
77 }
78 Ok(Self::admitted(owner))
79 }
80}
81
82impl<T: Backing> Raw<T> {
83 pub fn try_new(owner: T) -> Result<Self, Rejected<T, crate::Error>> {
84 let input = owner.as_ref();
85 let mut index = 0;
86 if let Err(error) = input
87 .skip_value(&mut index)
88 .and_then(|()| input.finish(&mut index))
89 {
90 return Err(Rejected::new(owner, error));
91 }
92 Ok(Self::admitted(owner))
93 }
94}
95
96impl<'a> From<&'a str> for Text<&'a [u8]> {
97 fn from(owner: &'a str) -> Self {
98 Self::admitted(owner.as_bytes())
99 }
100}
101
102impl From<String> for Text<String> {
103 fn from(owner: String) -> Self {
104 Self::admitted(owner)
105 }
106}
107
108impl From<Token<0>> for Text<Token<0>> {
109 fn from(owner: Token<0>) -> Self {
110 Self::admitted(owner)
111 }
112}
113
114impl<T> From<Plain<T>> for Text<T> {
115 fn from(value: Plain<T>) -> Self {
116 value.text
117 }
118}
119
120impl<T> From<Raw<T>> for Text<T> {
121 fn from(value: Raw<T>) -> Self {
122 value.text
123 }
124}
125
126pub trait TextValue: seals::Text {
128 fn as_bytes(&self) -> &[u8];
129}
130
131impl<T: seals::Text + AsRef<[u8]> + ?Sized> TextValue for T {
132 fn as_bytes(&self) -> &[u8] {
133 self.as_ref()
134 }
135}
136impl<T: Backing> seals::Text for Text<T> {}
137impl<T: Backing> seals::Text for Plain<T> {}
138
139impl<T> Text<T> {
140 pub(crate) const fn admitted(owner: T) -> Self {
141 Self { owner }
142 }
143 pub fn into_inner(self) -> T {
144 self.owner
145 }
146}
147impl<T> Plain<T> {
148 pub(crate) const fn admitted(owner: T) -> Self {
149 Self {
150 text: Text::admitted(owner),
151 }
152 }
153 pub fn into_inner(self) -> T {
154 self.text.owner
155 }
156}
157impl<T> Raw<T> {
158 pub(crate) const fn admitted(owner: T) -> Self {
159 Self {
160 text: Text::admitted(owner),
161 }
162 }
163 pub fn into_inner(self) -> T {
164 self.text.owner
165 }
166}
167
168impl<T: Backing> Text<T> {
169 pub fn as_slice(&self) -> &[u8] {
170 self.owner.as_ref()
171 }
172 pub fn as_bytes(&self) -> &[u8] {
173 self.owner.as_ref()
174 }
175
176 pub fn as_str(&self) -> &str {
177 unsafe { str::from_utf8_unchecked(self.owner.as_ref()) }
180 }
181}
182
183impl<T: Backing> AsRef<[u8]> for Text<T> {
184 fn as_ref(&self) -> &[u8] {
185 self.owner.as_ref()
186 }
187}
188impl<T: Backing> AsRef<[u8]> for Plain<T> {
189 fn as_ref(&self) -> &[u8] {
190 self.text.owner.as_ref()
191 }
192}
193impl<T: Backing> AsRef<[u8]> for Raw<T> {
194 fn as_ref(&self) -> &[u8] {
195 self.text.owner.as_ref()
196 }
197}
198impl<T: Backing> ops::Deref for Text<T> {
199 type Target = [u8];
200 fn deref(&self) -> &[u8] {
201 self.owner.as_ref()
202 }
203}
204impl<T> ops::Deref for Plain<T> {
205 type Target = Text<T>;
206 fn deref(&self) -> &Text<T> {
207 &self.text
208 }
209}
210impl<T> ops::Deref for Raw<T> {
211 type Target = Text<T>;
212 fn deref(&self) -> &Text<T> {
213 &self.text
214 }
215}
216impl<T: Backing, U: AsRef<[u8]>> PartialEq<U> for Text<T> {
217 fn eq(&self, other: &U) -> bool {
218 self.owner.as_ref() == other.as_ref()
219 }
220}
221impl<T: Backing, U: AsRef<[u8]>> PartialEq<U> for Plain<T> {
222 fn eq(&self, other: &U) -> bool {
223 self.text.owner.as_ref() == other.as_ref()
224 }
225}
226impl<T: Backing, U: AsRef<[u8]>> PartialEq<U> for Raw<T> {
227 fn eq(&self, other: &U) -> bool {
228 self.text.owner.as_ref() == other.as_ref()
229 }
230}
231
232impl Text<storage::Shared> {
233 pub fn try_copy(value: &str) -> Result<Self, storage::AllocError> {
234 storage::Shared::try_copy(value.as_bytes()).map(Self::admitted)
235 }
236
237 pub fn into_request<'d>(self, id: request::Id<'d>) -> Text<request::Bytes<'d>> {
238 Text::admitted(request::Bytes::from_shared(id, self.owner))
239 }
240}
241impl Plain<storage::Shared> {
242 pub fn into_request<'d>(self, id: request::Id<'d>) -> Plain<request::Bytes<'d>> {
243 Plain {
244 text: self.text.into_request(id),
245 }
246 }
247}
248impl Raw<storage::Shared> {
249 pub fn into_request<'d>(self, id: request::Id<'d>) -> Raw<request::Bytes<'d>> {
250 Raw {
251 text: self.text.into_request(id),
252 }
253 }
254}
255
256impl Text<Bytes<'_>> {
257 pub fn try_share(self) -> Result<Text<storage::Shared>, Rejected<Self, storage::AllocError>> {
258 self.owner
259 .try_share()
260 .map(Text::admitted)
261 .map_err(|rejected| rejected.map(Text::admitted))
262 }
263}