use std::sync::Arc;
use simplicity::dag::{InternalSharing, PostOrderIterItem};
use simplicity::jet::{Elements, Jet};
use simplicity::node::{
self, CommitData, ConstructData as WitnessData, Constructible, Converter, CoreConstructible,
Inner, JetConstructible, NoDisconnect, NoWitness, Node, WitnessConstructible,
};
use simplicity::types::arrow::Arrow;
use simplicity::{types, CommitNode, FailEntropy};
use simplicity::{Cmr, ConstructNode as WitnessNode};
use crate::str::WitnessName;
use crate::value::StructuralValue;
use crate::witness::WitnessValues;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Construct<N> {
never: std::convert::Infallible,
phantom: std::marker::PhantomData<N>,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub enum ConstructId {}
impl<J: Jet> node::Marker for Construct<J> {
type CachedData = ConstructData<J>;
type Witness = WitnessName;
type Disconnect = NoDisconnect;
type SharingId = ConstructId;
type Jet = J;
fn compute_sharing_id(_: Cmr, _cached_data: &Self::CachedData) -> Option<Self::SharingId> {
None
}
}
pub type ConstructNode = Node<Construct<Elements>>;
pub fn to_commit_node(node: &ConstructNode) -> Result<Arc<CommitNode<Elements>>, types::Error> {
struct Forgetter;
impl<J: Jet> Converter<Construct<J>, node::Commit<J>> for Forgetter {
type Error = types::Error;
fn convert_witness(
&mut self,
_: &PostOrderIterItem<&Node<Construct<J>>>,
_: &WitnessName,
) -> Result<NoWitness, Self::Error> {
Ok(NoWitness)
}
fn convert_disconnect(
&mut self,
_: &PostOrderIterItem<&Node<Construct<J>>>,
_: Option<&Arc<CommitNode<J>>>,
_: &NoDisconnect,
) -> Result<NoDisconnect, Self::Error> {
Ok(NoDisconnect)
}
fn convert_data(
&mut self,
data: &PostOrderIterItem<&Node<Construct<J>>>,
inner: Inner<&Arc<CommitNode<J>>, J, &NoDisconnect, &NoWitness>,
) -> Result<Arc<CommitData<J>>, Self::Error> {
let arrow = data.node.cached_data().arrow();
let inner = inner.map(Arc::as_ref).map(CommitNode::<J>::cached_data);
CommitData::new(arrow, inner).map(Arc::new)
}
}
node.convert::<InternalSharing, _, _>(&mut Forgetter)
}
pub fn to_witness_node(node: &ConstructNode, values: WitnessValues) -> Arc<WitnessNode<Elements>> {
struct Populator {
values: WitnessValues,
inference_context: types::Context,
}
impl<J: Jet> Converter<Construct<J>, node::Construct<J>> for Populator {
type Error = ();
fn convert_witness(
&mut self,
_: &PostOrderIterItem<&Node<Construct<J>>>,
witness: &WitnessName,
) -> Result<Option<simplicity::Value>, Self::Error> {
let maybe_value = self
.values
.get(witness)
.map(StructuralValue::from)
.map(simplicity::Value::from);
Ok(maybe_value)
}
fn convert_disconnect(
&mut self,
_: &PostOrderIterItem<&Node<Construct<J>>>,
_: Option<&Arc<WitnessNode<J>>>,
_: &NoDisconnect,
) -> Result<Option<Arc<WitnessNode<J>>>, Self::Error> {
Ok(None)
}
fn convert_data(
&mut self,
_: &PostOrderIterItem<&Node<Construct<J>>>,
inner: Inner<
&Arc<WitnessNode<J>>,
J,
&Option<Arc<WitnessNode<J>>>,
&Option<simplicity::Value>,
>,
) -> Result<WitnessData<J>, Self::Error> {
let inner = inner
.map(Arc::as_ref)
.map(WitnessNode::<J>::cached_data)
.map_witness(Option::<simplicity::Value>::clone);
Ok(WitnessData::from_inner(&self.inference_context, inner).unwrap())
}
}
let mut populator = Populator {
inference_context: types::Context::new(),
values,
};
node.convert::<InternalSharing, _, _>(&mut populator)
.unwrap()
}
#[derive(Clone, Debug)]
pub struct ConstructData<J> {
arrow: Arrow,
phantom: std::marker::PhantomData<J>,
}
impl<J> ConstructData<J> {
pub fn arrow(&self) -> &Arrow {
&self.arrow
}
}
impl<J> From<Arrow> for ConstructData<J> {
fn from(arrow: Arrow) -> Self {
Self {
arrow,
phantom: std::marker::PhantomData,
}
}
}
impl<J> CoreConstructible for ConstructData<J> {
fn iden(inference_context: &types::Context) -> Self {
Arrow::iden(inference_context).into()
}
fn unit(inference_context: &types::Context) -> Self {
Arrow::unit(inference_context).into()
}
fn injl(child: &Self) -> Self {
Arrow::injl(&child.arrow).into()
}
fn injr(child: &Self) -> Self {
Arrow::injr(&child.arrow).into()
}
fn take(child: &Self) -> Self {
Arrow::take(&child.arrow).into()
}
fn drop_(child: &Self) -> Self {
Arrow::drop_(&child.arrow).into()
}
fn comp(left: &Self, right: &Self) -> Result<Self, types::Error> {
Arrow::comp(&left.arrow, &right.arrow).map(Self::from)
}
fn case(left: &Self, right: &Self) -> Result<Self, types::Error> {
Arrow::case(&left.arrow, &right.arrow).map(Self::from)
}
fn assertl(left: &Self, right: Cmr) -> Result<Self, types::Error> {
Arrow::assertl(&left.arrow, right).map(Self::from)
}
fn assertr(left: Cmr, right: &Self) -> Result<Self, types::Error> {
Arrow::assertr(left, &right.arrow).map(Self::from)
}
fn pair(left: &Self, right: &Self) -> Result<Self, types::Error> {
Arrow::pair(&left.arrow, &right.arrow).map(Self::from)
}
fn fail(inference_context: &types::Context, entropy: FailEntropy) -> Self {
Arrow::fail(inference_context, entropy).into()
}
fn const_word(inference_context: &types::Context, word: simplicity::Word) -> Self {
Arrow::const_word(inference_context, word).into()
}
fn inference_context(&self) -> &types::Context {
self.arrow.inference_context()
}
}
impl<J: Jet> JetConstructible<J> for ConstructData<J> {
fn jet(inference_context: &types::Context, jet: J) -> Self {
Arrow::jet(inference_context, jet).into()
}
}
impl<J> WitnessConstructible<WitnessName> for ConstructData<J> {
fn witness(inference_context: &types::Context, _: WitnessName) -> Self {
Arrow::witness(inference_context, ()).into()
}
}
pub trait CoreExt: CoreConstructible + Sized {
fn h(inference_context: &types::Context) -> PairBuilder<Self> {
PairBuilder::iden(inference_context)
}
fn o() -> SelectorBuilder<Self> {
SelectorBuilder::default().o()
}
fn i() -> SelectorBuilder<Self> {
SelectorBuilder::default().i()
}
fn bit(inference_context: &types::Context, bit: bool) -> PairBuilder<Self> {
match bit {
false => PairBuilder::unit(inference_context).injl(),
true => PairBuilder::unit(inference_context).injr(),
}
}
fn unit_scribe(inference_context: &types::Context, value: &simplicity::Value) -> Self {
Self::comp(
&Self::unit(inference_context),
&Self::scribe(inference_context, value),
)
.unwrap()
}
fn assertl_take(&self, cmr: Cmr) -> Self {
Self::assertl(&Self::take(self), cmr).unwrap()
}
fn assertl_drop(&self, cmr: Cmr) -> Self {
Self::assertl(&Self::drop_(self), cmr).unwrap()
}
fn assertr_take(cmr: Cmr, right: &Self) -> Self {
Self::assertr(cmr, &Self::take(right)).unwrap()
}
fn assertr_drop(cmr: Cmr, right: &Self) -> Self {
Self::assertr(cmr, &Self::drop_(right)).unwrap()
}
fn case_false_true(inference_context: &types::Context) -> Self {
Self::case(
&Self::bit_false(inference_context),
&Self::bit_true(inference_context),
)
.unwrap()
}
fn case_true_false(inference_context: &types::Context) -> Self {
Self::case(
&Self::bit_true(inference_context),
&Self::bit_false(inference_context),
)
.unwrap()
}
}
impl<N: CoreConstructible> CoreExt for N {}
#[derive(Debug, Clone, Hash)]
pub struct SelectorBuilder<P> {
selection: Vec<bool>,
program: std::marker::PhantomData<P>,
}
impl<P> Default for SelectorBuilder<P> {
fn default() -> Self {
Self {
selection: Vec::default(),
program: std::marker::PhantomData,
}
}
}
impl<P: CoreExt> SelectorBuilder<P> {
pub fn o(mut self) -> Self {
self.selection.push(false);
self
}
pub fn i(mut self) -> Self {
self.selection.push(true);
self
}
pub fn pop(mut self) -> Self {
self.selection.pop().expect("Stack is empty");
self
}
pub fn h(self, inference_context: &types::Context) -> PairBuilder<P> {
let mut expr = PairBuilder::iden(inference_context);
for bit in self.selection.into_iter().rev() {
match bit {
false => expr = expr.take(),
true => expr = expr.drop_(),
}
}
expr
}
}
#[derive(Debug, Clone, Hash)]
pub struct PairBuilder<P>(P);
impl<P: CoreExt> PairBuilder<P> {
pub fn unit(inference_context: &types::Context) -> Self {
Self(P::unit(inference_context))
}
pub fn iden(inference_context: &types::Context) -> Self {
Self(P::iden(inference_context))
}
pub fn fail(inference_context: &types::Context, entropy: FailEntropy) -> Self {
Self(P::fail(inference_context, entropy))
}
pub fn injl(self) -> Self {
Self(P::injl(&self.0))
}
pub fn injr(self) -> Self {
Self(P::injr(&self.0))
}
pub fn take(self) -> Self {
Self(P::take(&self.0))
}
pub fn drop_(self) -> Self {
Self(P::drop_(&self.0))
}
pub fn comp<Q: std::borrow::Borrow<P>>(self, other: &Q) -> Result<Self, types::Error> {
P::comp(&self.0, other.borrow()).map(Self)
}
pub fn pair(self, other: Self) -> Self {
Self(P::pair(&self.0, &other.0).unwrap())
}
pub fn unit_scribe(inference_context: &types::Context, value: &simplicity::Value) -> Self {
Self(P::unit_scribe(inference_context, value))
}
}
impl<P: WitnessConstructible<WitnessName>> PairBuilder<P> {
pub fn witness(inference_context: &types::Context, witness: WitnessName) -> Self {
Self(P::witness(inference_context, witness))
}
}
impl<P> PairBuilder<P> {
pub fn build(self) -> P {
self.0
}
}
impl<P> AsRef<P> for PairBuilder<P> {
fn as_ref(&self) -> &P {
&self.0
}
}
impl<P> std::borrow::Borrow<P> for PairBuilder<P> {
fn borrow(&self) -> &P {
&self.0
}
}