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 try_from: None,
174 try_into_inner: None,
175 try_borrow_inner: None,
176 partial_eq: Some(ref_partial_eq),
177 partial_cmp: Some(ref_partial_cmp),
178 cmp: Some(ref_cmp),
179};
180
181static REF_TYPE_OPS: TypeOpsIndirect = TypeOpsIndirect {
183 drop_in_place: ref_drop,
184 default_in_place: None,
185 clone_into: Some(ref_clone),
186 is_truthy: None,
187};
188
189const REF_MUT_VTABLE: VTableIndirect = VTableIndirect {
191 display: Some(ref_display),
192 debug: Some(ref_debug),
193 hash: Some(ref_hash),
194 invariants: None,
195 parse: None,
196 try_from: None,
197 try_into_inner: None,
198 try_borrow_inner: None,
199 partial_eq: Some(ref_partial_eq),
200 partial_cmp: Some(ref_partial_cmp),
201 cmp: Some(ref_cmp),
202};
203
204static REF_MUT_TYPE_OPS: TypeOpsIndirect = TypeOpsIndirect {
206 drop_in_place: ref_drop,
207 default_in_place: None,
208 clone_into: None,
209 is_truthy: None,
210};
211
212unsafe fn ref_borrow<T: ?Sized>(this: PtrConst) -> PtrConst {
214 let ptr: &&T = unsafe { this.get::<&T>() };
215 let ptr: &T = ptr;
216 PtrConst::new(ptr as *const T)
218}
219
220unsafe fn ref_mut_borrow<T: ?Sized>(this: PtrConst) -> PtrConst {
222 let ptr: &&mut T = unsafe { this.get::<&mut T>() };
223 let ptr: &T = ptr;
224 PtrConst::new(ptr as *const T)
226}
227
228unsafe impl<'a, T: ?Sized + Facet<'a>> Facet<'a> for &'a T {
229 const SHAPE: &'static Shape = &const {
230 const fn build_pointer_vtable<T: ?Sized>() -> PointerVTable {
231 PointerVTable {
232 borrow_fn: Some(ref_borrow::<T>),
233 ..PointerVTable::new()
234 }
235 }
236
237 ShapeBuilder::for_sized::<&T>("&T")
238 .type_name(ref_type_name)
239 .ty({
240 let vpt = ValuePointerType {
241 mutable: false,
242 wide: size_of::<*const T>() != size_of::<*const ()>(),
243 target: T::SHAPE,
244 };
245 Type::Pointer(PointerType::Reference(vpt))
246 })
247 .def(Def::Pointer(PointerDef {
248 vtable: &const { build_pointer_vtable::<T>() },
249 pointee: Some(T::SHAPE),
250 weak: None,
251 strong: None,
252 flags: PointerFlags::EMPTY,
253 known: Some(KnownPointer::SharedReference),
254 }))
255 .type_params(&[TypeParam {
256 name: "T",
257 shape: T::SHAPE,
258 }])
259 .inner(T::SHAPE)
260 .vtable_indirect(&REF_VTABLE)
261 .type_ops_indirect(&REF_TYPE_OPS)
262 .build()
263 };
264}
265
266unsafe impl<'a, T: ?Sized + Facet<'a>> Facet<'a> for &'a mut T {
267 const SHAPE: &'static Shape = &const {
268 const fn build_pointer_vtable<T: ?Sized>() -> PointerVTable {
269 PointerVTable {
270 borrow_fn: Some(ref_mut_borrow::<T>),
271 ..PointerVTable::new()
272 }
273 }
274
275 ShapeBuilder::for_sized::<&mut T>("&mut T")
276 .type_name(ref_mut_type_name)
277 .ty({
278 let vpt = ValuePointerType {
279 mutable: true,
280 wide: size_of::<*const T>() != size_of::<*const ()>(),
281 target: T::SHAPE,
282 };
283 Type::Pointer(PointerType::Reference(vpt))
284 })
285 .def(Def::Pointer(PointerDef {
286 vtable: &const { build_pointer_vtable::<T>() },
287 pointee: Some(T::SHAPE),
288 weak: None,
289 strong: None,
290 flags: PointerFlags::EMPTY,
291 known: Some(KnownPointer::ExclusiveReference),
292 }))
293 .type_params(&[TypeParam {
294 name: "T",
295 shape: T::SHAPE,
296 }])
297 .inner(T::SHAPE)
298 .vtable_indirect(&REF_MUT_VTABLE)
299 .type_ops_indirect(&REF_MUT_TYPE_OPS)
300 .build()
301 };
302}