Match on arc inside pattern

I'm guessing the answer is "no," but is it possible to clean up a nested match which has an Arc in the nested pattern, like this?:

enum Node {
    Left { parent: Arc<Node> },
    Right { left: Arc<Node> },
    Empty,
}

impl Node {
    fn parent(&self) -> Option<Arc<Self>> {
        match self {
            Node::Empty => None,
            Node::Left { parent } => Some(parent.clone()),
            Node::Right {
                left: Node::Left { parent },  // Rust doesn't like this, and with good reason
            } => Some(parent.clone()),
        }
    }
}

If that's not clear, I made a full repro here: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=5b50aa5141d6c3ce4a15fca47b0ab0a7 I don't like the seven lines matching the Node::Right arm when the three commented lines have such elegance.

I don't think this is possible today. It might be neat if patterns could involve Deref coercion though...

If this did work, note also that your patterns are not exhaustive, as there could (theoretically) be a Node::Right where left is actually a Right or Empty. Even if you're dynamically forbidding this, it is possible at the type level, so it must be handled. I see that you panicked in your "less elegant" solution, and you would need a match arm here to do the same.

1 Like

FWIW in my opinion an inner match in place of the if let would be more readable:

fn parent(&self) -> Option<Arc<Self>> {
    match self {
        Node::Left { parent } => Some(parent.clone()),
        Node::Right { left } => match &**left {
            Node::Left { parent } => Some(parent.clone()),
             _ => panic!("invalid tree structure"),
        },
        Node::Empty => None,
    }
}

Incidentally, I like that the ref and the derefs are spelled out as-is. I'd actually be surprised if what you want had worked — the auto-reffing pattern binding modes along with auto-deref — hiding three pointer operations and one complete smart pointer type — are just way too magical.

1 Like

True, it's a giant can of worms to start invoking user code, in their Deref implementation. Patterns today are purely structural, and you can only observe user code in pattern guards.

1 Like