From c667b8c195150448b99071cc15fc4d1f0c989fca Mon Sep 17 00:00:00 2001 From: CAD97 Date: Tue, 16 Jun 2020 21:40:52 -0400 Subject: [PATCH] Reintroduce `Into` coercion to builder API --- src/green/builder.rs | 22 ++++++++++-------- src/utils.rs | 54 +++++++++++++++++++++++++++++++++++++++++++- tests/smoke.rs | 6 ++--- 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/src/green/builder.rs b/src/green/builder.rs index 0c8dc8d..fab129b 100644 --- a/src/green/builder.rs +++ b/src/green/builder.rs @@ -92,10 +92,12 @@ impl Builder { /// This checks children for identity equivalence, not structural, /// so it is `O(children.len())` and only caches higher-level nodes /// if the lower-level nodes have also been cached. - pub fn node(&mut self, kind: Kind, children: I) -> Arc + pub fn node(&mut self, kind: Kind, children: I) -> Arc where - I: IntoIterator, Arc>>, - I::IntoIter: ExactSizeIterator + AsRef<[NodeOrToken, Arc>]>, + I: IntoIterator, + I::Item: Into, Arc>>, + I::IntoIter: ExactSizeIterator + AsRef<[R]>, + for<'a> &'a R: Into>, { let hasher = &self.hasher; let children = children.into_iter(); @@ -105,12 +107,12 @@ impl Builder { let state = &mut hasher.build_hasher(); kind.hash(state); for child in children.as_ref() { - match child { + match child.into() { NodeOrToken::Node(node) => { - ptr::hash(&**node as *const Node as *const (), state) + ptr::hash(node as *const Node as *const (), state) } NodeOrToken::Token(token) => { - ptr::hash(&**token as *const Token as *const (), state) + ptr::hash(token as *const Token as *const (), state) } } } @@ -119,16 +121,16 @@ impl Builder { let entry = self.nodes.raw_entry_mut().from_hash(hash, |ThinEqNode(node)| { node.kind() == kind - && node.children().zip(children.as_ref().iter()).all(|pair| match pair { - (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => ptr::eq(&*lhs, &**rhs), - (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => ptr::eq(&*lhs, &**rhs), + && node.children().zip(children.as_ref().iter().map(Into::into)).all(|pair| match pair { + (NodeOrToken::Node(lhs), NodeOrToken::Node(rhs)) => ptr::eq(&*lhs, rhs), + (NodeOrToken::Token(lhs), NodeOrToken::Token(rhs)) => ptr::eq(&*lhs, rhs), _ => false, }) }); let (ThinEqNode(node), ()) = match entry { RawEntryMut::Occupied(entry) => entry.into_key_value(), RawEntryMut::Vacant(entry) => { - let node = Node::new(kind, children.map(pack_node_or_token)); + let node = Node::new(kind, children.map(Into::into).map(pack_node_or_token)); entry.insert_with_hasher(hash, ThinEqNode(node), (), |x| do_hash(hasher, x)) } }; diff --git a/src/utils.rs b/src/utils.rs index 55cfb67..47518cc 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,5 +1,8 @@ use { - crate::prelude::{GreenNode, GreenToken}, + crate::{ + prelude::{GreenNode, GreenToken}, + ArcBorrow, + }, std::{ fmt::{self, Debug}, ops::Deref, @@ -119,3 +122,52 @@ impl From> for NodeOrToken, Arc> { NodeOrToken::Token(this) } } + +impl<'a> From<&'a GreenNode> for NodeOrToken<&'a GreenNode, &'a GreenToken> { + fn from(this: &'a GreenNode) -> Self { + NodeOrToken::Node(this) + } +} + +impl<'a> From<&'a GreenToken> for NodeOrToken<&'a GreenNode, &'a GreenToken> { + fn from(this: &'a GreenToken) -> Self { + NodeOrToken::Token(this) + } +} + +impl<'a> From<&'a NodeOrToken, Arc>> for NodeOrToken<&'a GreenNode, &'a GreenToken> { + fn from(this: &'a NodeOrToken, Arc>) -> Self { + this.as_deref() + } +} + +impl<'a> From<&'a Arc> for NodeOrToken<&'a GreenNode, &'a GreenToken> { + fn from(this: &'a Arc) -> Self { + NodeOrToken::Node(&*this) + } +} + +impl<'a> From<&'a Arc> for NodeOrToken<&'a GreenNode, &'a GreenToken> { + fn from(this: &'a Arc) -> Self { + NodeOrToken::Token(&*this) + } +} + + +impl<'a> From> for NodeOrToken<&'a GreenNode, &'a GreenToken> { + fn from(this: ArcBorrow<'a, GreenNode>) -> Self { + NodeOrToken::Node(ArcBorrow::downgrade(this)) + } +} + +impl<'a> From> for NodeOrToken<&'a GreenNode, &'a GreenToken> { + fn from(this: ArcBorrow<'a, GreenToken>) -> Self { + NodeOrToken::Token(ArcBorrow::downgrade(this)) + } +} + +impl<'a> From, ArcBorrow<'a, GreenToken>>> for NodeOrToken<&'a GreenNode, &'a GreenToken> { + fn from(this: NodeOrToken, ArcBorrow<'a, GreenToken>>) -> Self { + this.map(ArcBorrow::downgrade, ArcBorrow::downgrade) + } +} diff --git a/tests/smoke.rs b/tests/smoke.rs index 9200ba6..785fb13 100644 --- a/tests/smoke.rs +++ b/tests/smoke.rs @@ -108,15 +108,15 @@ fn make_math_tree() { // Invocations of the builder with the same (id) arguments produces the same (id) results assert!(Arc::ptr_eq(&ws, &builder.token(WS, " "))); - // builder.node accepts iterator of NodeOrToken, Arc> so you need to wrap. - // You'll know if you need the bottom-up builder (LR or such). Use TreeBuilder otherwise. + // builder.node accepts iterator of Arc, Arc, or NodeOrToken, Arc> + // so if you're mixing nodes and tokens, you need to include the type changing boilerplate. let n = |node: &Arc| NodeOrToken::from(node.clone()); let t = |token: &Arc| NodeOrToken::from(token.clone()); // Currently, only vec::IntoIter and vec::Drain are able to be used for builder.node, as // building a node requires being able to pre-iterate the children to check the dedup cache. // (Please, const-generic angels, give us `for [_; N]: IntoIterator` soon(ish)!) - let inner_mul = builder.node(EXPR, vec![t(&n2), t(&ws), t(&mul), t(&ws), t(&n3)]); + let inner_mul = builder.node(EXPR, vec![n2, ws.clone(), mul, ws.clone(), n3]); let left_add = builder.node(EXPR, vec![t(&n1), t(&ws), t(&add), t(&ws), n(&inner_mul)]); let right_add = builder.node(EXPR, vec![n(&left_add), t(&ws), t(&add), t(&ws), t(&n4)]);