use std::sync::Arc;
use simplicity::dag::{InternalSharing, PostOrderIterItem};
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;
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> = Node<WithNames<node::Construct<'brand>>>;
pub type CommitNode = Node<WithNames<node::Commit>>;
pub fn finalize_types<'brand>(
node: &Node<WithNames<node::Construct<'brand>>>,
) -> Result<Arc<Node<WithNames<node::Commit>>>, 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,
N::Witness: Nullable,
F: FnMut(
&Node<WithNames<M>>,
Inner<&N::CachedData, &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,
N::Witness: Nullable,
F: FnMut(
&Node<WithNames<M>>,
Inner<&N::CachedData, &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>>>, &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::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(
node: &CommitNode,
values: WitnessValues,
) -> Result<Arc<node::RedeemNode>, String> {
struct Populator {
values: WitnessValues,
}
impl Converter<WithNames<node::Commit>, node::Redeem> for Populator {
type Error = String;
fn convert_witness(
&mut self,
_: &PostOrderIterItem<&CommitNode>,
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>,
_: Option<&Arc<node::RedeemNode>>,
_: &NoDisconnect,
) -> Result<Arc<node::RedeemNode>, Self::Error> {
unreachable!("SimplicityHL does not use disconnect right now")
}
fn convert_data(
&mut self,
data: &PostOrderIterItem<&CommitNode>,
inner: Inner<&Arc<node::RedeemNode>, &Arc<node::RedeemNode>, &simplicity::Value>,
) -> Result<Arc<node::RedeemData>, 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> WitnessConstructible<'brand, WitnessName> for node::ConstructData<'brand> {
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
}
}