use alloc::{collections::BTreeMap, vec::Vec};
mod iset;
mod partial_api;
use crate::{KeyPath, ReflectError, TrackerKind, trace};
use core::marker::PhantomData;
mod heap_value;
pub use heap_value::*;
use facet_core::{
Def, EnumType, Field, PtrUninit, Shape, SliceBuilderVTable, Type, UserType, Variant,
};
use iset::ISet;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum PartialState {
Active,
Built,
}
enum FrameMode {
Strict {
stack: Vec<Frame>,
},
Deferred {
stack: Vec<Frame>,
start_depth: usize,
current_path: KeyPath,
stored_frames: BTreeMap<KeyPath, Frame>,
},
}
impl FrameMode {
const fn stack(&self) -> &Vec<Frame> {
match self {
FrameMode::Strict { stack } | FrameMode::Deferred { stack, .. } => stack,
}
}
const fn stack_mut(&mut self) -> &mut Vec<Frame> {
match self {
FrameMode::Strict { stack } | FrameMode::Deferred { stack, .. } => stack,
}
}
const fn is_deferred(&self) -> bool {
matches!(self, FrameMode::Deferred { .. })
}
const fn start_depth(&self) -> Option<usize> {
match self {
FrameMode::Deferred { start_depth, .. } => Some(*start_depth),
FrameMode::Strict { .. } => None,
}
}
const fn current_path(&self) -> Option<&KeyPath> {
match self {
FrameMode::Deferred { current_path, .. } => Some(current_path),
FrameMode::Strict { .. } => None,
}
}
}
pub struct Partial<'facet, const BORROW: bool = true> {
mode: FrameMode,
state: PartialState,
invariant: PhantomData<fn(&'facet ()) -> &'facet ()>,
}
#[derive(Clone, Copy, Debug)]
pub(crate) enum MapInsertState {
Idle,
PushingKey {
key_ptr: PtrUninit,
key_initialized: bool,
key_frame_on_stack: bool,
},
PushingValue {
key_ptr: PtrUninit,
value_ptr: Option<PtrUninit>,
value_initialized: bool,
value_frame_on_stack: bool,
},
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum FrameOwnership {
Owned,
Field { field_idx: usize },
TrackedBuffer,
BorrowedInPlace,
}
impl FrameOwnership {
const fn needs_dealloc(&self) -> bool {
matches!(self, FrameOwnership::Owned | FrameOwnership::TrackedBuffer)
}
}
pub(crate) struct AllocatedShape {
shape: &'static Shape,
allocated_size: usize,
}
impl AllocatedShape {
pub(crate) const fn new(shape: &'static Shape, allocated_size: usize) -> Self {
Self {
shape,
allocated_size,
}
}
pub(crate) const fn shape(&self) -> &'static Shape {
self.shape
}
pub(crate) const fn allocated_size(&self) -> usize {
self.allocated_size
}
}
#[must_use]
pub(crate) struct Frame {
pub(crate) data: PtrUninit,
pub(crate) allocated: AllocatedShape,
pub(crate) is_init: bool,
pub(crate) tracker: Tracker,
pub(crate) ownership: FrameOwnership,
pub(crate) using_custom_deserialization: bool,
pub(crate) shape_level_proxy: Option<&'static facet_core::ProxyDef>,
}
#[derive(Debug)]
pub(crate) enum Tracker {
Scalar,
Array {
iset: ISet,
current_child: Option<usize>,
},
Struct {
iset: ISet,
current_child: Option<usize>,
},
SmartPointer,
SmartPointerSlice {
vtable: &'static SliceBuilderVTable,
building_item: bool,
},
Enum {
variant: &'static Variant,
data: ISet,
current_child: Option<usize>,
},
List {
current_child: bool,
},
Map {
insert_state: MapInsertState,
},
Set {
current_child: bool,
},
Option {
building_inner: bool,
},
Result {
is_ok: bool,
building_inner: bool,
},
DynamicValue {
state: DynamicValueState,
},
}
#[derive(Debug)]
#[allow(dead_code)] pub(crate) enum DynamicValueState {
Uninit,
Scalar,
Array { building_element: bool },
Object {
insert_state: DynamicObjectInsertState,
},
}
#[derive(Debug)]
#[allow(dead_code)] pub(crate) enum DynamicObjectInsertState {
Idle,
BuildingValue {
key: alloc::string::String,
},
}
impl Tracker {
const fn kind(&self) -> TrackerKind {
match self {
Tracker::Scalar => TrackerKind::Scalar,
Tracker::Array { .. } => TrackerKind::Array,
Tracker::Struct { .. } => TrackerKind::Struct,
Tracker::SmartPointer => TrackerKind::SmartPointer,
Tracker::SmartPointerSlice { .. } => TrackerKind::SmartPointerSlice,
Tracker::Enum { .. } => TrackerKind::Enum,
Tracker::List { .. } => TrackerKind::List,
Tracker::Map { .. } => TrackerKind::Map,
Tracker::Set { .. } => TrackerKind::Set,
Tracker::Option { .. } => TrackerKind::Option,
Tracker::Result { .. } => TrackerKind::Result,
Tracker::DynamicValue { .. } => TrackerKind::DynamicValue,
}
}
const fn set_current_child(&mut self, idx: usize) {
match self {
Tracker::Struct { current_child, .. }
| Tracker::Enum { current_child, .. }
| Tracker::Array { current_child, .. } => {
*current_child = Some(idx);
}
_ => {}
}
}
const fn clear_current_child(&mut self) {
match self {
Tracker::Struct { current_child, .. }
| Tracker::Enum { current_child, .. }
| Tracker::Array { current_child, .. } => {
*current_child = None;
}
_ => {}
}
}
}
impl Frame {
const fn new(data: PtrUninit, allocated: AllocatedShape, ownership: FrameOwnership) -> Self {
let is_init = matches!(
allocated.shape().ty,
Type::User(UserType::Struct(struct_type)) if struct_type.fields.is_empty()
);
Self {
data,
allocated,
is_init,
tracker: Tracker::Scalar,
ownership,
using_custom_deserialization: false,
shape_level_proxy: None,
}
}
fn deinit(&mut self) {
if matches!(self.ownership, FrameOwnership::BorrowedInPlace) {
self.is_init = false;
self.tracker = Tracker::Scalar;
return;
}
match &self.tracker {
Tracker::Scalar => {
if self.is_init {
unsafe {
self.allocated
.shape()
.call_drop_in_place(self.data.assume_init())
};
}
}
Tracker::Array { iset, .. } => {
if let Type::Sequence(facet_core::SequenceType::Array(array_def)) =
self.allocated.shape().ty
{
let element_layout = array_def.t.layout.sized_layout().ok();
if let Some(layout) = element_layout {
for idx in 0..array_def.n {
if iset.get(idx) {
let offset = layout.size() * idx;
let element_ptr = unsafe { self.data.field_init(offset) };
unsafe { array_def.t.call_drop_in_place(element_ptr) };
}
}
}
}
}
Tracker::Struct { iset, .. } => {
if let Type::User(UserType::Struct(struct_type)) = self.allocated.shape().ty {
if iset.all_set(struct_type.fields.len()) {
unsafe {
self.allocated
.shape()
.call_drop_in_place(self.data.assume_init())
};
} else {
for (idx, field) in struct_type.fields.iter().enumerate() {
if iset.get(idx) {
let field_ptr = unsafe { self.data.field_init(field.offset) };
unsafe { field.shape().call_drop_in_place(field_ptr) };
}
}
}
}
}
Tracker::Enum { variant, data, .. } => {
for (idx, field) in variant.data.fields.iter().enumerate() {
if data.get(idx) {
let field_ptr = unsafe { self.data.field_init(field.offset) };
unsafe { field.shape().call_drop_in_place(field_ptr) };
}
}
}
Tracker::SmartPointer => {
if self.is_init {
unsafe {
self.allocated
.shape()
.call_drop_in_place(self.data.assume_init())
};
}
}
Tracker::SmartPointerSlice { vtable, .. } => {
let builder_ptr = unsafe { self.data.assume_init() };
unsafe {
(vtable.free_fn)(builder_ptr);
}
}
Tracker::List { .. } => {
if self.is_init {
unsafe {
self.allocated
.shape()
.call_drop_in_place(self.data.assume_init())
};
}
}
Tracker::Map { insert_state } => {
if self.is_init {
unsafe {
self.allocated
.shape()
.call_drop_in_place(self.data.assume_init())
};
}
match insert_state {
MapInsertState::PushingKey {
key_ptr,
key_initialized,
key_frame_on_stack,
} => {
if !*key_frame_on_stack
&& let Def::Map(map_def) = self.allocated.shape().def
{
if *key_initialized {
unsafe { map_def.k().call_drop_in_place(key_ptr.assume_init()) };
}
if let Ok(key_layout) = map_def.k().layout.sized_layout()
&& key_layout.size() > 0
{
unsafe {
alloc::alloc::dealloc(key_ptr.as_mut_byte_ptr(), key_layout)
};
}
}
}
MapInsertState::PushingValue {
key_ptr,
value_ptr,
value_initialized,
value_frame_on_stack,
} => {
if let Def::Map(map_def) = self.allocated.shape().def {
unsafe { map_def.k().call_drop_in_place(key_ptr.assume_init()) };
if let Ok(key_layout) = map_def.k().layout.sized_layout()
&& key_layout.size() > 0
{
unsafe {
alloc::alloc::dealloc(key_ptr.as_mut_byte_ptr(), key_layout)
};
}
if !*value_frame_on_stack && let Some(value_ptr) = value_ptr {
if *value_initialized {
unsafe {
map_def.v().call_drop_in_place(value_ptr.assume_init())
};
}
if let Ok(value_layout) = map_def.v().layout.sized_layout()
&& value_layout.size() > 0
{
unsafe {
alloc::alloc::dealloc(
value_ptr.as_mut_byte_ptr(),
value_layout,
)
};
}
}
}
}
MapInsertState::Idle => {}
}
}
Tracker::Set { .. } => {
if self.is_init {
unsafe {
self.allocated
.shape()
.call_drop_in_place(self.data.assume_init())
};
}
}
Tracker::Option { building_inner } => {
if !building_inner {
unsafe {
self.allocated
.shape()
.call_drop_in_place(self.data.assume_init())
};
}
}
Tracker::Result { building_inner, .. } => {
if !building_inner {
unsafe {
self.allocated
.shape()
.call_drop_in_place(self.data.assume_init())
};
}
}
Tracker::DynamicValue { .. } => {
if self.is_init {
let result = unsafe {
self.allocated
.shape()
.call_drop_in_place(self.data.assume_init())
};
if result.is_none() {
panic!(
"DynamicValue type {} has no drop_in_place implementation",
self.allocated.shape()
);
}
}
}
}
self.is_init = false;
self.tracker = Tracker::Scalar;
}
fn deinit_for_replace(&mut self) {
if matches!(self.ownership, FrameOwnership::BorrowedInPlace) && self.is_init {
unsafe {
self.allocated
.shape()
.call_drop_in_place(self.data.assume_init());
}
if let Def::DynamicValue(dyn_def) = &self.allocated.shape().def {
unsafe {
(dyn_def.vtable.set_null)(self.data);
}
self.tracker = Tracker::DynamicValue {
state: DynamicValueState::Scalar,
};
return;
}
self.is_init = false;
self.tracker = Tracker::Scalar;
return;
}
self.deinit();
}
const unsafe fn mark_as_init(&mut self) {
self.is_init = true;
}
fn dealloc(self) {
if !self.ownership.needs_dealloc() {
return;
}
if self.is_init {
unreachable!("a frame has to be deinitialized before being deallocated")
}
if self.allocated.allocated_size() > 0 {
if let Ok(layout) = self.allocated.shape().layout.sized_layout() {
let actual_layout = core::alloc::Layout::from_size_align(
self.allocated.allocated_size(),
layout.align(),
)
.expect("allocated_size must be valid");
unsafe { alloc::alloc::dealloc(self.data.as_mut_byte_ptr(), actual_layout) };
}
}
}
fn fill_defaults(&mut self) -> Result<(), ReflectError> {
if !self.is_init
&& matches!(self.tracker, Tracker::Scalar)
&& let Type::User(UserType::Struct(struct_type)) = self.allocated.shape().ty
{
let data_mut = unsafe { self.data.assume_init() };
if unsafe { self.allocated.shape().call_default_in_place(data_mut) }.is_some() {
self.is_init = true;
return Ok(());
}
self.tracker = Tracker::Struct {
iset: ISet::new(struct_type.fields.len()),
current_child: None,
};
}
match &mut self.tracker {
Tracker::Struct { iset, .. } => {
if let Type::User(UserType::Struct(struct_type)) = self.allocated.shape().ty {
let no_fields_set = (0..struct_type.fields.len()).all(|i| !iset.get(i));
if no_fields_set {
let data_mut = unsafe { self.data.assume_init() };
if unsafe { self.allocated.shape().call_default_in_place(data_mut) }
.is_some()
{
self.tracker = Tracker::Scalar;
self.is_init = true;
return Ok(());
}
}
let container_has_default = self.allocated.shape().has_default_attr();
for (idx, field) in struct_type.fields.iter().enumerate() {
if iset.get(idx) {
continue;
}
let field_ptr = unsafe { self.data.field_uninit(field.offset) };
if unsafe {
Self::try_init_field_default(field, field_ptr, container_has_default)
} {
iset.set(idx);
} else if field.has_default() {
return Err(ReflectError::DefaultAttrButNoDefaultImpl {
shape: field.shape(),
});
}
}
}
}
Tracker::Enum { variant, data, .. } => {
let container_has_default = self.allocated.shape().has_default_attr();
for (idx, field) in variant.data.fields.iter().enumerate() {
if data.get(idx) {
continue;
}
let field_ptr = unsafe { self.data.field_uninit(field.offset) };
if unsafe {
Self::try_init_field_default(field, field_ptr, container_has_default)
} {
data.set(idx);
} else if field.has_default() {
return Err(ReflectError::DefaultAttrButNoDefaultImpl {
shape: field.shape(),
});
}
}
}
_ => {}
}
Ok(())
}
unsafe fn try_init_field_default(
field: &Field,
field_ptr: PtrUninit,
container_has_default: bool,
) -> bool {
use facet_core::DefaultSource;
if let Some(default_source) = field.default {
match default_source {
DefaultSource::Custom(default_fn) => {
unsafe { default_fn(field_ptr) };
return true;
}
DefaultSource::FromTrait => {
let field_ptr_mut = unsafe { field_ptr.assume_init() };
if unsafe { field.shape().call_default_in_place(field_ptr_mut) }.is_some() {
return true;
}
}
}
}
if container_has_default {
let field_ptr_mut = unsafe { field_ptr.assume_init() };
if unsafe { field.shape().call_default_in_place(field_ptr_mut) }.is_some() {
return true;
}
}
if matches!(field.shape().def, Def::Option(_)) {
let field_ptr_mut = unsafe { field_ptr.assume_init() };
if unsafe { field.shape().call_default_in_place(field_ptr_mut) }.is_some() {
return true;
}
}
if field.shape().is_type::<()>() {
let field_ptr_mut = unsafe { field_ptr.assume_init() };
if unsafe { field.shape().call_default_in_place(field_ptr_mut) }.is_some() {
return true;
}
}
if matches!(field.shape().def, Def::List(_) | Def::Map(_) | Def::Set(_)) {
let field_ptr_mut = unsafe { field_ptr.assume_init() };
if unsafe { field.shape().call_default_in_place(field_ptr_mut) }.is_some() {
return true;
}
}
false
}
fn require_full_initialization(&self) -> Result<(), ReflectError> {
match &self.tracker {
Tracker::Scalar => {
if self.is_init {
Ok(())
} else {
Err(ReflectError::UninitializedValue {
shape: self.allocated.shape(),
})
}
}
Tracker::Array { iset, .. } => {
match self.allocated.shape().ty {
Type::Sequence(facet_core::SequenceType::Array(array_def)) => {
if (0..array_def.n).all(|idx| iset.get(idx)) {
Ok(())
} else {
Err(ReflectError::UninitializedValue {
shape: self.allocated.shape(),
})
}
}
_ => Err(ReflectError::UninitializedValue {
shape: self.allocated.shape(),
}),
}
}
Tracker::Struct { iset, .. } => {
match self.allocated.shape().ty {
Type::User(UserType::Struct(struct_type)) => {
if iset.all_set(struct_type.fields.len()) {
Ok(())
} else {
let first_missing_idx =
(0..struct_type.fields.len()).find(|&idx| !iset.get(idx));
if let Some(missing_idx) = first_missing_idx {
let field_name = struct_type.fields[missing_idx].name;
Err(ReflectError::UninitializedField {
shape: self.allocated.shape(),
field_name,
})
} else {
Err(ReflectError::UninitializedValue {
shape: self.allocated.shape(),
})
}
}
}
_ => Err(ReflectError::UninitializedValue {
shape: self.allocated.shape(),
}),
}
}
Tracker::Enum { variant, data, .. } => {
let num_fields = variant.data.fields.len();
if num_fields == 0 {
Ok(())
} else if (0..num_fields).all(|idx| data.get(idx)) {
Ok(())
} else {
let first_missing_idx = (0..num_fields).find(|&idx| !data.get(idx));
if let Some(missing_idx) = first_missing_idx {
let field_name = variant.data.fields[missing_idx].name;
Err(ReflectError::UninitializedEnumField {
shape: self.allocated.shape(),
field_name,
variant_name: variant.name,
})
} else {
Err(ReflectError::UninitializedValue {
shape: self.allocated.shape(),
})
}
}
}
Tracker::SmartPointer => {
if self.is_init {
Ok(())
} else {
Err(ReflectError::UninitializedValue {
shape: self.allocated.shape(),
})
}
}
Tracker::SmartPointerSlice { building_item, .. } => {
if *building_item {
Err(ReflectError::UninitializedValue {
shape: self.allocated.shape(),
})
} else {
Ok(())
}
}
Tracker::List { current_child } => {
if self.is_init && !current_child {
Ok(())
} else {
Err(ReflectError::UninitializedValue {
shape: self.allocated.shape(),
})
}
}
Tracker::Map { insert_state } => {
if self.is_init && matches!(insert_state, MapInsertState::Idle) {
Ok(())
} else {
Err(ReflectError::UninitializedValue {
shape: self.allocated.shape(),
})
}
}
Tracker::Set { current_child } => {
if self.is_init && !current_child {
Ok(())
} else {
Err(ReflectError::UninitializedValue {
shape: self.allocated.shape(),
})
}
}
Tracker::Option { building_inner } => {
if *building_inner {
Err(ReflectError::UninitializedValue {
shape: self.allocated.shape(),
})
} else {
Ok(())
}
}
Tracker::Result { building_inner, .. } => {
if *building_inner {
Err(ReflectError::UninitializedValue {
shape: self.allocated.shape(),
})
} else {
Ok(())
}
}
Tracker::DynamicValue { state } => {
if matches!(state, DynamicValueState::Uninit) {
Err(ReflectError::UninitializedValue {
shape: self.allocated.shape(),
})
} else {
Ok(())
}
}
}
}
pub(crate) const fn get_enum_type(&self) -> Result<EnumType, ReflectError> {
match self.allocated.shape().ty {
Type::User(UserType::Enum(e)) => Ok(e),
_ => Err(ReflectError::WasNotA {
expected: "enum",
actual: self.allocated.shape(),
}),
}
}
pub(crate) fn get_field(&self) -> Option<&Field> {
match self.allocated.shape().ty {
Type::User(user_type) => match user_type {
UserType::Struct(struct_type) => {
if let Tracker::Struct {
current_child: Some(idx),
..
} = &self.tracker
{
struct_type.fields.get(*idx)
} else {
None
}
}
UserType::Enum(_enum_type) => {
if let Tracker::Enum {
variant,
current_child: Some(idx),
..
} = &self.tracker
{
variant.data.fields.get(*idx)
} else {
None
}
}
_ => None,
},
_ => None,
}
}
}
impl<'facet, const BORROW: bool> Partial<'facet, BORROW> {
#[inline]
pub(crate) const fn frames(&self) -> &Vec<Frame> {
self.mode.stack()
}
#[inline]
pub(crate) const fn frames_mut(&mut self) -> &mut Vec<Frame> {
self.mode.stack_mut()
}
#[inline]
pub const fn is_deferred(&self) -> bool {
self.mode.is_deferred()
}
#[inline]
pub(crate) const fn start_depth(&self) -> Option<usize> {
self.mode.start_depth()
}
#[inline]
pub(crate) const fn current_path(&self) -> Option<&KeyPath> {
self.mode.current_path()
}
}
impl<'facet, const BORROW: bool> Drop for Partial<'facet, BORROW> {
fn drop(&mut self) {
trace!("🧹 Partial is being dropped");
if let FrameMode::Deferred { stored_frames, .. } = &mut self.mode {
let mut stored_frames = core::mem::take(stored_frames);
let mut paths: Vec<_> = stored_frames.keys().cloned().collect();
paths.sort_by_key(|p| core::cmp::Reverse(p.len()));
for path in paths {
if let Some(mut frame) = stored_frames.remove(&path) {
frame.deinit();
frame.dealloc();
}
}
}
loop {
let stack = self.mode.stack_mut();
if stack.is_empty() {
break;
}
let mut frame = stack.pop().unwrap();
frame.deinit();
frame.dealloc();
}
}
}