facet_core/impls/alloc/
string.rs1use crate::{
2 Def, Facet, PtrConst, Shape, ShapeBuilder, Type, TypeOpsDirect, UserType, VTableDirect,
3 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) -> Result<(), alloc::string::String> {
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 Ok(());
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 Ok(());
39 }
40
41 Err(alloc::format!(
42 "cannot convert {} to String",
43 src_shape.type_identifier
44 ))
45}
46
47unsafe impl Facet<'_> for alloc::string::String {
48 const SHAPE: &'static Shape = &const {
50 const VTABLE: VTableDirect = vtable_direct!(alloc::string::String =>
51 FromStr,
52 Display,
53 Debug,
54 Hash,
55 PartialEq,
56 PartialOrd,
57 Ord,
58 [try_from = string_try_from],
59 );
60
61 ShapeBuilder::for_sized::<alloc::string::String>("String")
62 .ty(Type::User(UserType::Opaque))
63 .def(Def::Scalar)
64 .vtable_direct(&VTABLE)
65 .type_ops_direct(&STRING_TYPE_OPS)
66 .eq()
67 .send()
68 .sync()
69 .build()
70 };
71}
72
73#[cfg(test)]
74mod tests {
75 use core::ptr::NonNull;
76
77 use crate::Facet;
78 use alloc::string::String;
79
80 #[test]
81 fn test_string_has_parse() {
82 let shape = String::SHAPE;
84 assert!(
85 shape.vtable.has_parse(),
86 "String should have parse function"
87 );
88 }
89
90 #[test]
91 fn test_string_parse() {
92 let shape = String::SHAPE;
94
95 let layout = shape.layout.sized_layout().unwrap();
97 let ptr = unsafe { alloc::alloc::alloc(layout) };
98 let Some(ptr) = NonNull::new(ptr) else {
99 alloc::alloc::handle_alloc_error(layout)
100 };
101 let ptr_mut = crate::PtrMut::new(ptr.as_ptr());
102
103 let result = unsafe { shape.call_parse("hello world", ptr_mut) };
105 assert!(result.is_some(), "String should have parse function");
106 assert!(result.unwrap().is_ok());
107
108 let parsed = unsafe { ptr_mut.get::<String>() };
110 assert_eq!(parsed, &String::from("hello world"));
111
112 unsafe {
114 shape.call_drop_in_place(ptr_mut).unwrap();
115 alloc::alloc::dealloc(ptr.as_ptr(), layout);
116 }
117 }
118}