refactor(drawing/drawing): Ignore infringees using filter predicate instead of slice

This commit is contained in:
Mikolaj Wielgus 2025-05-03 21:54:10 +02:00 committed by mikolaj
parent cea96b20a0
commit 6175f7aec2
1 changed files with 87 additions and 56 deletions

View File

@ -269,7 +269,11 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
weight: FixedDotWeight, weight: FixedDotWeight,
) -> Result<FixedDotIndex, Infringement> { ) -> Result<FixedDotIndex, Infringement> {
self.add_dot_with_infringables(recorder, weight, Some(&[])) self.add_dot_with_infringement_filtering(
recorder,
weight,
&|_drawing, _infringer, _infringee| true,
)
} }
#[debug_ensures(self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count() - 1))] #[debug_ensures(self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count() - 1))]
@ -291,17 +295,17 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
#[debug_ensures(ret.is_ok() -> self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count() + 1))] #[debug_ensures(ret.is_ok() -> self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count() + 1))]
#[debug_ensures(ret.is_err() -> self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count()))] #[debug_ensures(ret.is_err() -> self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count()))]
fn add_dot_with_infringables<W: AccessDotWeight + Into<PrimitiveWeight> + GetLayer>( fn add_dot_with_infringement_filtering<W: AccessDotWeight + Into<PrimitiveWeight> + GetLayer>(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
weight: W, weight: W,
infringables: Option<&[PrimitiveIndex]>, predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
) -> Result<GenericIndex<W>, Infringement> ) -> Result<GenericIndex<W>, Infringement>
where where
GenericIndex<W>: Into<PrimitiveIndex> + Copy, GenericIndex<W>: Into<PrimitiveIndex> + Copy,
{ {
let dot = self.add_dot_infringably(recorder, weight); let dot = self.add_dot_infringably(recorder, weight);
self.fail_and_remove_if_infringes_except(recorder, dot.into(), infringables)?; self.fail_and_remove_if_infringes_except(recorder, dot.into(), predicate)?;
Ok(dot) Ok(dot)
} }
@ -316,7 +320,13 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
to: FixedDotIndex, to: FixedDotIndex,
weight: FixedSegWeight, weight: FixedSegWeight,
) -> Result<FixedSegIndex, Infringement> { ) -> Result<FixedSegIndex, Infringement> {
self.add_seg_with_infringables(recorder, from.into(), to.into(), weight, Some(&[])) self.add_seg_with_infringables(
recorder,
from.into(),
to.into(),
weight,
&|_drawing, _infringer, _infringee| true,
)
} }
#[debug_ensures(self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count() + 1))] #[debug_ensures(self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count() + 1))]
@ -342,8 +352,13 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
to: FixedDotIndex, to: FixedDotIndex,
weight: LoneLooseSegWeight, weight: LoneLooseSegWeight,
) -> Result<LoneLooseSegIndex, Infringement> { ) -> Result<LoneLooseSegIndex, Infringement> {
let seg = let seg = self.add_seg_with_infringables(
self.add_seg_with_infringables(recorder, from.into(), to.into(), weight, Some(&[]))?; recorder,
from.into(),
to.into(),
weight,
&|_drawing, _infringer, _infringee| true,
)?;
Ok(seg) Ok(seg)
} }
@ -358,7 +373,13 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
to: LooseDotIndex, to: LooseDotIndex,
weight: SeqLooseSegWeight, weight: SeqLooseSegWeight,
) -> Result<SeqLooseSegIndex, Infringement> { ) -> Result<SeqLooseSegIndex, Infringement> {
let seg = self.add_seg_with_infringables(recorder, from, to.into(), weight, Some(&[]))?; let seg = self.add_seg_with_infringables(
recorder,
from,
to.into(),
weight,
&|_drawing, _infringer, _infringee| true,
)?;
Ok(seg) Ok(seg)
} }
@ -372,13 +393,13 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
from: DotIndex, from: DotIndex,
to: DotIndex, to: DotIndex,
weight: W, weight: W,
infringables: Option<&[PrimitiveIndex]>, predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
) -> Result<GenericIndex<W>, Infringement> ) -> Result<GenericIndex<W>, Infringement>
where where
GenericIndex<W>: Into<PrimitiveIndex> + Copy, GenericIndex<W>: Into<PrimitiveIndex> + Copy,
{ {
let seg = self.add_seg_infringably(recorder, from, to, weight); let seg = self.add_seg_infringably(recorder, from, to, weight);
self.fail_and_remove_if_infringes_except(recorder, seg.into(), infringables)?; self.fail_and_remove_if_infringes_except(recorder, seg.into(), predicate)?;
Ok(seg) Ok(seg)
} }
@ -395,7 +416,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
to: LooseDotIndex, to: LooseDotIndex,
around: GearIndex, around: GearIndex,
weight: LooseBendWeight, weight: LooseBendWeight,
infringables: Option<&[PrimitiveIndex]>, predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
) -> Result<LooseBendIndex, DrawingException> { ) -> Result<LooseBendIndex, DrawingException> {
// It makes no sense to wrap something around or under one of its connectables. // It makes no sense to wrap something around or under one of its connectables.
// //
@ -423,7 +444,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
to.into(), to.into(),
core, core,
weight, weight,
infringables, predicate,
) )
.map_err(Into::into), .map_err(Into::into),
GearIndex::FixedBend(around) => self GearIndex::FixedBend(around) => self
@ -433,7 +454,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
to, to,
around.into(), around.into(),
weight, weight,
infringables, predicate,
) )
.map_err(Into::into), .map_err(Into::into),
GearIndex::LooseBend(around) => self GearIndex::LooseBend(around) => self
@ -443,7 +464,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
to, to,
around.into(), around.into(),
weight, weight,
infringables, predicate,
) )
.map_err(Into::into), .map_err(Into::into),
} }
@ -460,7 +481,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
to: DotIndex, to: DotIndex,
core: FixedDotIndex, core: FixedDotIndex,
weight: W, weight: W,
infringables: Option<&[PrimitiveIndex]>, predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
) -> Result<GenericIndex<W>, Infringement> ) -> Result<GenericIndex<W>, Infringement>
where where
GenericIndex<W>: Into<PrimitiveIndex> + Copy, GenericIndex<W>: Into<PrimitiveIndex> + Copy,
@ -469,7 +490,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
self.recording_geometry_with_rtree self.recording_geometry_with_rtree
.add_bend(recorder, from, to, core.into(), weight); .add_bend(recorder, from, to, core.into(), weight);
self.fail_and_remove_if_infringes_except(recorder, bend.into(), infringables)?; self.fail_and_remove_if_infringes_except(recorder, bend.into(), predicate)?;
Ok(bend) Ok(bend)
} }
@ -484,7 +505,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
to: LooseDotIndex, to: LooseDotIndex,
inner: BendIndex, inner: BendIndex,
weight: LooseBendWeight, weight: LooseBendWeight,
infringables: Option<&[PrimitiveIndex]>, predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
) -> Result<GenericIndex<LooseBendWeight>, Infringement> { ) -> Result<GenericIndex<LooseBendWeight>, Infringement> {
let core = *self let core = *self
.recording_geometry_with_rtree .recording_geometry_with_rtree
@ -519,7 +540,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
self.recording_geometry_with_rtree self.recording_geometry_with_rtree
.reattach_bend(recorder, bend.into(), Some(inner)); .reattach_bend(recorder, bend.into(), Some(inner));
self.fail_and_remove_if_infringes_except(recorder, bend.into(), infringables)?; self.fail_and_remove_if_infringes_except(recorder, bend.into(), predicate)?;
Ok(bend) Ok(bend)
} }
@ -562,7 +583,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
sense: RotationSense, sense: RotationSense,
) -> Result<Cane, DrawingException> { ) -> Result<Cane, DrawingException> {
let maybe_next_gear = around.ref_(self).next_gear(); let maybe_next_gear = around.ref_(self).next_gear();
let cane = self.add_cane_with_infringables( let cane = self.add_cane_with_infringement_filtering(
recorder, recorder,
from, from,
around, around,
@ -570,7 +591,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
seg_weight, seg_weight,
bend_weight, bend_weight,
sense, sense,
Some(&[]), &|_drawing, _infringer, _infringee| true,
)?; )?;
if let Some(next_gear) = maybe_next_gear { if let Some(next_gear) = maybe_next_gear {
@ -644,24 +665,26 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
(from, to, offset) (from, to, offset)
}; };
self.move_dot_with_infringables( let rail_outer_bows = self.bend_outer_bows(rail);
self.move_dot_with_infringement_filtering(
recorder, recorder,
joints.0.into(), joints.0.into(),
from.end_point(), from.end_point(),
Some(&self.bend_outer_bows(rail)), &|_drawing, _infringer, infringee| rail_outer_bows.contains(&infringee),
)?; )?;
self.move_dot_with_infringables( self.move_dot_with_infringement_filtering(
recorder, recorder,
joints.1.into(), joints.1.into(),
to.end_point(), to.end_point(),
Some(&self.bend_outer_bows(rail)), &|_drawing, _infringer, infringee| rail_outer_bows.contains(&infringee),
)?; )?;
self.shift_bend_with_infringables( self.shift_bend_with_infringables(
recorder, recorder,
rail.into(), rail.into(),
offset, offset,
Some(&self.bend_outer_bows(rail)), &|_drawing, _infringer, infringee| rail_outer_bows.contains(&infringee),
)?; )?;
// Update offsets in case the rule conditions changed. // Update offsets in case the rule conditions changed.
@ -704,7 +727,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
bend_weight: LooseBendWeight, bend_weight: LooseBendWeight,
sense: RotationSense, sense: RotationSense,
) -> Result<Cane, DrawingException> { ) -> Result<Cane, DrawingException> {
self.add_cane_with_infringables( self.add_cane_with_infringement_filtering(
recorder, recorder,
from, from,
around, around,
@ -712,7 +735,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
seg_weight, seg_weight,
bend_weight, bend_weight,
sense, sense,
Some(&[]), &|_drawing, _infringer, _infringee| true,
) )
} }
@ -720,7 +743,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
#[debug_ensures(ret.is_ok() -> self.recording_geometry_with_rtree.graph().edge_count() >= old(self.recording_geometry_with_rtree.graph().edge_count() + 5))] #[debug_ensures(ret.is_ok() -> self.recording_geometry_with_rtree.graph().edge_count() >= old(self.recording_geometry_with_rtree.graph().edge_count() + 5))]
#[debug_ensures(ret.is_err() -> self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count()))] #[debug_ensures(ret.is_err() -> self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count()))]
#[debug_ensures(ret.is_err() -> self.recording_geometry_with_rtree.graph().edge_count() == old(self.recording_geometry_with_rtree.graph().edge_count()))] #[debug_ensures(ret.is_err() -> self.recording_geometry_with_rtree.graph().edge_count() == old(self.recording_geometry_with_rtree.graph().edge_count()))]
fn add_cane_with_infringables( fn add_cane_with_infringement_filtering(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
from: DotIndex, from: DotIndex,
@ -729,18 +752,18 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
seg_weight: SeqLooseSegWeight, seg_weight: SeqLooseSegWeight,
bend_weight: LooseBendWeight, bend_weight: LooseBendWeight,
sense: RotationSense, sense: RotationSense,
infringables: Option<&[PrimitiveIndex]>, predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
) -> Result<Cane, DrawingException> { ) -> Result<Cane, DrawingException> {
let seg_to = self.add_dot_with_infringables(recorder, dot_weight, infringables)?; let seg_to = self.add_dot_with_infringement_filtering(recorder, dot_weight, predicate)?;
let seg = self let seg = self
.add_seg_with_infringables(recorder, from, seg_to.into(), seg_weight, infringables) .add_seg_with_infringables(recorder, from, seg_to.into(), seg_weight, predicate)
.inspect_err(|_| { .inspect_err(|_| {
self.recording_geometry_with_rtree self.recording_geometry_with_rtree
.remove_dot(recorder, seg_to.into()); .remove_dot(recorder, seg_to.into());
})?; })?;
let to = self let to = self
.add_dot_with_infringables(recorder, dot_weight, infringables) .add_dot_with_infringement_filtering(recorder, dot_weight, predicate)
.inspect_err(|_| { .inspect_err(|_| {
self.recording_geometry_with_rtree self.recording_geometry_with_rtree
.remove_seg(recorder, seg.into()); .remove_seg(recorder, seg.into());
@ -760,7 +783,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
bend_to, bend_to,
around, around,
bend_weight, bend_weight,
infringables, predicate,
) )
.inspect_err(|_| { .inspect_err(|_| {
self.recording_geometry_with_rtree self.recording_geometry_with_rtree
@ -823,19 +846,29 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
to: Point, to: Point,
) -> Result<(), Infringement> { ) -> Result<(), Infringement> {
match dot { match dot {
DotIndex::Fixed(..) => self.move_dot_with_infringables(recorder, dot, to, Some(&[])), DotIndex::Fixed(..) => self.move_dot_with_infringement_filtering(
DotIndex::Loose(..) => self.move_dot_with_infringables(recorder, dot, to, Some(&[])), recorder,
dot,
to,
&|_drawing, _infringer, _infringee| true,
),
DotIndex::Loose(..) => self.move_dot_with_infringement_filtering(
recorder,
dot,
to,
&|_drawing, _infringer, _infringee| true,
),
} }
} }
#[debug_ensures(self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count()))] #[debug_ensures(self.recording_geometry_with_rtree.graph().node_count() == old(self.recording_geometry_with_rtree.graph().node_count()))]
#[debug_ensures(self.recording_geometry_with_rtree.graph().edge_count() == old(self.recording_geometry_with_rtree.graph().edge_count()))] #[debug_ensures(self.recording_geometry_with_rtree.graph().edge_count() == old(self.recording_geometry_with_rtree.graph().edge_count()))]
fn move_dot_with_infringables( fn move_dot_with_infringement_filtering(
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
dot: DotIndex, dot: DotIndex,
to: Point, to: Point,
infringables: Option<&[PrimitiveIndex]>, predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
) -> Result<(), Infringement> { ) -> Result<(), Infringement> {
let old_pos = self let old_pos = self
.recording_geometry_with_rtree .recording_geometry_with_rtree
@ -846,7 +879,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
.move_dot(recorder, dot, to); .move_dot(recorder, dot, to);
for limb in dot.primitive(self).limbs() { for limb in dot.primitive(self).limbs() {
if let Some(infringement) = self.detect_infringement_except(limb, infringables) { if let Some(infringement) = self.detect_infringement_except(limb, predicate) {
// Restore original state. // Restore original state.
self.recording_geometry_with_rtree self.recording_geometry_with_rtree
.move_dot(recorder, dot, old_pos); .move_dot(recorder, dot, old_pos);
@ -854,7 +887,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
} }
} }
if let Some(infringement) = self.detect_infringement_except(dot.into(), infringables) { if let Some(infringement) = self.detect_infringement_except(dot.into(), predicate) {
// Restore original state. // Restore original state.
self.recording_geometry_with_rtree self.recording_geometry_with_rtree
.move_dot(recorder, dot, old_pos); .move_dot(recorder, dot, old_pos);
@ -871,7 +904,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
bend: BendIndex, bend: BendIndex,
offset: f64, offset: f64,
infringables: Option<&[PrimitiveIndex]>, predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
) -> Result<(), Infringement> { ) -> Result<(), Infringement> {
let old_offset = self let old_offset = self
.recording_geometry_with_rtree .recording_geometry_with_rtree
@ -881,7 +914,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
self.recording_geometry_with_rtree self.recording_geometry_with_rtree
.shift_bend(recorder, bend, offset); .shift_bend(recorder, bend, offset);
if let Some(infringement) = self.detect_infringement_except(bend.into(), infringables) { if let Some(infringement) = self.detect_infringement_except(bend.into(), predicate) {
// Restore original state. // Restore original state.
self.recording_geometry_with_rtree self.recording_geometry_with_rtree
.shift_bend(recorder, bend, old_offset); .shift_bend(recorder, bend, old_offset);
@ -980,9 +1013,9 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
&mut self, &mut self,
recorder: &mut DrawingEdit<CW, Cel>, recorder: &mut DrawingEdit<CW, Cel>,
node: PrimitiveIndex, node: PrimitiveIndex,
maybe_except: Option<&[PrimitiveIndex]>, predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
) -> Result<(), Infringement> { ) -> Result<(), Infringement> {
if let Some(infringement) = self.detect_infringement_except(node, maybe_except) { if let Some(infringement) = self.detect_infringement_except(node, predicate) {
if let Ok(dot) = node.try_into() { if let Ok(dot) = node.try_into() {
self.recording_geometry_with_rtree.remove_dot(recorder, dot); self.recording_geometry_with_rtree.remove_dot(recorder, dot);
} else if let Ok(seg) = node.try_into() { } else if let Ok(seg) = node.try_into() {
@ -998,26 +1031,24 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
fn detect_infringement_except( fn detect_infringement_except(
&self, &self,
node: PrimitiveIndex, infringer: PrimitiveIndex,
maybe_except: Option<&[PrimitiveIndex]>, predicate: &impl Fn(&Self, PrimitiveIndex, PrimitiveIndex) -> bool,
) -> Option<Infringement> { ) -> Option<Infringement> {
self.find_infringement( self.find_infringement(
node, infringer,
self.locate_possible_infringers(node) self.locate_possible_infringees(infringer)
.filter_map(|n| { .filter_map(|infringee_node| {
if let GenericNode::Primitive(primitive_node) = n { if let GenericNode::Primitive(primitive_node) = infringee_node {
Some(primitive_node) Some(primitive_node)
} else { } else {
None None
} }
}) })
.filter(|primitive_node| { .filter(|infringee| predicate(&self, infringer, *infringee)),
maybe_except.is_some_and(|except| !except.contains(primitive_node))
}),
) )
} }
fn locate_possible_infringers( fn locate_possible_infringees(
&self, &self,
node: PrimitiveIndex, node: PrimitiveIndex,
) -> impl Iterator<Item = GenericNode<PrimitiveIndex, GenericIndex<CW>>> + '_ { ) -> impl Iterator<Item = GenericNode<PrimitiveIndex, GenericIndex<CW>>> + '_ {
@ -1128,11 +1159,11 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
} }
fn are_connectable(&self, node1: PrimitiveIndex, node2: PrimitiveIndex) -> bool { fn are_connectable(&self, node1: PrimitiveIndex, node2: PrimitiveIndex) -> bool {
if let (Some(node1_net_id), Some(node2_net_id)) = ( if let (Some(node1_net), Some(node2_net)) = (
node1.primitive(self).maybe_net(), node1.primitive(self).maybe_net(),
node2.primitive(self).maybe_net(), node2.primitive(self).maybe_net(),
) { ) {
node1_net_id == node2_net_id node1_net == node2_net
} else { } else {
true true
} }
@ -1153,7 +1184,7 @@ impl<CW: Clone, Cel: Copy, R: AccessRules> Drawing<CW, Cel, R> {
.any(|node| { .any(|node| {
self.find_infringement( self.find_infringement(
node, node,
self.locate_possible_infringers(node) self.locate_possible_infringees(node)
.filter_map(|n| { .filter_map(|n| {
if let GenericNode::Primitive(primitive_node) = n { if let GenericNode::Primitive(primitive_node) = n {
Some(primitive_node) Some(primitive_node)