use super::match_result::{
MatchResult, MatchResultMultiple, MatchResultOptional, MatchResultSingle,
};
pub trait SingleSnapProj<Bucket, V>
where
Bucket: MatchResultSingle,
{
fn project<'a, 'd>(&self, snap: &'a mut Bucket::Snapshot<'d>) -> &'a mut Option<&'d V>
where
Bucket: 'd;
}
pub trait MultipleSnapProj<Bucket, V>
where
Bucket: MatchResultMultiple,
{
fn project<'a, 'd>(&self, snap: &'a mut Bucket::Snapshot<'d>) -> &'a mut Vec<&'d V>
where
Bucket: 'd;
}
pub trait OptionalSnapProj<Bucket, V>
where
Bucket: MatchResultOptional,
{
fn project<'a, 'd>(&self, snap: &'a mut Bucket::Snapshot<'d>) -> &'a mut Option<&'d V>
where
Bucket: 'd;
}
#[derive(Clone, Copy)]
pub struct SingleSnapProjAt<const N: usize>;
#[derive(Clone, Copy)]
pub struct MultipleSnapProjAt<const N: usize>;
#[derive(Clone, Copy)]
pub struct OptionalSnapProjAt<const N: usize>;
#[derive(Clone, Copy)]
pub struct BindDebugInfo {
pub property_name: &'static str,
pub file: &'static str,
pub line: u32,
pub column: u32,
}
pub trait Property<Value, MRes>
where
MRes: MatchResult,
{
fn put_in_result(&self, result: &mut MRes, value: Value, debug: Option<BindDebugInfo>);
fn put_ref_in_snapshot<'a>(&self, snapshot: &mut MRes::Snapshot<'a>, value: &'a Value);
fn remove_from_result(&self, result: &mut MRes, debug: Option<BindDebugInfo>);
#[inline]
fn bind_result(&self, value: Value) -> super::bound::BoundValue<Value, Self>
where
Self: Sized,
Self: Clone,
{
super::bound::BoundValue::new(value, self.clone(), None)
}
#[inline]
fn bind_result_with_debug(
&self,
value: Value,
debug: BindDebugInfo,
) -> super::bound::BoundValue<Value, Self>
where
Self: Sized,
Self: Clone,
{
super::bound::BoundValue::new(value, self.clone(), Some(debug))
}
}
#[derive(Clone, Copy)]
pub struct SingleProperty<FDirect, FSnapshot> {
direct_setter: FDirect,
snapshot_setter: FSnapshot,
}
impl<FDirect, FSnapshot> SingleProperty<FDirect, FSnapshot> {
#[inline]
pub fn new(direct_setter: FDirect, snapshot_setter: FSnapshot) -> Self {
Self {
direct_setter,
snapshot_setter,
}
}
}
impl<V, MRes, FDirect, FSnapshot> Property<V, MRes> for SingleProperty<FDirect, FSnapshot>
where
MRes: MatchResult,
FDirect: Fn(&mut MRes::Single) -> &mut Option<V>,
FSnapshot: SingleSnapProj<MRes::Single, V>,
{
#[inline]
fn put_in_result(&self, result: &mut MRes, value: V, debug: Option<BindDebugInfo>) {
let property_slot = (self.direct_setter)(result.single());
if property_slot.is_some() {
if let Some(debug) = debug {
panic!(
"SingleProperty '{}' already set (bind! at {}:{}:{})",
debug.property_name, debug.file, debug.line, debug.column
);
}
panic!("SingleProperty already set");
}
*property_slot = Some(value);
}
#[inline]
fn put_ref_in_snapshot<'a>(&self, snapshot: &mut MRes::Snapshot<'a>, value: &'a V) {
let bucket = MRes::project_single_snapshot_mut(snapshot);
let property_slot = self.snapshot_setter.project(bucket);
if property_slot.is_some() {
panic!("SingleProperty already set in snapshot");
}
*property_slot = Some(value);
}
#[inline]
fn remove_from_result(&self, result: &mut MRes, _debug: Option<BindDebugInfo>) {
let property_slot = (self.direct_setter)(result.single());
if property_slot.is_some() {
*property_slot = None;
} else {
panic!("Trying to remove a value that was not set");
}
}
}
#[derive(Clone, Copy)]
pub struct MultipleProperty<FDirect, FSnapshot> {
direct_setter: FDirect,
snapshot_setter: FSnapshot,
}
impl<FDirect, FSnapshot> MultipleProperty<FDirect, FSnapshot> {
#[inline]
pub fn new(direct_setter: FDirect, snapshot_setter: FSnapshot) -> Self {
Self {
direct_setter,
snapshot_setter,
}
}
}
impl<V, MRes, FDirect, FSnapshot> Property<V, MRes> for MultipleProperty<FDirect, FSnapshot>
where
MRes: MatchResult,
FDirect: Fn(&mut MRes::Multiple) -> &mut Vec<V>,
FSnapshot: MultipleSnapProj<MRes::Multiple, V>,
{
#[inline]
fn put_in_result(&self, result: &mut MRes, value: V, _debug: Option<BindDebugInfo>) {
let property_slot = (self.direct_setter)(result.multiple());
property_slot.push(value);
}
#[inline]
fn put_ref_in_snapshot<'a>(&self, snapshot: &mut MRes::Snapshot<'a>, value: &'a V) {
let bucket = MRes::project_multiple_snapshot_mut(snapshot);
let property_slot = self.snapshot_setter.project(bucket);
property_slot.push(value);
}
#[inline]
fn remove_from_result(&self, result: &mut MRes, _debug: Option<BindDebugInfo>) {
let property_slot = (self.direct_setter)(result.multiple());
if property_slot.pop().is_none() {
panic!("Trying to remove a value that was not set");
}
}
}
#[derive(Clone, Copy)]
pub struct OptionalProperty<FDirect, FSnapshot> {
direct_setter: FDirect,
snapshot_setter: FSnapshot,
}
impl<FDirect, FSnapshot> OptionalProperty<FDirect, FSnapshot> {
#[inline]
pub fn new(direct_setter: FDirect, snapshot_setter: FSnapshot) -> Self {
Self {
direct_setter,
snapshot_setter,
}
}
}
impl<V, MRes, FDirect, FSnapshot> Property<V, MRes> for OptionalProperty<FDirect, FSnapshot>
where
MRes: MatchResult,
FDirect: Fn(&mut MRes::Optional) -> &mut Option<V>,
FSnapshot: OptionalSnapProj<MRes::Optional, V>,
{
#[inline]
fn put_in_result(&self, result: &mut MRes, value: V, debug: Option<BindDebugInfo>) {
let property_slot = (self.direct_setter)(result.optional());
if property_slot.is_some() {
if let Some(debug) = debug {
panic!(
"OptionalProperty '{}' already set (bind! at {}:{}:{})",
debug.property_name, debug.file, debug.line, debug.column
);
}
panic!("OptionalProperty already set");
}
*property_slot = Some(value);
}
#[inline]
fn put_ref_in_snapshot<'a>(&self, snapshot: &mut MRes::Snapshot<'a>, value: &'a V) {
let bucket = MRes::project_optional_snapshot_mut(snapshot);
let property_slot = self.snapshot_setter.project(bucket);
if property_slot.is_some() {
panic!("OptionalProperty already set in snapshot");
}
*property_slot = Some(value);
}
#[inline]
fn remove_from_result(&self, result: &mut MRes, _debug: Option<BindDebugInfo>) {
let property_slot = (self.direct_setter)(result.optional());
if property_slot.is_some() {
*property_slot = None;
} else {
panic!("Trying to remove a value that was not set");
}
}
}