#![cfg_attr(not(feature = "std"), no_std)]
#![warn(missing_docs)]
#![warn(clippy::std_instead_of_core)]
#![warn(clippy::std_instead_of_alloc)]
#![doc = include_str!("../README.md")]
#[cfg(not(feature = "alloc"))]
compile_error!("`alloc` feature is required at this time");
extern crate alloc;
use core::alloc::Layout;
pub use facet_peek::*;
use facet_core::{Def, Facet, Opaque, OpaqueUninit, Shape};
mod value;
pub use value::*;
mod list;
pub use list::*;
mod map;
pub use map::*;
mod struct_;
pub use struct_::*;
mod enum_;
pub use enum_::*;
mod option;
pub use option::*;
#[non_exhaustive]
pub enum PokeUninit<'mem> {
Scalar(PokeValueUninit<'mem>),
List(PokeListUninit<'mem>),
Map(PokeMapUninit<'mem>),
Struct(PokeStruct<'mem>),
Enum(PokeEnumNoVariant<'mem>),
Option(PokeOptionUninit<'mem>),
}
pub struct Guard {
ptr: *mut u8,
layout: Layout,
shape: &'static Shape,
}
impl Drop for Guard {
fn drop(&mut self) {
if self.layout.size() == 0 {
return;
}
unsafe { alloc::alloc::dealloc(self.ptr, self.layout) };
}
}
impl<'mem> PokeUninit<'mem> {
pub fn alloc<S: Facet>() -> (Self, Guard) {
let data = S::SHAPE.allocate();
let layout = Layout::new::<S>();
let guard = Guard {
ptr: data.as_mut_bytes(),
layout,
shape: S::SHAPE,
};
let poke = unsafe { Self::unchecked_new(data, S::SHAPE) };
(poke, guard)
}
pub fn alloc_shape(shape: &'static Shape) -> (Self, Guard) {
let data = shape.allocate();
let layout = shape.layout;
let guard = Guard {
ptr: data.as_mut_bytes(),
layout,
shape,
};
let poke = unsafe { Self::unchecked_new(data, shape) };
(poke, guard)
}
pub unsafe fn unchecked_new(data: OpaqueUninit<'mem>, shape: &'static Shape) -> Self {
match shape.def {
Def::Struct(struct_def) => {
PokeUninit::Struct(unsafe { PokeStruct::new(data, shape, struct_def) })
}
Def::Map(map_def) => {
let pmu = unsafe { PokeMapUninit::new(data, shape, map_def) };
PokeUninit::Map(pmu)
}
Def::List(list_def) => {
let plu = unsafe { PokeListUninit::new(data, shape, list_def) };
PokeUninit::List(plu)
}
Def::Scalar { .. } => PokeUninit::Scalar(unsafe { PokeValueUninit::new(data, shape) }),
Def::Enum(enum_def) => {
PokeUninit::Enum(unsafe { PokeEnumNoVariant::new(data, shape, enum_def) })
}
Def::Option(option_def) => {
let pou = unsafe { PokeOptionUninit::new(data, shape, option_def) };
PokeUninit::Option(pou)
}
_ => todo!("unsupported def: {:?}", shape.def),
}
}
pub fn into_struct(self) -> PokeStruct<'mem> {
match self {
PokeUninit::Struct(s) => s,
_ => panic!("expected Struct variant"),
}
}
pub fn into_list(self) -> PokeListUninit<'mem> {
match self {
PokeUninit::List(l) => l,
_ => panic!("expected List variant"),
}
}
pub fn into_map(self) -> PokeMapUninit<'mem> {
match self {
PokeUninit::Map(m) => m,
_ => panic!("expected Map variant"),
}
}
pub fn into_scalar(self) -> PokeValueUninit<'mem> {
match self {
PokeUninit::Scalar(s) => s,
_ => panic!("expected Scalar variant"),
}
}
pub fn into_enum(self) -> PokeEnumNoVariant<'mem> {
match self {
PokeUninit::Enum(e) => e,
_ => panic!("expected Enum variant"),
}
}
pub fn into_option(self) -> PokeOptionUninit<'mem> {
match self {
PokeUninit::Option(o) => o,
_ => panic!("expected Option variant"),
}
}
#[inline(always)]
pub fn into_value(self) -> PokeValueUninit<'mem> {
match self {
PokeUninit::Scalar(s) => s.into_value(),
PokeUninit::List(l) => l.into_value(),
PokeUninit::Map(m) => m.into_value(),
PokeUninit::Struct(s) => s.into_value(),
PokeUninit::Enum(e) => e.into_value(),
PokeUninit::Option(o) => o.into_value(),
}
}
#[inline(always)]
pub fn shape(&self) -> &'static Shape {
match self {
PokeUninit::Scalar(poke_value) => poke_value.shape(),
PokeUninit::List(poke_list_uninit) => poke_list_uninit.shape(),
PokeUninit::Map(poke_map_uninit) => poke_map_uninit.shape(),
PokeUninit::Struct(poke_struct) => poke_struct.shape(),
PokeUninit::Enum(poke_enum_no_variant) => poke_enum_no_variant.shape(),
PokeUninit::Option(poke_option_uninit) => poke_option_uninit.shape(),
}
}
}
#[derive(Clone, Copy, Default)]
pub struct ISet(u64);
impl ISet {
pub fn set(&mut self, index: usize) {
if index >= 64 {
panic!("ISet can only track up to 64 fields. Index {index} is out of bounds.");
}
self.0 |= 1 << index;
}
pub fn unset(&mut self, index: usize) {
if index >= 64 {
panic!("ISet can only track up to 64 fields. Index {index} is out of bounds.");
}
self.0 &= !(1 << index);
}
pub fn has(&self, index: usize) -> bool {
if index >= 64 {
panic!("ISet can only track up to 64 fields. Index {index} is out of bounds.");
}
(self.0 & (1 << index)) != 0
}
pub fn all_set(&self, count: usize) -> bool {
if count > 64 {
panic!("ISet can only track up to 64 fields. Count {count} is out of bounds.");
}
let mask = (1 << count) - 1;
self.0 & mask == mask
}
}
#[non_exhaustive]
pub enum Poke<'mem> {
Scalar(PokeValue<'mem>),
List(PokeList<'mem>),
Map(PokeMap<'mem>),
Struct(PokeStruct<'mem>),
Enum(PokeEnum<'mem>),
Option(PokeOption<'mem>),
}
impl<'mem> Poke<'mem> {
pub unsafe fn unchecked_new(data: Opaque<'mem>, shape: &'static Shape) -> Self {
match shape.def {
Def::Struct(struct_def) => Poke::Struct(unsafe {
let mut ps =
PokeStruct::new(OpaqueUninit::new(data.as_mut_byte_ptr()), shape, struct_def);
for (i, _f) in ps.def().fields.iter().enumerate() {
ps.mark_initialized(i);
}
ps
}),
Def::Map(map_def) => {
let pm = unsafe { PokeMap::new(data, shape, map_def) };
Poke::Map(pm)
}
Def::List(list_def) => {
let pl = unsafe { PokeList::new(data, shape, list_def) };
Poke::List(pl)
}
Def::Scalar { .. } => Poke::Scalar(unsafe { PokeValue::new(data, shape) }),
Def::Enum(_enum_def) => {
todo!("we need to get the active variant somehow")
}
Def::Option(option_def) => {
let po = unsafe { PokeOption::new(data, shape, option_def) };
Poke::Option(po)
}
_ => todo!("unsupported def: {:?}", shape.def),
}
}
#[inline(always)]
pub fn borrow<T: Facet>(data: &'mem mut T) -> Poke<'mem> {
let shape = T::SHAPE;
let data = Opaque::new(data);
unsafe { Poke::unchecked_new(data, shape) }
}
pub fn into_scalar(self) -> PokeValue<'mem> {
match self {
Poke::Scalar(s) => s,
_ => panic!("expected Scalar variant"),
}
}
pub fn into_list(self) -> PokeList<'mem> {
match self {
Poke::List(l) => l,
_ => panic!("expected List variant"),
}
}
pub fn into_map(self) -> PokeMap<'mem> {
match self {
Poke::Map(m) => m,
_ => panic!("expected Map variant"),
}
}
pub fn into_struct(self) -> PokeStruct<'mem> {
match self {
Poke::Struct(s) => s,
_ => panic!("expected Struct variant"),
}
}
pub fn into_enum(self) -> PokeEnum<'mem> {
match self {
Poke::Enum(e) => e,
_ => panic!("expected Enum variant"),
}
}
pub fn into_option(self) -> PokeOption<'mem> {
match self {
Poke::Option(o) => o,
_ => panic!("expected Option variant"),
}
}
#[inline(always)]
pub fn shape(&self) -> &'static Shape {
match self {
Poke::Scalar(poke_value) => poke_value.shape(),
Poke::List(poke_list) => poke_list.shape(),
Poke::Map(poke_map) => poke_map.shape(),
Poke::Struct(poke_struct) => poke_struct.shape(),
Poke::Enum(poke_enum) => poke_enum.shape(),
Poke::Option(poke_option) => poke_option.shape(),
}
}
}