1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
// SPDX-License-Identifier: CC0-1.0
//! Disconnect Nodes
//!
//! This module defines the [`Disconnectable`] trait, which is applied to the
//! right child of `disconnect` Simplicity nodes, allowing them to represent
//! "disconnected expressions" which may or may not be present, and which
//! contribute to a node's IMR but not CMR.
use crate::dag::Dag;
use std::sync::Arc;
/// Null data type used as dummy for [`Marker::Disconnect`]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct NoDisconnect;
/// Trait representing a "disconnected expression".
pub trait Disconnectable<L> {
/// Given a generic left child, and treating `self` as the disconnected right
/// child, produce a [`Dag`] node representing a disconnect node.
///
/// If the disconnected expression is present, this should yield a [`Dag::Binary`].
/// If it is not present, this should yield a [`Dag::Unary`].
fn disconnect_dag_arc(self, other: Arc<L>) -> Dag<Arc<L>>;
/// Same as [`Disconnectable::disconnect_dag_ref`] but takes self by reference.
fn disconnect_dag_ref<'s>(&'s self, other: &'s L) -> Dag<&'s L>;
}
// Rust's coherence rules prevent us from just doing a small set of blanket
// implementations; one for NoDisconnect (always yielding Dag::Unary) and
// one for T: Borrow<L> (always yielding Dag::Binary) and optional variants.
//
// Instead we have this messy and incomplete list.
// `NoDisconnect` works with arbitrary Arcs
impl<L> Disconnectable<L> for NoDisconnect {
fn disconnect_dag_arc(self, other: Arc<L>) -> Dag<Arc<L>> {
Dag::Unary(other)
}
fn disconnect_dag_ref<'s>(&'s self, other: &'s L) -> Dag<&'s L> {
Dag::Unary(other)
}
}
// Arbitrary things (references, Arcs, whatever) work with themselves.
// This blanket impl is why we can't have a blanket impl for NoDisconnect.
impl<L> Disconnectable<L> for Arc<L> {
fn disconnect_dag_arc(self, other: Arc<L>) -> Dag<Arc<L>> {
Dag::Binary(other, self)
}
fn disconnect_dag_ref<'s>(&'s self, other: &'s L) -> Dag<&'s L> {
Dag::Binary(other, self)
}
}
// Then Option<Arc> can work with either Arcs or references.
impl<L> Disconnectable<L> for Option<Arc<L>> {
fn disconnect_dag_arc(self, other: Arc<L>) -> Dag<Arc<L>> {
match self {
Some(right) => Dag::Binary(other, right),
None => Dag::Unary(other),
}
}
fn disconnect_dag_ref<'s>(&'s self, other: &'s L) -> Dag<&'s L> {
match self {
Some(right) => Dag::Binary(other, right),
None => Dag::Unary(other),
}
}
}