facet_core/impls_alloc/
string.rs

1use crate::{Def, Facet, Shape, Type, UserType, value_vtable};
2use alloc::string::ToString;
3
4#[cfg(feature = "alloc")]
5unsafe impl Facet<'_> for alloc::string::String {
6    const SHAPE: &'static Shape = &const {
7        Shape::builder_for_sized::<Self>()
8            .vtable({
9                let mut vtable = value_vtable!(alloc::string::String, |f, _opts| write!(
10                    f,
11                    "{}",
12                    Self::SHAPE.type_identifier
13                ));
14
15                let vtable_sized = &mut vtable;
16                vtable_sized.parse = {
17                    Some(|s, target| {
18                        // For String, parsing from a string is just copying the string
19                        Ok(unsafe { target.put(s.to_string()) })
20                    })
21                };
22
23                vtable
24            })
25            .def(Def::Scalar)
26            .type_identifier("String")
27            .ty(Type::User(UserType::Opaque))
28            .build()
29    };
30}
31
32unsafe impl<'a> Facet<'a> for alloc::borrow::Cow<'a, str> {
33    const SHAPE: &'static Shape = &const {
34        Shape::builder_for_sized::<Self>()
35            .vtable({
36                value_vtable!(alloc::borrow::Cow<'_, str>, |f, _opts| write!(
37                    f,
38                    "Cow<'_, str>"
39                ))
40            })
41            .def(Def::Scalar)
42            .type_identifier("Cow")
43            .ty(Type::User(UserType::Opaque))
44            .build()
45    };
46}
47
48#[cfg(test)]
49mod tests {
50    use core::ptr::NonNull;
51
52    use crate::Facet;
53    use crate::ptr::PtrUninit;
54    use alloc::string::String;
55
56    #[test]
57    fn test_string_has_parse() {
58        // Check that String has a parse function in its vtable
59        let shape = String::SHAPE;
60        assert!(
61            shape.vtable.has_parse(),
62            "String should have parse function"
63        );
64    }
65
66    #[test]
67    fn test_string_parse() {
68        // Test that we can parse a string into a String
69        let shape = String::SHAPE;
70        let parse_fn = shape.vtable.parse.unwrap();
71
72        // Allocate memory for the String
73        let layout = shape.layout.sized_layout().unwrap();
74        let ptr = unsafe { alloc::alloc::alloc(layout) };
75        let Some(ptr) = NonNull::new(ptr) else {
76            alloc::alloc::handle_alloc_error(layout)
77        };
78        let uninit = PtrUninit::new(ptr);
79
80        // Parse the string
81        let result = unsafe { parse_fn("hello world", uninit) };
82        assert!(result.is_ok());
83
84        // Get the parsed value
85        let ptr_mut = result.unwrap();
86        let parsed = unsafe { ptr_mut.get::<String>() };
87        assert_eq!(parsed, &String::from("hello world"));
88
89        // Clean up
90        unsafe {
91            ptr_mut.drop_in_place::<String>();
92            alloc::alloc::dealloc(ptr.as_ptr(), layout);
93        }
94    }
95}