1use core::{cmp::Ordering, marker::PhantomData};
2use facet_core::{Def, Facet, PtrConst, PtrMut, Shape, TypeNameOpts, ValueVTable};
3
4use crate::{ReflectError, ScalarType};
5
6use super::{PeekEnum, PeekList, PeekMap, PeekSmartPointer, PeekStruct};
7
8#[derive(Clone, Copy, PartialEq, Eq, Hash)]
10pub struct ValueId {
11 pub(crate) shape: &'static Shape,
12 pub(crate) ptr: *const u8,
13}
14
15impl ValueId {
16 pub(crate) fn new(shape: &'static Shape, ptr: *const u8) -> Self {
17 Self { shape, ptr }
18 }
19}
20
21impl core::fmt::Display for ValueId {
22 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
23 write!(f, "{}@{:p}", self.shape, self.ptr)
24 }
25}
26
27impl core::fmt::Debug for ValueId {
28 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
29 core::fmt::Display::fmt(self, f)
30 }
31}
32
33#[derive(Clone, Copy)]
35pub struct Peek<'mem, 'facet_lifetime> {
36 pub(crate) data: PtrConst<'mem>,
38
39 pub(crate) shape: &'static Shape,
41
42 invariant: PhantomData<fn(&'facet_lifetime ()) -> &'facet_lifetime ()>,
43}
44
45impl<'mem, 'facet_lifetime> Peek<'mem, 'facet_lifetime> {
46 pub fn new<T: Facet<'facet_lifetime>>(t: &'mem T) -> Self {
48 Self {
49 data: PtrConst::new(t as *const T),
50 shape: T::SHAPE,
51 invariant: PhantomData,
52 }
53 }
54
55 pub unsafe fn unchecked_new(data: PtrConst<'mem>, shape: &'static Shape) -> Self {
63 Self {
64 data,
65 shape,
66 invariant: PhantomData,
67 }
68 }
69
70 #[inline(always)]
72 pub fn vtable(&self) -> &'static ValueVTable {
73 self.shape.vtable
74 }
75
76 pub fn id(&self) -> ValueId {
78 ValueId::new(self.shape, self.data.as_byte_ptr())
79 }
80
81 #[inline]
83 pub fn ptr_eq(&self, other: &Peek<'_, '_>) -> bool {
84 self.data.as_byte_ptr() == other.data.as_byte_ptr()
85 }
86
87 #[inline]
93 pub fn eq(&self, other: &Peek<'_, '_>) -> Option<bool> {
94 unsafe {
95 self.shape
96 .vtable
97 .eq
98 .map(|eq_fn| eq_fn(self.data, other.data))
99 }
100 }
101
102 #[inline]
108 pub fn partial_cmp(&self, other: &Peek<'_, '_>) -> Option<Ordering> {
109 unsafe {
110 self.shape
111 .vtable
112 .partial_ord
113 .and_then(|partial_ord_fn| partial_ord_fn(self.data, other.data))
114 }
115 }
116
117 #[inline(always)]
123 pub fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) -> bool {
124 unsafe {
125 if let Some(hash_fn) = self.shape.vtable.hash {
126 let hasher_opaque = PtrMut::new(hasher);
127 hash_fn(self.data, hasher_opaque, |opaque, bytes| {
128 opaque.as_mut::<H>().write(bytes)
129 });
130 true
131 } else {
132 false
133 }
134 }
135 }
136
137 #[inline(always)]
148 pub fn type_name(
149 &self,
150 f: &mut core::fmt::Formatter<'_>,
151 opts: TypeNameOpts,
152 ) -> core::fmt::Result {
153 (self.shape.vtable.type_name)(f, opts)
154 }
155
156 #[inline(always)]
158 pub const fn shape(&self) -> &'static Shape {
159 self.shape
160 }
161
162 #[inline(always)]
164 pub const fn data(&self) -> PtrConst<'mem> {
165 self.data
166 }
167
168 pub fn scalar_type(&self) -> Option<ScalarType> {
170 ScalarType::try_from_shape(self.shape)
171 }
172
173 pub fn get<T: Facet<'facet_lifetime>>(&self) -> Result<&T, ReflectError> {
179 if self.shape != T::SHAPE {
180 Err(ReflectError::WrongShape {
181 expected: self.shape,
182 actual: T::SHAPE,
183 })
184 } else {
185 Ok(unsafe { self.data.get::<T>() })
186 }
187 }
188
189 pub fn into_struct(self) -> Result<PeekStruct<'mem, 'facet_lifetime>, ReflectError> {
191 if let Def::Struct(def) = self.shape.def {
192 Ok(PeekStruct { value: self, def })
193 } else {
194 Err(ReflectError::WasNotA {
195 expected: "struct",
196 actual: self.shape,
197 })
198 }
199 }
200
201 pub fn into_enum(self) -> Result<PeekEnum<'mem, 'facet_lifetime>, ReflectError> {
203 if let Def::Enum(def) = self.shape.def {
204 Ok(PeekEnum { value: self, def })
205 } else {
206 Err(ReflectError::WasNotA {
207 expected: "enum",
208 actual: self.shape,
209 })
210 }
211 }
212
213 pub fn into_map(self) -> Result<PeekMap<'mem, 'facet_lifetime>, ReflectError> {
215 if let Def::Map(def) = self.shape.def {
216 Ok(PeekMap { value: self, def })
217 } else {
218 Err(ReflectError::WasNotA {
219 expected: "map",
220 actual: self.shape,
221 })
222 }
223 }
224
225 pub fn into_list(self) -> Result<PeekList<'mem, 'facet_lifetime>, ReflectError> {
227 if let Def::List(def) = self.shape.def {
228 Ok(PeekList { value: self, def })
229 } else {
230 Err(ReflectError::WasNotA {
231 expected: "list",
232 actual: self.shape,
233 })
234 }
235 }
236
237 pub fn into_smart_pointer(
239 self,
240 ) -> Result<PeekSmartPointer<'mem, 'facet_lifetime>, ReflectError> {
241 if let Def::SmartPointer(def) = self.shape.def {
242 Ok(PeekSmartPointer { value: self, def })
243 } else {
244 Err(ReflectError::WasNotA {
245 expected: "smart pointer",
246 actual: self.shape,
247 })
248 }
249 }
250
251 pub fn into_option(self) -> Result<super::PeekOption<'mem, 'facet_lifetime>, ReflectError> {
253 if let Def::Option(def) = self.shape.def {
254 Ok(super::PeekOption { value: self, def })
255 } else {
256 Err(ReflectError::WasNotA {
257 expected: "option",
258 actual: self.shape,
259 })
260 }
261 }
262}
263
264impl core::fmt::Display for Peek<'_, '_> {
265 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
266 if let Some(display_fn) = self.vtable().display {
267 unsafe { display_fn(self.data, f) }
268 } else {
269 write!(f, "⟨{}⟩", self.shape)
270 }
271 }
272}
273
274impl core::fmt::Debug for Peek<'_, '_> {
275 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
276 if let Some(debug_fn) = self.vtable().debug {
277 unsafe { debug_fn(self.data, f) }
278 } else {
279 write!(f, "⟨{}⟩", self.shape)
280 }
281 }
282}
283
284impl core::cmp::PartialEq for Peek<'_, '_> {
285 fn eq(&self, other: &Self) -> bool {
286 if self.shape != other.shape {
287 return false;
288 }
289 let eq_fn = match self.shape.vtable.eq {
290 Some(eq_fn) => eq_fn,
291 None => return false,
292 };
293 unsafe { eq_fn(self.data, other.data) }
294 }
295}
296
297impl core::cmp::PartialOrd for Peek<'_, '_> {
298 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
299 if self.shape != other.shape {
300 return None;
301 }
302 let partial_ord_fn = self.shape.vtable.partial_ord?;
303 unsafe { partial_ord_fn(self.data, other.data) }
304 }
305}
306
307impl core::hash::Hash for Peek<'_, '_> {
308 fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
309 if let Some(hash_fn) = self.shape.vtable.hash {
310 let hasher_opaque = PtrMut::new(hasher);
311 unsafe {
312 hash_fn(self.data, hasher_opaque, |opaque, bytes| {
313 opaque.as_mut::<H>().write(bytes)
314 })
315 };
316 } else {
317 panic!("Hashing is not supported for this shape");
318 }
319 }
320}