use core::{mem, ops::Deref};
use facet_core::{
Def, Facet, FieldBuilder, Shape, StructKind, TypeOpsDirect, type_ops_direct, vtable_direct,
};
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Span {
pub offset: usize,
pub len: usize,
}
impl Span {
pub const fn new(offset: usize, len: usize) -> Self {
Self { offset, len }
}
pub const fn is_unknown(&self) -> bool {
self.offset == 0 && self.len == 0
}
pub const fn end(&self) -> usize {
self.offset + self.len
}
}
unsafe impl Facet<'_> for Span {
const SHAPE: &'static Shape = &const {
static FIELDS: [facet_core::Field; 2] = [
FieldBuilder::new(
"offset",
facet_core::shape_of::<usize>,
mem::offset_of!(Span, offset),
)
.build(),
FieldBuilder::new(
"len",
facet_core::shape_of::<usize>,
mem::offset_of!(Span, len),
)
.build(),
];
const VTABLE: facet_core::VTableDirect = vtable_direct!(Span => Debug, PartialEq);
const TYPE_OPS: TypeOpsDirect = type_ops_direct!(Span => Default, Clone);
Shape::builder_for_sized::<Span>("Span")
.vtable_direct(&VTABLE)
.type_ops_direct(&TYPE_OPS)
.ty(facet_core::Type::struct_builder(StructKind::Struct, &FIELDS).build())
.def(Def::Undefined)
.build()
};
}
#[derive(Debug)]
pub struct Spanned<T> {
pub value: T,
pub span: Span,
}
impl<T> Spanned<T> {
pub const fn new(value: T, span: Span) -> Self {
Self { value, span }
}
pub const fn span(&self) -> Span {
self.span
}
pub const fn value(&self) -> &T {
&self.value
}
pub fn into_inner(self) -> T {
self.value
}
}
impl<T> Deref for Spanned<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<T: Default> Default for Spanned<T> {
fn default() -> Self {
Self {
value: T::default(),
span: Span::default(),
}
}
}
impl<T: Clone> Clone for Spanned<T> {
fn clone(&self) -> Self {
Self {
value: self.value.clone(),
span: self.span,
}
}
}
impl<T: PartialEq> PartialEq for Spanned<T> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl<T: Eq> Eq for Spanned<T> {}
unsafe impl<'a, T: Facet<'a>> Facet<'a> for Spanned<T> {
const SHAPE: &'static Shape = &const {
use facet_core::{TypeOpsIndirect, TypeParam, VTableIndirect};
unsafe fn drop_in_place<T>(ox: facet_core::OxPtrMut) {
unsafe { core::ptr::drop_in_place(ox.ptr().as_byte_ptr() as *mut Spanned<T>) };
}
Shape::builder_for_sized::<Spanned<T>>("Spanned")
.module_path("facet_reflect::spanned")
.vtable_indirect(&VTableIndirect::EMPTY)
.type_ops_indirect(
&const {
TypeOpsIndirect {
drop_in_place: drop_in_place::<T>,
default_in_place: None,
clone_into: None,
is_truthy: None,
}
},
)
.type_params(
&const {
[TypeParam {
name: "T",
shape: T::SHAPE,
}]
},
)
.ty(facet_core::Type::struct_builder(
StructKind::Struct,
&const {
[
FieldBuilder::new(
"value",
facet_core::shape_of::<T>,
mem::offset_of!(Spanned<T>, value),
)
.build(),
FieldBuilder::new(
"span",
facet_core::shape_of::<Span>,
mem::offset_of!(Spanned<T>, span),
)
.metadata("span")
.build(),
]
},
)
.build())
.def(Def::Undefined)
.type_name(|_shape, f, opts| {
write!(f, "Spanned")?;
if let Some(opts) = opts.for_children() {
write!(f, "<")?;
if let Some(type_name_fn) = T::SHAPE.type_name {
type_name_fn(T::SHAPE, f, opts)?;
} else {
write!(f, "{}", T::SHAPE.type_identifier)?;
}
write!(f, ">")?;
} else {
write!(f, "<…>")?;
}
Ok(())
})
.build()
};
}
pub fn is_spanned_shape(shape: &Shape) -> bool {
use facet_core::{Type, UserType};
if let Type::User(UserType::Struct(struct_def)) = &shape.ty {
let has_span_metadata = struct_def
.fields
.iter()
.any(|f| f.metadata_kind() == Some("span"));
let has_value_field = struct_def.fields.iter().any(|f| !f.is_metadata());
return has_span_metadata && has_value_field;
}
false
}
pub fn find_span_metadata_field(shape: &Shape) -> Option<&'static facet_core::Field> {
use facet_core::{Type, UserType};
if let Type::User(UserType::Struct(struct_def)) = &shape.ty {
return struct_def
.fields
.iter()
.find(|f| f.metadata_kind() == Some("span"));
}
None
}
pub fn get_spanned_inner_shape(shape: &Shape) -> Option<&'static Shape> {
use facet_core::{Type, UserType};
if !is_spanned_shape(shape) {
return None;
}
if let Type::User(UserType::Struct(struct_def)) = &shape.ty {
struct_def
.fields
.iter()
.find(|f| !f.is_metadata())
.map(|f| f.shape.get())
} else {
None
}
}