1extern crate alloc;
7
8use std::borrow::Cow;
9
10use facet_core::{Def, KnownPointer, Type, UserType};
11use facet_reflect::{Partial, ReflectError, Span};
12
13pub enum PointerAction {
15 HandleAsScalar,
18 SliceBuilder,
20 SizedPointee,
22}
23
24pub fn begin_pointer<'input, const BORROW: bool>(
53 mut wip: Partial<'input, BORROW>,
54) -> Result<(Partial<'input, BORROW>, PointerAction), DessertError> {
55 let shape = wip.shape();
56 let ptr_def = match &shape.def {
57 Def::Pointer(ptr_def) => ptr_def,
58 _ => {
59 return Err(DessertError::Reflect {
60 error: ReflectError::OperationFailed {
61 shape,
62 operation: "begin_pointer requires a pointer type",
63 },
64 span: None,
65 });
66 }
67 };
68
69 if ptr_def
72 .pointee()
73 .is_some_and(|p| p.type_identifier == "str")
74 {
75 return Ok((wip, PointerAction::HandleAsScalar));
76 }
77
78 wip = wip.begin_smart_ptr()?;
80
81 let action = if wip.is_building_smart_ptr_slice() {
83 PointerAction::SliceBuilder
84 } else {
85 PointerAction::SizedPointee
86 };
87
88 Ok((wip, action))
89}
90
91#[derive(Debug)]
93pub enum DessertError {
94 Reflect {
96 error: ReflectError,
98 span: Option<Span>,
100 },
101 CannotBorrow {
103 message: Cow<'static, str>,
105 },
106}
107
108impl std::fmt::Display for DessertError {
109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 match self {
111 DessertError::Reflect { error, span } => {
112 if let Some(span) = span {
113 write!(f, "{} at {:?}", error, span)
114 } else {
115 write!(f, "{}", error)
116 }
117 }
118 DessertError::CannotBorrow { message } => write!(f, "{}", message),
119 }
120 }
121}
122
123impl std::error::Error for DessertError {
124 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
125 match self {
126 DessertError::Reflect { error, .. } => Some(error),
127 DessertError::CannotBorrow { .. } => None,
128 }
129 }
130}
131
132impl From<ReflectError> for DessertError {
133 fn from(error: ReflectError) -> Self {
134 DessertError::Reflect { error, span: None }
135 }
136}
137
138pub fn set_string_value<'input, const BORROW: bool>(
147 mut wip: Partial<'input, BORROW>,
148 s: Cow<'input, str>,
149 span: Option<Span>,
150) -> Result<Partial<'input, BORROW>, DessertError> {
151 let shape = wip.shape();
152
153 if matches!(&shape.def, Def::Option(_)) {
154 wip = wip.begin_some()?;
155 wip = set_string_value(wip, s, span)?;
156 wip = wip.end()?;
157 return Ok(wip);
158 }
159
160 if shape.vtable.has_parse() {
161 wip = wip.parse_from_str(s.as_ref())?;
162 return Ok(wip);
163 }
164
165 if let Type::User(UserType::Enum(enum_def)) = &shape.ty {
167 if shape.is_numeric()
169 && let Ok(discriminant) = s.parse::<i64>()
170 {
171 wip = wip.select_variant(discriminant)?;
172 return Ok(wip);
173 }
174 if let Some((_, variant)) = enum_def
178 .variants
179 .iter()
180 .enumerate()
181 .find(|(_, v)| v.effective_name() == s.as_ref())
182 {
183 wip = wip.select_variant_named(variant.effective_name())?;
184 return Ok(wip);
185 }
186
187 return Err(DessertError::Reflect {
189 error: ReflectError::OperationFailed {
190 shape,
191 operation: "no matching enum variant found for string value",
192 },
193 span,
194 });
195 }
196
197 if shape.is_transparent() {
199 wip = wip.begin_nth_field(0)?;
200 wip = set_string_value(wip, s, span)?;
201 wip = wip.end()?;
202 return Ok(wip);
203 }
204
205 set_string_value_inner(wip, s, span)
206}
207
208fn set_string_value_inner<'input, const BORROW: bool>(
209 mut wip: Partial<'input, BORROW>,
210 s: Cow<'input, str>,
211 span: Option<Span>,
212) -> Result<Partial<'input, BORROW>, DessertError> {
213 let shape = wip.shape();
214
215 let reflect_err = |e: ReflectError| DessertError::Reflect { error: e, span };
216
217 if let Def::Pointer(ptr_def) = shape.def
218 && matches!(ptr_def.known, Some(KnownPointer::SharedReference))
219 && ptr_def
220 .pointee()
221 .is_some_and(|p| p.type_identifier == "str")
222 {
223 if !BORROW {
224 return Err(DessertError::CannotBorrow {
225 message: "cannot deserialize into &str when borrowing is disabled - use String or Cow<str> instead".into(),
226 });
227 }
228 match s {
229 Cow::Borrowed(borrowed) => {
230 wip = wip.set(borrowed).map_err(&reflect_err)?;
231 return Ok(wip);
232 }
233 Cow::Owned(_) => {
234 return Err(DessertError::CannotBorrow {
235 message: "cannot borrow &str from string containing escape sequences - use String or Cow<str> instead".into(),
236 });
237 }
238 }
239 }
240
241 if let Def::Pointer(ptr_def) = shape.def
242 && matches!(ptr_def.known, Some(KnownPointer::Cow))
243 && ptr_def
244 .pointee()
245 .is_some_and(|p| p.type_identifier == "str")
246 {
247 wip = wip.set(s).map_err(&reflect_err)?;
248 return Ok(wip);
249 }
250
251 if let Def::Pointer(ptr_def) = shape.def
253 && matches!(
254 ptr_def.known,
255 Some(KnownPointer::Arc | KnownPointer::Box | KnownPointer::Rc)
256 )
257 && ptr_def
258 .pointee()
259 .is_some_and(|p| p.type_identifier == "str")
260 {
261 wip = wip.begin_smart_ptr().map_err(&reflect_err)?;
262 wip = wip.set(s.into_owned()).map_err(&reflect_err)?;
263 wip = wip.end().map_err(&reflect_err)?;
264 return Ok(wip);
265 }
266
267 wip = wip.set(s.into_owned()).map_err(&reflect_err)?;
268 Ok(wip)
269}
270
271pub fn set_bytes_value<'input, const BORROW: bool>(
276 mut wip: Partial<'input, BORROW>,
277 b: Cow<'input, [u8]>,
278 span: Option<Span>,
279) -> Result<Partial<'input, BORROW>, DessertError> {
280 let shape = wip.shape();
281
282 let reflect_err = |e: ReflectError| DessertError::Reflect { error: e, span };
283
284 let is_byte_slice = |pointee: &facet_core::Shape| matches!(pointee.def, Def::Slice(slice_def) if slice_def.t.type_identifier == "u8");
285
286 if let Def::Pointer(ptr_def) = shape.def
287 && matches!(ptr_def.known, Some(KnownPointer::SharedReference))
288 && ptr_def.pointee().is_some_and(is_byte_slice)
289 {
290 if !BORROW {
291 return Err(DessertError::CannotBorrow {
292 message: "cannot deserialize into &[u8] when borrowing is disabled - use Vec<u8> or Cow<[u8]> instead".into(),
293 });
294 }
295 match b {
296 Cow::Borrowed(borrowed) => {
297 wip = wip.set(borrowed).map_err(&reflect_err)?;
298 return Ok(wip);
299 }
300 Cow::Owned(_) => {
301 return Err(DessertError::CannotBorrow {
302 message:
303 "cannot borrow &[u8] from owned bytes - use Vec<u8> or Cow<[u8]> instead"
304 .into(),
305 });
306 }
307 }
308 }
309
310 if let Def::Pointer(ptr_def) = shape.def
311 && matches!(ptr_def.known, Some(KnownPointer::Cow))
312 && ptr_def.pointee().is_some_and(is_byte_slice)
313 {
314 wip = wip.set(b).map_err(&reflect_err)?;
315 return Ok(wip);
316 }
317
318 wip = wip.set(b.into_owned()).map_err(&reflect_err)?;
319 Ok(wip)
320}