-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat!: impl HugrView for any &(mut) to a HugrView #1678
base: main
Are you sure you want to change the base?
Conversation
…grMut ?" This reverts commit 925940be354e0a1294b9d90b8da70778ebcaf867.
This reverts commit 633c5a8112322dda5060ade8dec2e5109f4fdaec.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1678 +/- ##
==========================================
- Coverage 86.34% 86.33% -0.01%
==========================================
Files 166 166
Lines 29747 29762 +15
Branches 26659 26674 +15
==========================================
+ Hits 25684 25694 +10
- Misses 2537 2542 +5
Partials 1526 1526
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
hugr-core/src/hugr/views.rs
Outdated
macro_rules! hugr_view_methods { | ||
() => { | ||
delegate! { | ||
to (**self) { | ||
|
||
#[inline] | ||
fn contains_node(&self, node: Node) -> bool; | ||
|
||
#[inline] | ||
fn node_count(&self) -> usize; | ||
|
||
#[inline] | ||
fn edge_count(&self) -> usize; | ||
|
||
#[inline] | ||
fn nodes(&self) -> impl Iterator<Item = Node> + Clone; | ||
|
||
#[inline] | ||
fn node_ports(&self, node: Node, dir: Direction) -> impl Iterator<Item = Port> + Clone; | ||
|
||
#[inline] | ||
fn all_node_ports(&self, node: Node) -> impl Iterator<Item = Port> + Clone; | ||
|
||
#[inline] | ||
fn linked_ports( | ||
&self, | ||
node: Node, | ||
port: impl Into<Port>, | ||
) -> impl Iterator<Item = (Node, Port)> + Clone; | ||
|
||
#[inline] | ||
fn node_connections(&self, node: Node, other: Node) -> impl Iterator<Item = [Port; 2]> + Clone; | ||
|
||
#[inline] | ||
fn num_ports(&self, node: Node, dir: Direction) -> usize; | ||
|
||
#[inline] | ||
fn children(&self, node: Node) -> impl DoubleEndedIterator<Item = Node> + Clone; | ||
|
||
#[inline] | ||
fn neighbours(&self, node: Node, dir: Direction) -> impl Iterator<Item = Node> + Clone; | ||
|
||
#[inline] | ||
fn all_neighbours(&self, node: Node) -> impl Iterator<Item = Node> + Clone; | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl<T: HugrView> HugrView for &T { | ||
hugr_view_methods! {} | ||
} | ||
|
||
impl<T: HugrView> HugrView for &mut T { | ||
hugr_view_methods! {} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- There's no need to add
inline
s.derive_more
takes care of that already. - We normally single-line the methods when using
derive!
- With the above, I don't think the macro simplifies the code much.
Writing it explicitly avoids the extra layer of indirection.
macro_rules! hugr_view_methods { | |
() => { | |
delegate! { | |
to (**self) { | |
#[inline] | |
fn contains_node(&self, node: Node) -> bool; | |
#[inline] | |
fn node_count(&self) -> usize; | |
#[inline] | |
fn edge_count(&self) -> usize; | |
#[inline] | |
fn nodes(&self) -> impl Iterator<Item = Node> + Clone; | |
#[inline] | |
fn node_ports(&self, node: Node, dir: Direction) -> impl Iterator<Item = Port> + Clone; | |
#[inline] | |
fn all_node_ports(&self, node: Node) -> impl Iterator<Item = Port> + Clone; | |
#[inline] | |
fn linked_ports( | |
&self, | |
node: Node, | |
port: impl Into<Port>, | |
) -> impl Iterator<Item = (Node, Port)> + Clone; | |
#[inline] | |
fn node_connections(&self, node: Node, other: Node) -> impl Iterator<Item = [Port; 2]> + Clone; | |
#[inline] | |
fn num_ports(&self, node: Node, dir: Direction) -> usize; | |
#[inline] | |
fn children(&self, node: Node) -> impl DoubleEndedIterator<Item = Node> + Clone; | |
#[inline] | |
fn neighbours(&self, node: Node, dir: Direction) -> impl Iterator<Item = Node> + Clone; | |
#[inline] | |
fn all_neighbours(&self, node: Node) -> impl Iterator<Item = Node> + Clone; | |
} | |
} | |
} | |
} | |
impl<T: HugrView> HugrView for &T { | |
hugr_view_methods! {} | |
} | |
impl<T: HugrView> HugrView for &mut T { | |
hugr_view_methods! {} | |
} | |
impl<T: HugrView> HugrView for &T { | |
delegate! { | |
to (**self) { | |
fn contains_node(&self, node: Node) -> bool; | |
fn node_count(&self) -> usize; | |
fn edge_count(&self) -> usize; | |
fn nodes(&self) -> impl Iterator<Item = Node> + Clone; | |
fn node_ports(&self, node: Node, dir: Direction) -> impl Iterator<Item = Port> + Clone; | |
fn all_node_ports(&self, node: Node) -> impl Iterator<Item = Port> + Clone; | |
fn linked_ports(&self, node: Node, port: impl Into<Port>) -> impl Iterator<Item = (Node, Port)> + Clone; | |
fn node_connections(&self, node: Node, other: Node) -> impl Iterator<Item = [Port; 2]> + Clone; | |
fn num_ports(&self, node: Node, dir: Direction) -> usize; | |
fn children(&self, node: Node) -> impl DoubleEndedIterator<Item = Node> + Clone; | |
fn neighbours(&self, node: Node, dir: Direction) -> impl Iterator<Item = Node> + Clone; | |
fn all_neighbours(&self, node: Node) -> impl Iterator<Item = Node> + Clone; | |
} | |
} | |
} | |
impl<T: HugrView> HugrView for &mut T { | |
delegate! { | |
to (**self) { | |
fn contains_node(&self, node: Node) -> bool; | |
fn node_count(&self) -> usize; | |
fn edge_count(&self) -> usize; | |
fn nodes(&self) -> impl Iterator<Item = Node> + Clone; | |
fn node_ports(&self, node: Node, dir: Direction) -> impl Iterator<Item = Port> + Clone; | |
fn all_node_ports(&self, node: Node) -> impl Iterator<Item = Port> + Clone; | |
fn linked_ports(&self, node: Node, port: impl Into<Port>) -> impl Iterator<Item = (Node, Port)> + Clone; | |
fn node_connections(&self, node: Node, other: Node) -> impl Iterator<Item = [Port; 2]> + Clone; | |
fn num_ports(&self, node: Node, dir: Direction) -> usize; | |
fn children(&self, node: Node) -> impl DoubleEndedIterator<Item = Node> + Clone; | |
fn neighbours(&self, node: Node, dir: Direction) -> impl Iterator<Item = Node> + Clone; | |
fn all_neighbours(&self, node: Node) -> impl Iterator<Item = Node> + Clone; | |
} | |
} | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- There's no need to add
inline
s.derive_more
takes care of that already.
Sounds good, but how does derive_more
get involved here? I took the [inline]
s from the old impl<T: AsRef<Hugr>> HugrView for T {
...
I've now managed to common up all three of the delegations with the same macro...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, s/derive_more/delegate/g -.-'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah....right. (That makes sense!)
Ok, so if delegate
automatically adds [inline]
....then (a) that shortens the macro :), and (b) yes it does reduce the utility of the macro a bit. OTOH there are now three instances of it, so...we can drop it....but do you really want to? :)
Note the macro is local to hugr::views
, which I think works quite well, but we'd have to put Rc
/ Cow
/ Arc
versions thereof in hugr::views::refs
or something - not a bad place I guess. If we do those as well it'd be 5-6 instances of the macro.... (but they are easy to add, even in this PR)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They should all go on the same hugr::views::impl
files imo, including these.
A file-local macro would be ok there, the file would only contain the same repeated calls.
delegate! { | ||
to self.as_ref() { | ||
#[inline] | ||
fn contains_node(&self, node: Node) -> bool; | ||
|
||
#[inline] | ||
fn node_count(&self) -> usize; | ||
|
||
#[inline] | ||
fn edge_count(&self) -> usize; | ||
|
||
#[inline] | ||
fn nodes(&self) -> impl Iterator<Item = Node> + Clone; | ||
|
||
#[inline] | ||
fn node_ports(&self, node: Node, dir: Direction) -> impl Iterator<Item = Port> + Clone; | ||
|
||
#[inline] | ||
fn all_node_ports(&self, node: Node) -> impl Iterator<Item = Port> + Clone; | ||
|
||
#[inline] | ||
fn linked_ports( | ||
&self, | ||
node: Node, | ||
port: impl Into<Port>, | ||
) -> impl Iterator<Item = (Node, Port)> + Clone; | ||
|
||
#[inline] | ||
fn node_connections(&self, node: Node, other: Node) -> impl Iterator<Item = [Port; 2]> + Clone; | ||
|
||
#[inline] | ||
fn num_ports(&self, node: Node, dir: Direction) -> usize; | ||
|
||
#[inline] | ||
fn children(&self, node: Node) -> impl DoubleEndedIterator<Item = Node> + Clone; | ||
|
||
#[inline] | ||
fn neighbours(&self, node: Node, dir: Direction) -> impl Iterator<Item = Node> + Clone; | ||
|
||
#[inline] | ||
fn all_neighbours(&self, node: Node) -> impl Iterator<Item = Node> + Clone; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delegate! { | |
to self.as_ref() { | |
#[inline] | |
fn contains_node(&self, node: Node) -> bool; | |
#[inline] | |
fn node_count(&self) -> usize; | |
#[inline] | |
fn edge_count(&self) -> usize; | |
#[inline] | |
fn nodes(&self) -> impl Iterator<Item = Node> + Clone; | |
#[inline] | |
fn node_ports(&self, node: Node, dir: Direction) -> impl Iterator<Item = Port> + Clone; | |
#[inline] | |
fn all_node_ports(&self, node: Node) -> impl Iterator<Item = Port> + Clone; | |
#[inline] | |
fn linked_ports( | |
&self, | |
node: Node, | |
port: impl Into<Port>, | |
) -> impl Iterator<Item = (Node, Port)> + Clone; | |
#[inline] | |
fn node_connections(&self, node: Node, other: Node) -> impl Iterator<Item = [Port; 2]> + Clone; | |
#[inline] | |
fn num_ports(&self, node: Node, dir: Direction) -> usize; | |
#[inline] | |
fn children(&self, node: Node) -> impl DoubleEndedIterator<Item = Node> + Clone; | |
#[inline] | |
fn neighbours(&self, node: Node, dir: Direction) -> impl Iterator<Item = Node> + Clone; | |
#[inline] | |
fn all_neighbours(&self, node: Node) -> impl Iterator<Item = Node> + Clone; | |
} | |
} | |
delegate! { | |
to self.as_ref() { | |
fn contains_node(&self, node: Node) -> bool; | |
fn node_count(&self) -> usize; | |
fn edge_count(&self) -> usize; | |
fn nodes(&self) -> impl Iterator<Item = Node> + Clone; | |
fn node_ports(&self, node: Node, dir: Direction) -> impl Iterator<Item = Port> + Clone; | |
fn all_node_ports(&self, node: Node) -> impl Iterator<Item = Port> + Clone; | |
fn linked_ports(&self, node: Node, port: impl Into<Port>) -> impl Iterator<Item = (Node, Port)> + Clone; | |
fn node_connections(&self, node: Node, other: Node) -> impl Iterator<Item = [Port; 2]> + Clone; | |
fn num_ports(&self, node: Node, dir: Direction) -> usize; | |
fn children(&self, node: Node) -> impl DoubleEndedIterator<Item = Node> + Clone; | |
fn neighbours(&self, node: Node, dir: Direction) -> impl Iterator<Item = Node> + Clone; | |
fn all_neighbours(&self, node: Node) -> impl Iterator<Item = Node> + Clone; | |
} | |
} |
Any I don't think the delegate block is annoying enough to merit much more workarounds. We can add the handful implementations to |
closes #1636 . Uses macro to cover both
&T
and&mut T
and alsoRootChecked
.While this "works", there are downsides: previously we had an
impl<T:AsRef<Hugr>> HugrView for T
so the "AsRef" coversRc
,Cow
, etc. etc., whereas now we only have specific cases of&
and&mut
(admittedly for any HugrView not just an actual Hugr).Really it seems that what we'd like is one
impl<H: HugrView, T: AsRef<H>> HugrView for T
. However there are about three issues here:impl HugrView for Hugr
because we haveimpl AsRef<Hugr> for Hugr
, and we need that for the builder. We can actually remove that conflictingimpl AsRef
if we add a new trait (call itBuildable
😁) - see eeb9e73 - so that is soluble, and might even be good, if it were a step towards being able to use the builder on arbitrary HugrMut's e.g. limited to a sibling subtree. But it's mildly disruptive, so I've not undone that for this PR.impl AsRef<Hugr> for Hugr
, means that&Hugr
doesn't implAsRef<Hugr>
either (!) - the wayAsRef
works is that&T
inherits anyAsRef
-ness fromT
, there is no blanketimpl<T> AsRef<T> for &T
. ConverselyBorrow
has both blanketimpl<T> Borrow<T> for &T
and alsoimpl<T> Borrow<T> for T
, the latter again means we conflict withimpl HugrView for Hugr
). Possibly we could define our own trait/version of AsRef that we impl forRc
,Cow
,&
and&mut
.... :-(AsRef<X> for Y
for anyX
,Y
that both implement HugrView, so rustc won't even let usimpl<H: HugrView, T: AsRef<H>> HugrView for T
. (Might this work for our own version of AsRef?) One possible solution here would be to say, every new implementation of HugrView, such asDescendantsGraph
, should have its ownimpl<T: AsRef<DescendantsGraph>> HugrView for T
, and then we provide the macro to do that (like thehugr_view_methods
here - the same macro would also have toimpl<T:AsRef<_>> HugrInternals for T
too, which doesn't sound all that "internal", ick...)<T: HugrView + AsRef<T>>
, which is awkward - I'm not sure whether we could avoid that withtrait HugrView: AsRef<Self>
, I haven't got that far. Perhaps if we have a custom AsRef and say:???
(I even wonder if we might use
std::ops::Deref
, but I started to try that and got into lots of trouble with lifetimes...)Summary this PR has some shortcomings, but it does work. The CustomAsRef route might be better, but might not work at all, and/or may have other unforeseen problems - is it worth pursuing?
BREAKING CHANGE: types which implement AsRef - both library ones such as Rc and custom ones - no longer get a blanket impl of HugrView. Workaround by manually calling
as_ref()
and using the&Hugr
yourself.