1use crate::{
2 Def, Facet, KnownPointer, OxPtrConst, OxPtrMut, PointerDef, PointerFlags, PointerVTable,
3 PtrConst, Shape, ShapeBuilder, Type, TypeNameFn, TypeNameOpts, TypeOpsIndirect, TypeParam,
4 UserType, VTableIndirect,
5};
6use alloc::borrow::Cow;
7use alloc::borrow::ToOwned;
8
9unsafe fn cow_debug<T: ?Sized + ToOwned + 'static>(
14 ox: OxPtrConst,
15 f: &mut core::fmt::Formatter<'_>,
16) -> Option<core::fmt::Result>
17where
18 T::Owned: 'static,
19{
20 let cow_ref: &Cow<'_, T> = unsafe { ox.get::<Cow<'static, T>>() };
21
22 let cow_shape = ox.shape();
24 let t_shape = cow_shape.inner?;
25
26 let inner_ref: &T = cow_ref.as_ref();
27
28 let inner_ptr = PtrConst::new(inner_ref as *const T);
29 unsafe { t_shape.call_debug(inner_ptr, f) }
30}
31
32unsafe fn cow_display<T: ?Sized + ToOwned + 'static>(
37 ox: OxPtrConst,
38 f: &mut core::fmt::Formatter<'_>,
39) -> Option<core::fmt::Result>
40where
41 T::Owned: 'static,
42{
43 let cow_ref: &Cow<'_, T> = unsafe { ox.get::<Cow<'static, T>>() };
44
45 let cow_shape = ox.shape();
47 let t_shape = cow_shape.inner?;
48
49 if !t_shape.vtable.has_display() {
50 return None;
51 }
52
53 let inner_ref: &T = cow_ref.as_ref();
54 let inner_ptr = PtrConst::new(inner_ref as *const T);
55
56 unsafe { t_shape.call_display(inner_ptr, f) }
57}
58
59unsafe fn cow_partial_eq<T: ?Sized + ToOwned + 'static>(
64 a: OxPtrConst,
65 b: OxPtrConst,
66) -> Option<bool>
67where
68 T::Owned: 'static,
69{
70 let a_cow_ref: &Cow<'_, T> = unsafe { a.get::<Cow<'static, T>>() };
71 let b_cow_ref: &Cow<'_, T> = unsafe { b.get::<Cow<'static, T>>() };
72
73 let cow_shape = a.shape();
74 let t_shape = cow_shape.inner?;
75
76 let a_inner = PtrConst::new(a_cow_ref.as_ref() as *const T);
77 let b_inner = PtrConst::new(b_cow_ref.as_ref() as *const T);
78
79 unsafe { t_shape.call_partial_eq(a_inner, b_inner) }
80}
81
82unsafe fn cow_partial_cmp<T: ?Sized + ToOwned + 'static>(
87 a: OxPtrConst,
88 b: OxPtrConst,
89) -> Option<Option<core::cmp::Ordering>>
90where
91 T::Owned: 'static,
92{
93 let a_cow_ref: &Cow<'_, T> = unsafe { a.get::<Cow<'static, T>>() };
94 let b_cow_ref: &Cow<'_, T> = unsafe { b.get::<Cow<'static, T>>() };
95
96 let cow_shape = a.shape();
97 let t_shape = cow_shape.inner?;
98
99 let a_inner = PtrConst::new(a_cow_ref.as_ref() as *const T);
100 let b_inner = PtrConst::new(b_cow_ref.as_ref() as *const T);
101
102 unsafe { t_shape.call_partial_cmp(a_inner, b_inner) }
103}
104
105unsafe fn cow_cmp<T: ?Sized + ToOwned + 'static>(
110 a: OxPtrConst,
111 b: OxPtrConst,
112) -> Option<core::cmp::Ordering>
113where
114 T::Owned: 'static,
115{
116 let a_cow_ref: &Cow<'_, T> = unsafe { a.get::<Cow<'static, T>>() };
117 let b_cow_ref: &Cow<'_, T> = unsafe { b.get::<Cow<'static, T>>() };
118
119 let cow_shape = a.shape();
120 let t_shape = cow_shape.inner?;
121
122 let a_inner = PtrConst::new(a_cow_ref.as_ref() as *const T);
123 let b_inner = PtrConst::new(b_cow_ref.as_ref() as *const T);
124
125 unsafe { t_shape.call_cmp(a_inner, b_inner) }
126}
127
128unsafe fn cow_borrow<T: ?Sized + ToOwned + 'static>(this: PtrConst) -> PtrConst
133where
134 T::Owned: 'static,
135{
136 let cow_ref: &Cow<'_, T> =
138 unsafe { &*(this.as_byte_ptr() as *const alloc::borrow::Cow<'_, T>) };
139 let inner_ref: &T = cow_ref.as_ref();
140 PtrConst::new(inner_ref as *const T)
141}
142
143unsafe impl<'a, T> Facet<'a> for Cow<'a, T>
144where
145 T: 'a + ?Sized + ToOwned + 'static,
146 T: Facet<'a>,
147 T::Owned: Facet<'static>,
148{
149 const SHAPE: &'static Shape = &const {
150 const fn build_cow_vtable<T: ?Sized + ToOwned + 'static>() -> VTableIndirect
151 where
152 T::Owned: Facet<'static> + 'static,
153 {
154 VTableIndirect {
155 debug: Some(cow_debug::<T>),
156 display: Some(cow_display::<T>),
157 partial_eq: Some(cow_partial_eq::<T>),
158 partial_cmp: Some(cow_partial_cmp::<T>),
159 cmp: Some(cow_cmp::<T>),
160 ..VTableIndirect::EMPTY
161 }
162 }
163
164 const fn build_cow_type_ops<'facet, T>() -> TypeOpsIndirect
165 where
166 T: ?Sized + ToOwned + 'static + Facet<'facet>,
167 T::Owned: Facet<'static> + 'static,
168 {
169 unsafe fn drop_in_place<T: ?Sized + ToOwned + 'static>(ox: OxPtrMut)
170 where
171 T::Owned: 'static,
172 {
173 unsafe {
174 core::ptr::drop_in_place(
175 ox.ptr().as_ptr::<Cow<'static, T>>() as *mut Cow<'static, T>
176 )
177 };
178 }
179
180 unsafe fn clone_into<T: ?Sized + ToOwned + 'static>(src: OxPtrConst, dst: OxPtrMut)
181 where
182 T::Owned: 'static,
183 {
184 let src_cow_ref: &Cow<'_, T> = unsafe { src.get::<Cow<'static, T>>() };
185 let cloned = src_cow_ref.clone();
186 let out: *mut Cow<'static, T> =
190 unsafe { dst.ptr().as_ptr::<Cow<'static, T>>() as *mut Cow<'static, T> };
191 unsafe { core::ptr::write(out, cloned) };
192 }
193
194 unsafe fn default_in_place<T: ?Sized + ToOwned + 'static>(dst: OxPtrMut)
200 where
201 T::Owned: Facet<'static> + 'static,
202 {
203 let cow_shape = dst.shape();
205 let type_params = cow_shape.type_params;
206 if type_params.len() < 2 {
207 return;
208 }
209
210 let owned_shape = type_params[1].shape;
211
212 let owned_layout = match owned_shape.layout.sized_layout() {
214 Ok(layout) => layout,
215 Err(_) => return,
216 };
217
218 let owned_ptr = unsafe { alloc::alloc::alloc(owned_layout) };
219 if owned_ptr.is_null() {
220 return;
221 }
222
223 let owned_uninit = crate::PtrMut::new(owned_ptr);
224 if unsafe { owned_shape.call_default_in_place(owned_uninit) }.is_none() {
225 unsafe { alloc::alloc::dealloc(owned_ptr, owned_layout) };
227 return;
228 }
229
230 let owned_value: T::Owned =
233 unsafe { core::ptr::read(owned_ptr as *const T::Owned) };
234 unsafe { alloc::alloc::dealloc(owned_ptr, owned_layout) };
235
236 let out: *mut Cow<'static, T> =
239 unsafe { dst.ptr().as_ptr::<Cow<'static, T>>() as *mut Cow<'static, T> };
240 unsafe { core::ptr::write(out, Cow::Owned(owned_value)) };
241 }
242
243 unsafe fn truthy<'facet, T>(ptr: PtrConst) -> bool
244 where
245 T: ?Sized + ToOwned + 'static + Facet<'facet>,
246 T::Owned: Facet<'static> + 'static,
247 {
248 let cow_ref: &Cow<'_, T> = unsafe { ptr.get::<Cow<'static, T>>() };
249 let inner_shape = <T as Facet<'facet>>::SHAPE;
250 if let Some(truthy) = inner_shape.truthiness_fn() {
251 let inner: &T = cow_ref.as_ref();
252 unsafe { truthy(PtrConst::new(inner as *const T)) }
253 } else {
254 false
255 }
256 }
257
258 TypeOpsIndirect {
259 drop_in_place: drop_in_place::<T>,
260 default_in_place: Some(default_in_place::<T>),
261 clone_into: Some(clone_into::<T>),
262 is_truthy: Some(truthy::<'facet, T>),
263 }
264 }
265
266 const fn build_type_name<'a, T: Facet<'a> + ?Sized + ToOwned>() -> TypeNameFn {
267 fn type_name_impl<'a, T: Facet<'a> + ?Sized + ToOwned>(
268 _shape: &'static Shape,
269 f: &mut core::fmt::Formatter<'_>,
270 opts: TypeNameOpts,
271 ) -> core::fmt::Result {
272 write!(f, "Cow")?;
273 if let Some(opts) = opts.for_children() {
274 write!(f, "<")?;
275 T::SHAPE.write_type_name(f, opts)?;
276 write!(f, ">")?;
277 } else {
278 write!(f, "<…>")?;
279 }
280 Ok(())
281 }
282 type_name_impl::<T>
283 }
284
285 ShapeBuilder::for_sized::<Cow<'a, T>>("Cow")
286 .type_name(build_type_name::<T>())
287 .ty(Type::User(UserType::Opaque))
288 .def(Def::Pointer(PointerDef {
289 vtable: &const {
290 PointerVTable {
291 borrow_fn: Some(cow_borrow::<T>),
292 ..PointerVTable::new()
293 }
294 },
295 pointee: Some(T::SHAPE),
296 weak: None,
297 strong: None,
298 flags: PointerFlags::EMPTY,
299 known: Some(KnownPointer::Cow),
300 }))
301 .type_params(&[
302 TypeParam {
303 name: "T",
304 shape: T::SHAPE,
305 },
306 TypeParam {
307 name: "Owned",
308 shape: <T::Owned>::SHAPE,
309 },
310 ])
311 .inner(T::SHAPE)
312 .vtable_indirect(&const { build_cow_vtable::<T>() })
313 .type_ops_indirect(&const { build_cow_type_ops::<'a, T>() })
314 .build()
315 };
316}