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, Variance, VarianceDep, VarianceDesc,
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
150const unsafe 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 .decl_id(crate::DeclId::new(crate::decl_id_hash("#ref#&T")))
241 .type_name(ref_type_name)
242 .ty({
243 let vpt = ValuePointerType {
244 mutable: false,
245 wide: size_of::<*const T>() != size_of::<*const ()>(),
246 target: T::SHAPE,
247 };
248 Type::Pointer(PointerType::Reference(vpt))
249 })
250 .def(Def::Pointer(PointerDef {
251 vtable: &const { build_pointer_vtable::<T>() },
252 pointee: Some(T::SHAPE),
253 weak: None,
254 strong: None,
255 flags: PointerFlags::EMPTY,
256 known: Some(KnownPointer::SharedReference),
257 }))
258 .type_params(&[TypeParam {
259 name: "T",
260 shape: T::SHAPE,
261 }])
262 .inner(T::SHAPE)
263 .variance(VarianceDesc {
266 base: Variance::Covariant,
267 deps: &const { [VarianceDep::covariant(T::SHAPE)] },
268 })
269 .vtable_indirect(&REF_VTABLE)
270 .type_ops_indirect(&REF_TYPE_OPS)
271 .build()
272 };
273}
274
275unsafe impl<'a, T: ?Sized + Facet<'a>> Facet<'a> for &'a mut T {
276 const SHAPE: &'static Shape = &const {
277 const fn build_pointer_vtable<T: ?Sized>() -> PointerVTable {
278 PointerVTable {
279 borrow_fn: Some(ref_mut_borrow::<T>),
280 ..PointerVTable::new()
281 }
282 }
283
284 ShapeBuilder::for_sized::<&mut T>("&mut T")
285 .decl_id(crate::DeclId::new(crate::decl_id_hash("#ref#&mut T")))
286 .type_name(ref_mut_type_name)
287 .ty({
288 let vpt = ValuePointerType {
289 mutable: true,
290 wide: size_of::<*const T>() != size_of::<*const ()>(),
291 target: T::SHAPE,
292 };
293 Type::Pointer(PointerType::Reference(vpt))
294 })
295 .def(Def::Pointer(PointerDef {
296 vtable: &const { build_pointer_vtable::<T>() },
297 pointee: Some(T::SHAPE),
298 weak: None,
299 strong: None,
300 flags: PointerFlags::EMPTY,
301 known: Some(KnownPointer::ExclusiveReference),
302 }))
303 .type_params(&[TypeParam {
304 name: "T",
305 shape: T::SHAPE,
306 }])
307 .inner(T::SHAPE)
308 .variance(VarianceDesc {
315 base: Variance::Covariant,
316 deps: &const { [VarianceDep::invariant(T::SHAPE)] },
317 })
318 .vtable_indirect(&REF_MUT_VTABLE)
319 .type_ops_indirect(&REF_MUT_TYPE_OPS)
320 .build()
321 };
322}