From 02dcc7f13f8cac4567506614e64df108e604837f Mon Sep 17 00:00:00 2001 From: Andrew Golovashevich Date: Fri, 26 Dec 2025 23:10:49 +0300 Subject: [PATCH] Dynamic wrapper for parent2node clojure --- src/parent2node/dynamic_wrappers.rs | 164 ++++++++++++++++++++++++++++ src/parent2node/mod.rs | 3 +- 2 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 src/parent2node/dynamic_wrappers.rs diff --git a/src/parent2node/dynamic_wrappers.rs b/src/parent2node/dynamic_wrappers.rs new file mode 100644 index 0000000..6649a8f --- /dev/null +++ b/src/parent2node/dynamic_wrappers.rs @@ -0,0 +1,164 @@ +use super::clojure::Parent2NodeSetterClojure; +use crate::BinaryTreeDirection; +use crate::NodeRefContainer; +use crate::context::BinaryTreeRootGetter; +use crate::context::{BinaryTreeChildrenGetterContext, BinaryTreeChildrenSetterContext}; +use crate::directed::{ + DirectedBinaryTreeChildrenGetterContext, DirectedBinaryTreeChildrenSetterContext, +}; +use crate::direction::DirectedBinaryTreeDirection; +use crate::parent2node::clojure::Parent2NodeGetterClojure; +use std::mem::ManuallyDrop; + +macro_rules! _mut_switch { + ($macro:tt $excl_mark:tt ( $($args:tt)+) ) => { + $macro$excl_mark($($args)+); + $macro$excl_mark($($args)+ mut); + }; +} + +union _NodeOrNothing { + nothing: (), + node: ManuallyDrop, +} + +struct dyn_lr { + dir: Option, + ctx: CtxRef, + node: _NodeOrNothing, +} + +struct dyn_dir { + dir: Option, + ctx: CtxRef, + node: _NodeOrNothing, +} + +macro_rules! _constructor { + ($name:ident $direction:ident $($mut:tt)?) => { + impl<'ctx, Ctx: NodeRefContainer> $name <&'ctx $($mut)? Ctx, Ctx::NodeRef> { + pub fn wrap_not_root( + ctx: &'ctx $($mut)? Ctx, node: Ctx::NodeRef, direction: $direction + ) -> Self { + return Self { + dir: Some(direction), + ctx: ctx, + node: _NodeOrNothing { node: ManuallyDrop::new(node) } + }; + } + } + }; +} + +_mut_switch!(_constructor!(dyn_lr BinaryTreeDirection)); +_mut_switch!(_constructor!(dyn_dir DirectedBinaryTreeDirection)); + +macro_rules! _node_ref { + ($name:ident $($mut:tt)?) => { + impl NodeRefContainer for $name<& $($mut)? Ctx, Ctx::NodeRef> { + type NodeRef = Ctx::NodeRef; + } + }; +} + +_mut_switch!(_node_ref!(dyn_lr)); +_mut_switch!(_node_ref!(dyn_dir)); + +macro_rules! _get_child { + ( + $name:ident $ctx_constraint:ident + $dir_enum_lbl:ident $d1_lbl:ident $d1_get:ident $d2_lbl:ident $d2_get:ident + $($mut:tt)? + ) => { + impl< + 'ctx, + Ctx: NodeRefContainer + BinaryTreeRootGetter + $ctx_constraint + > Parent2NodeGetterClojure + for $name <&'ctx $($mut)? Ctx, Ctx::NodeRef> + { + fn getChild(&self) -> Self::NodeRef { + match self.dir { + None => return self.ctx.getRoot(), + Some($dir_enum_lbl::$d1_lbl) => self.ctx.$d1_get (self.ctx.node.node), + Some($dir_enum_lbl::$d2_lbl) => self.ctx.$d2_get (self.ctx.node.node) + } + } + } + }; +} + +_mut_switch!(_get_child!( + dyn_lr BinaryTreeChildrenGetterContext + BinaryTreeDirection LEFT getLeftChild RIGHT getRightChild +)); +_mut_switch!(_get_child!( + dyn_dir DirectedBinaryTreeChildrenGetterContext + DirectedBinaryTreeDirection FORWARD getForwardChild OPPOSITE getOppositeChild +)); + +macro_rules! _set_child { + ( + $name:ident $ctx_constraint:ident $dir_enum_lbl:ident + $d1_lbl:ident $d1_xset:ident $d1_set:ident $d1_clear:ident + $d2_lbl:ident $d2_xset:ident $d2_set:ident $d2_clear:ident + $($mut:tt)? + ) => { + impl< + 'ctx, + Ctx: NodeRefContainer + BinaryTreeRootGetter + $ctx_constraint + > Parent2NodeSetterClojure + for $name <&'ctx $($mut)? Ctx, Ctx::NodeRef> + { + fn xSetChild(&mut self, newChild: Option) { + match self.dir { + None => return self.ctx.xSetRoot(newChild), + Some($dir_enum_lbl::$d1_lbl) => self.ctx.$d1_xset (self.ctx.node.node, newChild), + Some($dir_enum_lbl::$d2_lbl) => self.ctx.$d2_xset (self.ctx.node.node, newChild) + } + } + + fn setChild(&mut self, newChild: Self::NodeRef) { + match self.dir { + None => return self.ctx.setRoot(newChild), + Some($dir_enum_lbl::$d1_lbl) => self.ctx.$d1_set (self.ctx.node.node, newChild), + Some($dir_enum_lbl::$d2_lbl) => self.ctx.$d2_set (self.ctx.node.node, newChild) + } + } + + fn clearChild(&mut self) { + match self.dir { + None => return self.ctx.clearRoot(), + Some($dir_enum_lbl::$d1_lbl) => self.ctx.$d1_clear (self.ctx.node.node), + Some($dir_enum_lbl::$d2_lbl) => self.ctx.$d2_clear (self.ctx.node.node) + } + } + } + }; +} + +_set_child!( + dyn_lr BinaryTreeChildrenSetterContext BinaryTreeDirection + LEFT xSetLeftChild setLeftChild clearLeftChild + RIGHT xSetRightChild setRightChild clearRightChild +); +_set_child!( + dyn_dir DirectedBinaryTreeChildrenSetterContext DirectedBinaryTreeDirection + FORWARD xSetForwardChild setForwardChild clearForwardChild + OPPOSITE xSetOppositeChild setOppositeChild clearOppositeChild +); + +macro_rules! _drop { + ($name:ident $($mut:tt)?) => { + impl Drop for $name { + fn drop(&mut self) { + if matches!(self.dir, Some(_)) { + unsafe { ManuallyDrop::drop(&mut self.node.node) } + } + } + } + }; +} + +_drop!(dyn_lr); +_drop!(dyn_dir); + diff --git a/src/parent2node/mod.rs b/src/parent2node/mod.rs index bf1af10..852c13f 100644 --- a/src/parent2node/mod.rs +++ b/src/parent2node/mod.rs @@ -1,2 +1,3 @@ mod clojure; -mod fixed_wrapper; \ No newline at end of file +mod fixed_wrapper; +mod dynamic_wrappers; \ No newline at end of file