use super::clojure::{Parent2NodeSetterClojure, ParentProviderClojure}; use crate::BinaryTreeDirection; use crate::NodeRefContainer; use crate::context::{BinaryTreeParentSetterContext, BinaryTreeRootGetter}; use crate::context::BinaryTreeRootSetter; use crate::context::{BinaryTreeChildrenGetterContext, BinaryTreeChildrenSetterContext}; use crate::directed::{ DirectedBinaryTreeChildrenGetterContext, DirectedBinaryTreeChildrenSetterContext, }; use crate::direction::DirectedBinaryTreeDirection; use crate::parent2node::clojure::Parent2NodeGetterClojure; use std::mem::ManuallyDrop; use std::ops::Deref; 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 DynamicParent2NodeGetterClojureFromContext { dir: Option, ctx: CtxRef, node: _NodeOrNothing, } struct DynamicParent2NodeGetterClojureFromDirectedContext { dir: Option, ctx: CtxRef, node: _NodeOrNothing, } macro_rules! _constructor { ($name:ident $direction:ident) => { impl<'ctx, Ctx: NodeRefContainer> $name <&'ctx Ctx, Ctx::NodeRef> { pub fn wrapNode( ctx: &'ctx Ctx, node: Ctx::NodeRef, direction: $direction ) -> Self { return Self { dir: Some(direction), ctx: ctx, node: _NodeOrNothing { node: ManuallyDrop::new(node) } }; } pub fn wrapRoot( ctx: &'ctx Ctx ) -> Self { return Self { dir: None, ctx: ctx, node: _NodeOrNothing { nothing: () } }; } } }; ($name:ident $direction:ident mut) => { impl<'ctx, Ctx: NodeRefContainer> $name <&'ctx mut Ctx, Ctx::NodeRef> { pub fn wrapNode_mut( ctx: &'ctx mut Ctx, node: Ctx::NodeRef, direction: $direction ) -> Self { return Self { dir: Some(direction), ctx: ctx, node: _NodeOrNothing { node: ManuallyDrop::new(node) } }; } pub fn wrapRoot_mut( ctx: &'ctx mut Ctx ) -> Self { return Self { dir: None, ctx: ctx, node: _NodeOrNothing { nothing: () } }; } } }; } _mut_switch!(_constructor!(DynamicParent2NodeGetterClojureFromContext BinaryTreeDirection)); _mut_switch!(_constructor!(DynamicParent2NodeGetterClojureFromDirectedContext 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!(DynamicParent2NodeGetterClojureFromContext)); _mut_switch!(_node_ref!(DynamicParent2NodeGetterClojureFromDirectedContext)); 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) -> Option { match self.dir { None => return self.ctx.getRoot(), Some($dir_enum_lbl::$d1_lbl) => unsafe { self.ctx.$d1_get ((*self.node.node.deref()).clone()) }, Some($dir_enum_lbl::$d2_lbl) => unsafe { self.ctx.$d2_get ((*self.node.node.deref()).clone()) } } } } }; } _mut_switch!(_get_child!( DynamicParent2NodeGetterClojureFromContext BinaryTreeChildrenGetterContext BinaryTreeDirection LEFT getLeftChild RIGHT getRightChild )); _mut_switch!(_get_child!( DynamicParent2NodeGetterClojureFromDirectedContext 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 ) => { impl< 'ctx, Ctx: NodeRefContainer + BinaryTreeRootSetter + $ctx_constraint > Parent2NodeSetterClojure for $name <&'ctx mut Ctx, Ctx::NodeRef> { fn xSetChild(&mut self, newChild: Option) { match self.dir { None => self.ctx.xSetRoot(newChild), Some($dir_enum_lbl::$d1_lbl) => unsafe { self.ctx.$d1_xset ((*self.node.node.deref()).clone(), newChild) }, Some($dir_enum_lbl::$d2_lbl) => unsafe { self.ctx.$d2_xset ((*self.node.node.deref()).clone(), newChild) } }; } fn setChild(&mut self, newChild: Self::NodeRef) { match self.dir { None => self.ctx.setRoot(newChild), Some($dir_enum_lbl::$d1_lbl) => unsafe { self.ctx.$d1_set ((*self.node.node.deref()).clone(), newChild) }, Some($dir_enum_lbl::$d2_lbl) => unsafe { self.ctx.$d2_set ((*self.node.node.deref()).clone(), newChild) } }; } fn clearChild(&mut self) { match self.dir { None => self.ctx.clearRoot(), Some($dir_enum_lbl::$d1_lbl) => unsafe { self.ctx.$d1_clear ((*self.node.node.deref()).clone()) }, Some($dir_enum_lbl::$d2_lbl) => unsafe { self.ctx.$d2_clear ((*self.node.node.deref()).clone()) } }; } } }; } _set_child!( DynamicParent2NodeGetterClojureFromContext BinaryTreeChildrenSetterContext BinaryTreeDirection LEFT xSetLeftChild setLeftChild clearLeftChild RIGHT xSetRightChild setRightChild clearRightChild ); _set_child!( DynamicParent2NodeGetterClojureFromDirectedContext DirectedBinaryTreeChildrenSetterContext DirectedBinaryTreeDirection FORWARD xSetForwardChild setForwardChild clearForwardChild OPPOSITE xSetOppositeChild setOppositeChild clearOppositeChild ); macro_rules! _set_as_parent_of { ($name:ident $dir_enum_lbl:ident $d1_lbl:ident $d2_lbl:ident) => { impl<'ctx, Ctx: BinaryTreeParentSetterContext> ParentProviderClojure for $name<&'ctx mut Ctx, Ctx::NodeRef> { fn setAsParentOf(&mut self, child: Self::NodeRef) { match self.dir { None => self.ctx.clearParent(child), Some($dir_enum_lbl::$d1_lbl) => unsafe { self.ctx.setParent(child, (*self.node.node.deref()).clone()) }, Some($dir_enum_lbl::$d2_lbl) => unsafe { self.ctx.setParent(child, (*self.node.node.deref()).clone()) } }; } } }; } _set_as_parent_of!( DynamicParent2NodeGetterClojureFromContext BinaryTreeDirection LEFT RIGHT ); _set_as_parent_of!( DynamicParent2NodeGetterClojureFromDirectedContext DirectedBinaryTreeDirection FORWARD OPPOSITE ); 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!(DynamicParent2NodeGetterClojureFromContext); _drop!(DynamicParent2NodeGetterClojureFromDirectedContext);