use std::sync::Arc;
use simplicity::dag::{InternalSharing, PostOrderIterItem};
use simplicity::jet::Jet;
use simplicity::node::{
self, Converter, CoreConstructible, Inner, NoDisconnect, NoWitness, Node, WitnessConstructible,
};
use simplicity::Cmr;
use simplicity::{types, FailEntropy};
use crate::str::WitnessName;
use crate::value::StructuralValue;
use crate::witness::WitnessValues;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct WithNames<T>(T);
impl<M: node::Marker> node::Marker for WithNames<M> {
type CachedData = M::CachedData;
type Witness = WitnessName;
type Disconnect = NoDisconnect;
type SharingId = M::SharingId;
type Jet = M::Jet;
fn compute_sharing_id(cmr: Cmr, cached_data: &Self::CachedData) -> Option<Self::SharingId> {
M::compute_sharing_id(cmr, cached_data)
}
}
pub trait Nullable {
fn none() -> Self;
}
impl<T> Nullable for Option<T> {
fn none() -> Self {
None
}
}
impl Nullable for NoWitness {
fn none() -> Self {
NoWitness
}
}
impl Nullable for NoDisconnect {
fn none() -> Self {
NoDisconnect
}
}
pub type ConstructNode<'brand, J> = Node<WithNames<node::Construct<'brand, J>>>;
pub type CommitNode<J> = Node<WithNames<node::Commit<J>>>;
pub fn finalize_types<J: Jet>(
node: &Node<WithNames<node::Construct<J>>>,
) -> Result<Arc<Node<WithNames<node::Commit<J>>>>, types::Error> {
translate(node, |node, inner| {
let inner = inner.map_witness(|_| &NoWitness);
node::CommitData::new(node.cached_data().arrow(), inner).map(Arc::new)
})
}
fn translate<M, N, F, E>(
node: &Node<WithNames<M>>,
translatefn: F,
) -> Result<Arc<Node<WithNames<N>>>, E>
where
M: node::Marker,
N: node::Marker<Jet = M::Jet>,
N::Witness: Nullable,
F: FnMut(
&Node<WithNames<M>>,
Inner<&N::CachedData, N::Jet, &NoDisconnect, &WitnessName>,
) -> Result<N::CachedData, E>,
{
struct Translator<F>(F);
impl<M, N, F, E> Converter<WithNames<M>, WithNames<N>> for Translator<F>
where
M: node::Marker,
N: node::Marker<Jet = M::Jet>,
N::Witness: Nullable,
F: FnMut(
&Node<WithNames<M>>,
Inner<&N::CachedData, N::Jet, &NoDisconnect, &WitnessName>,
) -> Result<N::CachedData, E>,
{
type Error = E;
fn convert_witness(
&mut self,
_: &PostOrderIterItem<&Node<WithNames<M>>>,
wit: &WitnessName,
) -> Result<WitnessName, Self::Error> {
Ok(wit.shallow_clone())
}
fn convert_disconnect(
&mut self,
_: &PostOrderIterItem<&Node<WithNames<M>>>,
_: Option<&Arc<Node<WithNames<N>>>>,
_: &NoDisconnect,
) -> Result<NoDisconnect, Self::Error> {
Ok(NoDisconnect)
}
fn convert_data(
&mut self,
data: &PostOrderIterItem<&Node<WithNames<M>>>,
inner: Inner<&Arc<Node<WithNames<N>>>, N::Jet, &NoDisconnect, &WitnessName>,
) -> Result<N::CachedData, Self::Error> {
let new_inner = inner.map(|node| node.cached_data());
self.0(data.node, new_inner)
}
}
node.convert::<InternalSharing, _, _>(&mut Translator(translatefn))
}
pub fn forget_names<M>(node: &Node<WithNames<M>>) -> Arc<Node<M>>
where
M: node::Marker,
M::Disconnect: Nullable,
M::Witness: Nullable,
{
struct Forgetter;
impl<M> Converter<WithNames<M>, M> for Forgetter
where
M: node::Marker,
M::Disconnect: Nullable,
M::Witness: Nullable,
{
type Error = core::convert::Infallible;
fn convert_witness(
&mut self,
_: &PostOrderIterItem<&Node<WithNames<M>>>,
_: &WitnessName,
) -> Result<M::Witness, Self::Error> {
Ok(M::Witness::none())
}
fn convert_disconnect(
&mut self,
_: &PostOrderIterItem<&Node<WithNames<M>>>,
_: Option<&Arc<Node<M>>>,
_: &NoDisconnect,
) -> Result<M::Disconnect, Self::Error> {
Ok(M::Disconnect::none())
}
fn convert_data(
&mut self,
data: &PostOrderIterItem<&Node<WithNames<M>>>,
_: Inner<&Arc<Node<M>>, M::Jet, &M::Disconnect, &M::Witness>,
) -> Result<M::CachedData, Self::Error> {
Ok(data.node.cached_data().clone())
}
}
match node.convert::<InternalSharing, _, _>(&mut Forgetter) {
Ok(ret) => ret,
Err(inf) => match inf {},
}
}
pub fn populate_witnesses<J: Jet>(
node: &CommitNode<J>,
values: WitnessValues,
) -> Result<Arc<node::RedeemNode<J>>, String> {
struct Populator {
values: WitnessValues,
}
impl<J: Jet> Converter<WithNames<node::Commit<J>>, node::Redeem<J>> for Populator {
type Error = String;
fn convert_witness(
&mut self,
_: &PostOrderIterItem<&CommitNode<J>>,
witness: &WitnessName,
) -> Result<simplicity::Value, Self::Error> {
match self.values.get(witness) {
Some(val) => Ok(simplicity::Value::from(StructuralValue::from(val))),
None => Err(format!("missing witness for {witness}")),
}
}
fn convert_disconnect(
&mut self,
_: &PostOrderIterItem<&CommitNode<J>>,
_: Option<&Arc<node::RedeemNode<J>>>,
_: &NoDisconnect,
) -> Result<Arc<node::RedeemNode<J>>, Self::Error> {
unreachable!("SimplicityHL does not use disconnect right now")
}
fn convert_data(
&mut self,
data: &PostOrderIterItem<&CommitNode<J>>,
inner: Inner<
&Arc<node::RedeemNode<J>>,
J,
&Arc<node::RedeemNode<J>>,
&simplicity::Value,
>,
) -> Result<Arc<node::RedeemData<J>>, Self::Error> {
let inner = inner
.map(|node| node.cached_data())
.map_disconnect(|node| node.cached_data())
.map_witness(simplicity::Value::shallow_clone);
Ok(Arc::new(node::RedeemData::new(
data.node.cached_data().arrow().shallow_clone(),
inner,
)))
}
}
let mut populator = Populator { values };
node.convert::<InternalSharing, _, _>(&mut populator)
}
impl<'brand, J: Jet> WitnessConstructible<'brand, WitnessName> for node::ConstructData<'brand, J> {
fn witness(inference_context: &types::Context<'brand>, _: WitnessName) -> Self {
WitnessConstructible::<Option<_>>::witness(inference_context, None)
}
}
pub trait CoreExt<'brand>: CoreConstructible<'brand> + Sized {
fn h(inference_context: &types::Context<'brand>) -> 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<'brand>, 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<'brand>, 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<'brand>) -> Self {
Self::case(
&Self::bit_false(inference_context),
&Self::bit_true(inference_context),
)
.unwrap()
}
fn case_true_false(inference_context: &types::Context<'brand>) -> Self {
Self::case(
&Self::bit_true(inference_context),
&Self::bit_false(inference_context),
)
.unwrap()
}
}
impl<'brand, N: CoreConstructible<'brand>> CoreExt<'brand> 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<'brand, P: CoreExt<'brand>> 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<'brand>) -> 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<'brand, P: CoreExt<'brand>> PairBuilder<P> {
pub fn unit(inference_context: &types::Context<'brand>) -> Self {
Self(P::unit(inference_context))
}
pub fn iden(inference_context: &types::Context<'brand>) -> Self {
Self(P::iden(inference_context))
}
pub fn fail(inference_context: &types::Context<'brand>, 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<'brand>,
value: &simplicity::Value,
) -> Self {
Self(P::unit_scribe(inference_context, value))
}
}
impl<'brand, P: WitnessConstructible<'brand, WitnessName>> PairBuilder<P> {
pub fn witness(inference_context: &types::Context<'brand>, 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
}
}