1use core::fmt;
4
5use crate::{
6 Def, Facet, HashProxy, KnownPointer, OxPtrConst, OxPtrMut, PointerDef, PointerFlags,
7 PointerType, PointerVTable, PtrConst, Shape, ShapeBuilder, Type, TypeNameOpts, TypeOpsIndirect,
8 TypeParam, VTableIndirect, ValuePointerType,
9};
10
11fn ref_type_name(
13 shape: &'static Shape,
14 f: &mut fmt::Formatter<'_>,
15 opts: TypeNameOpts,
16) -> fmt::Result {
17 let pointee = match &shape.def {
18 Def::Pointer(ptr_def) => ptr_def.pointee,
19 _ => None,
20 };
21
22 write!(f, "&")?;
23 if let Some(pointee) = pointee {
24 if let Some(opts) = opts.for_children() {
25 pointee.write_type_name(f, opts)?;
26 } else {
27 write!(f, "…")?;
28 }
29 } else {
30 write!(f, "?")?;
31 }
32 Ok(())
33}
34
35fn ref_mut_type_name(
37 shape: &'static Shape,
38 f: &mut fmt::Formatter<'_>,
39 opts: TypeNameOpts,
40) -> fmt::Result {
41 let pointee = match &shape.def {
42 Def::Pointer(ptr_def) => ptr_def.pointee,
43 _ => None,
44 };
45
46 write!(f, "&mut ")?;
47 if let Some(pointee) = pointee {
48 if let Some(opts) = opts.for_children() {
49 pointee.write_type_name(f, opts)?;
50 } else {
51 write!(f, "…")?;
52 }
53 } else {
54 write!(f, "?")?;
55 }
56 Ok(())
57}
58
59unsafe fn deref_to_pointee(ox: OxPtrConst) -> Option<(&'static Shape, PtrConst)> {
66 let shape = ox.shape();
67 let Def::Pointer(ptr_def) = shape.def else {
68 return None;
69 };
70 let pointee_shape = ptr_def.pointee?;
71
72 let ref_size = shape.layout.sized_layout().ok()?.size();
83
84 if ref_size == core::mem::size_of::<*const ()>() {
85 let inner_ptr = unsafe { *(ox.ptr().as_byte_ptr() as *const *const u8) };
87 Some((pointee_shape, PtrConst::new(inner_ptr as *const ())))
88 } else {
89 let fat_ptr_location = ox.ptr().as_byte_ptr() as *const [*const u8; 2];
98 let [data_ptr, metadata] = unsafe { *fat_ptr_location };
99
100 Some((
102 pointee_shape,
103 PtrConst::new_wide(data_ptr, metadata as *const ()),
104 ))
105 }
106}
107
108unsafe fn ref_debug(ox: OxPtrConst, f: &mut core::fmt::Formatter<'_>) -> Option<core::fmt::Result> {
110 let (pointee_shape, inner) = unsafe { deref_to_pointee(ox)? };
111 unsafe { pointee_shape.call_debug(inner, f) }
112}
113
114unsafe fn ref_display(
116 ox: OxPtrConst,
117 f: &mut core::fmt::Formatter<'_>,
118) -> Option<core::fmt::Result> {
119 let (pointee_shape, inner) = unsafe { deref_to_pointee(ox)? };
120 unsafe { pointee_shape.call_display(inner, f) }
121}
122
123unsafe fn ref_hash(ox: OxPtrConst, hasher: &mut HashProxy<'_>) -> Option<()> {
125 let (pointee_shape, inner) = unsafe { deref_to_pointee(ox)? };
126 unsafe { pointee_shape.call_hash(inner, hasher) }
127}
128
129unsafe fn ref_partial_eq(a: OxPtrConst, b: OxPtrConst) -> Option<bool> {
131 let (pointee_shape, a_inner) = unsafe { deref_to_pointee(a)? };
132 let (_, b_inner) = unsafe { deref_to_pointee(b)? };
133 unsafe { pointee_shape.call_partial_eq(a_inner, b_inner) }
134}
135
136unsafe fn ref_partial_cmp(a: OxPtrConst, b: OxPtrConst) -> Option<Option<core::cmp::Ordering>> {
138 let (pointee_shape, a_inner) = unsafe { deref_to_pointee(a)? };
139 let (_, b_inner) = unsafe { deref_to_pointee(b)? };
140 unsafe { pointee_shape.call_partial_cmp(a_inner, b_inner) }
141}
142
143unsafe fn ref_cmp(a: OxPtrConst, b: OxPtrConst) -> Option<core::cmp::Ordering> {
145 let (pointee_shape, a_inner) = unsafe { deref_to_pointee(a)? };
146 let (_, b_inner) = unsafe { deref_to_pointee(b)? };
147 unsafe { pointee_shape.call_cmp(a_inner, b_inner) }
148}
149
150unsafe fn ref_drop(_ptr: OxPtrMut) {
152 }
154
155unsafe fn ref_clone(src: OxPtrConst, dst: OxPtrMut) {
157 let Some(size) = src.shape().layout.sized_layout().ok().map(|l| l.size()) else {
159 return;
160 };
161 unsafe {
162 core::ptr::copy_nonoverlapping(src.ptr().as_byte_ptr(), dst.ptr().as_mut_byte_ptr(), size);
163 }
164}
165
166const REF_VTABLE: VTableIndirect = VTableIndirect {
168 display: Some(ref_display),
169 debug: Some(ref_debug),
170 hash: Some(ref_hash),
171 invariants: None,
172 parse: None,
173 parse_bytes: None,
174 try_from: None,
175 try_into_inner: None,
176 try_borrow_inner: None,
177 partial_eq: Some(ref_partial_eq),
178 partial_cmp: Some(ref_partial_cmp),
179 cmp: Some(ref_cmp),
180};
181
182static REF_TYPE_OPS: TypeOpsIndirect = TypeOpsIndirect {
184 drop_in_place: ref_drop,
185 default_in_place: None,
186 clone_into: Some(ref_clone),
187 is_truthy: None,
188};
189
190const REF_MUT_VTABLE: VTableIndirect = VTableIndirect {
192 display: Some(ref_display),
193 debug: Some(ref_debug),
194 hash: Some(ref_hash),
195 invariants: None,
196 parse: None,
197 parse_bytes: None,
198 try_from: None,
199 try_into_inner: None,
200 try_borrow_inner: None,
201 partial_eq: Some(ref_partial_eq),
202 partial_cmp: Some(ref_partial_cmp),
203 cmp: Some(ref_cmp),
204};
205
206static REF_MUT_TYPE_OPS: TypeOpsIndirect = TypeOpsIndirect {
208 drop_in_place: ref_drop,
209 default_in_place: None,
210 clone_into: None,
211 is_truthy: None,
212};
213
214unsafe fn ref_borrow<T: ?Sized>(this: PtrConst) -> PtrConst {
216 let ptr: &&T = unsafe { this.get::<&T>() };
217 let ptr: &T = ptr;
218 PtrConst::new(ptr as *const T)
220}
221
222unsafe fn ref_mut_borrow<T: ?Sized>(this: PtrConst) -> PtrConst {
224 let ptr: &&mut T = unsafe { this.get::<&mut T>() };
225 let ptr: &T = ptr;
226 PtrConst::new(ptr as *const T)
228}
229
230unsafe impl<'a, T: ?Sized + Facet<'a>> Facet<'a> for &'a T {
231 const SHAPE: &'static Shape = &const {
232 const fn build_pointer_vtable<T: ?Sized>() -> PointerVTable {
233 PointerVTable {
234 borrow_fn: Some(ref_borrow::<T>),
235 ..PointerVTable::new()
236 }
237 }
238
239 ShapeBuilder::for_sized::<&T>("&T")
240 .type_name(ref_type_name)
241 .ty({
242 let vpt = ValuePointerType {
243 mutable: false,
244 wide: size_of::<*const T>() != size_of::<*const ()>(),
245 target: T::SHAPE,
246 };
247 Type::Pointer(PointerType::Reference(vpt))
248 })
249 .def(Def::Pointer(PointerDef {
250 vtable: &const { build_pointer_vtable::<T>() },
251 pointee: Some(T::SHAPE),
252 weak: None,
253 strong: None,
254 flags: PointerFlags::EMPTY,
255 known: Some(KnownPointer::SharedReference),
256 }))
257 .type_params(&[TypeParam {
258 name: "T",
259 shape: T::SHAPE,
260 }])
261 .inner(T::SHAPE)
262 .vtable_indirect(&REF_VTABLE)
263 .type_ops_indirect(&REF_TYPE_OPS)
264 .build()
265 };
266}
267
268unsafe impl<'a, T: ?Sized + Facet<'a>> Facet<'a> for &'a mut T {
269 const SHAPE: &'static Shape = &const {
270 const fn build_pointer_vtable<T: ?Sized>() -> PointerVTable {
271 PointerVTable {
272 borrow_fn: Some(ref_mut_borrow::<T>),
273 ..PointerVTable::new()
274 }
275 }
276
277 ShapeBuilder::for_sized::<&mut T>("&mut T")
278 .type_name(ref_mut_type_name)
279 .ty({
280 let vpt = ValuePointerType {
281 mutable: true,
282 wide: size_of::<*const T>() != size_of::<*const ()>(),
283 target: T::SHAPE,
284 };
285 Type::Pointer(PointerType::Reference(vpt))
286 })
287 .def(Def::Pointer(PointerDef {
288 vtable: &const { build_pointer_vtable::<T>() },
289 pointee: Some(T::SHAPE),
290 weak: None,
291 strong: None,
292 flags: PointerFlags::EMPTY,
293 known: Some(KnownPointer::ExclusiveReference),
294 }))
295 .type_params(&[TypeParam {
296 name: "T",
297 shape: T::SHAPE,
298 }])
299 .inner(T::SHAPE)
300 .vtable_indirect(&REF_MUT_VTABLE)
301 .type_ops_indirect(&REF_MUT_TYPE_OPS)
302 .build()
303 };
304}