facet_core/impls/alloc/
string.rs1use crate::{
2 Def, Facet, PtrConst, Shape, ShapeBuilder, TryFromOutcome, Type, TypeOpsDirect, UserType,
3 VTableDirect, type_ops_direct, vtable_direct,
4};
5
6#[inline(always)]
7unsafe fn string_truthy(value: PtrConst) -> bool {
8 !unsafe { value.get::<alloc::string::String>() }.is_empty()
9}
10
11static STRING_TYPE_OPS: TypeOpsDirect = TypeOpsDirect {
13 is_truthy: Some(string_truthy),
14 ..type_ops_direct!(alloc::string::String => Default, Clone)
15};
16
17unsafe fn string_try_from(
22 dst: *mut alloc::string::String,
23 src_shape: &'static Shape,
24 src: PtrConst,
25) -> TryFromOutcome {
26 if src_shape.id == <&str as crate::Facet>::SHAPE.id {
28 let str_ref: &str = unsafe { src.get::<&str>() };
29 unsafe { dst.write(alloc::string::String::from(str_ref)) };
30 return TryFromOutcome::Converted;
31 }
32
33 if src_shape.id == <alloc::string::String as crate::Facet>::SHAPE.id {
35 let src_string: &alloc::string::String =
36 unsafe { &*(src.as_byte_ptr() as *const alloc::string::String) };
37 unsafe { dst.write(src_string.clone()) };
38 return TryFromOutcome::Converted;
39 }
40
41 TryFromOutcome::Unsupported
42}
43
44unsafe impl Facet<'_> for alloc::string::String {
45 const SHAPE: &'static Shape = &const {
47 const VTABLE: VTableDirect = vtable_direct!(alloc::string::String =>
48 FromStr,
49 Display,
50 Debug,
51 Hash,
52 PartialEq,
53 PartialOrd,
54 Ord,
55 [try_from = string_try_from],
56 );
57
58 ShapeBuilder::for_sized::<alloc::string::String>("String")
59 .module_path("alloc::string")
60 .ty(Type::User(UserType::Opaque))
61 .def(Def::Scalar)
62 .vtable_direct(&VTABLE)
63 .type_ops_direct(&STRING_TYPE_OPS)
64 .eq()
65 .send()
66 .sync()
67 .build()
68 };
69}
70
71#[cfg(test)]
72mod tests {
73 use core::ptr::NonNull;
74
75 use crate::Facet;
76 use alloc::string::String;
77
78 #[test]
79 fn test_string_has_parse() {
80 let shape = String::SHAPE;
82 assert!(
83 shape.vtable.has_parse(),
84 "String should have parse function"
85 );
86 }
87
88 #[test]
89 fn test_string_parse() {
90 let shape = String::SHAPE;
92
93 let layout = shape.layout.sized_layout().unwrap();
95 let ptr = unsafe { alloc::alloc::alloc(layout) };
96 let Some(ptr) = NonNull::new(ptr) else {
97 alloc::alloc::handle_alloc_error(layout)
98 };
99 let ptr_uninit = crate::PtrUninit::new(ptr.as_ptr());
100
101 let result = unsafe { shape.call_parse("hello world", ptr_uninit) };
103 assert!(result.is_some(), "String should have parse function");
104 assert!(result.unwrap().is_ok());
105
106 let ptr_mut = unsafe { ptr_uninit.assume_init() };
108 let parsed = unsafe { ptr_mut.get::<String>() };
109 assert_eq!(parsed, &String::from("hello world"));
110
111 unsafe {
113 shape.call_drop_in_place(ptr_mut).unwrap();
114 alloc::alloc::dealloc(ptr.as_ptr(), layout);
115 }
116 }
117}