feat: more Rc in machine

This commit is contained in:
rvcas 2023-01-31 21:01:13 -05:00 committed by Lucas
parent c8efe60843
commit 9c4e921e79
4 changed files with 178 additions and 162 deletions

View File

@ -2,4 +2,5 @@
members = ["crates/*"] members = ["crates/*"]
[profile.release] [profile.release]
strip = true # strip = true
debug = true

View File

@ -16,8 +16,8 @@ use pallas_primitives::babbage::{BigInt, Language, PlutusData};
use self::{cost_model::CostModel, runtime::BuiltinRuntime}; use self::{cost_model::CostModel, runtime::BuiltinRuntime};
enum MachineStep { enum MachineStep {
Return(Rc<Context>, Value), Return(Rc<Context>, Rc<Value>),
Compute(Rc<Context>, Rc<Vec<Value>>, Rc<Term<NamedDeBruijn>>), Compute(Rc<Context>, Rc<Vec<Rc<Value>>>, Rc<Term<NamedDeBruijn>>),
Done(Rc<Term<NamedDeBruijn>>), Done(Rc<Term<NamedDeBruijn>>),
} }
@ -54,8 +54,8 @@ enum PartialTerm {
#[derive(Clone)] #[derive(Clone)]
enum DischargeStep { enum DischargeStep {
DischargeValue(Value), DischargeValue(Rc<Value>),
DischargeValueEnv(usize, Rc<Vec<Value>>, Rc<Term<NamedDeBruijn>>), DischargeValueEnv(usize, Rc<Vec<Rc<Value>>>, Rc<Term<NamedDeBruijn>>),
PopArgStack(PartialTerm), PopArgStack(PartialTerm),
} }
@ -122,14 +122,14 @@ impl Machine {
fn compute( fn compute(
&mut self, &mut self,
context: Rc<Context>, context: Rc<Context>,
env: Rc<Vec<Value>>, env: Rc<Vec<Rc<Value>>>,
term: Rc<Term<NamedDeBruijn>>, term: Rc<Term<NamedDeBruijn>>,
) -> Result<(), Error> { ) -> Result<(), Error> {
match term.as_ref() { match term.as_ref() {
Term::Var(name) => { Term::Var(name) => {
self.step_and_maybe_spend(StepKind::Var)?; self.step_and_maybe_spend(StepKind::Var)?;
let val = self.lookup_var(name, env)?; let val = self.lookup_var(name, &env)?;
self.stack.push(MachineStep::Return(context, val)); self.stack.push(MachineStep::Return(context, val));
} }
@ -138,7 +138,7 @@ impl Machine {
self.stack.push(MachineStep::Return( self.stack.push(MachineStep::Return(
context, context,
Value::Delay(Rc::clone(body), env), Value::Delay(Rc::clone(body), env).into(),
)); ));
} }
Term::Lambda { Term::Lambda {
@ -153,7 +153,8 @@ impl Machine {
parameter_name: parameter_name.clone(), parameter_name: parameter_name.clone(),
body: Rc::clone(body), body: Rc::clone(body),
env, env,
}, }
.into(),
)); ));
} }
Term::Apply { function, argument } => { Term::Apply { function, argument } => {
@ -173,7 +174,7 @@ impl Machine {
self.step_and_maybe_spend(StepKind::Constant)?; self.step_and_maybe_spend(StepKind::Constant)?;
self.stack self.stack
.push(MachineStep::Return(context, Value::Con(x.clone()))); .push(MachineStep::Return(context, Value::Con(x.clone()).into()));
} }
Term::Force(body) => { Term::Force(body) => {
self.step_and_maybe_spend(StepKind::Force)?; self.step_and_maybe_spend(StepKind::Force)?;
@ -195,8 +196,9 @@ impl Machine {
Value::Builtin { Value::Builtin {
fun: *fun, fun: *fun,
term, term,
runtime, runtime: runtime.into(),
}, }
.into(),
)); ));
} }
}; };
@ -204,10 +206,10 @@ impl Machine {
Ok(()) Ok(())
} }
fn return_compute(&mut self, context: Rc<Context>, value: Value) -> Result<(), Error> { fn return_compute(&mut self, context: Rc<Context>, value: Rc<Value>) -> Result<(), Error> {
match context.as_ref() { match context.as_ref() {
Context::FrameApplyFun(function, ctx) => { Context::FrameApplyFun(function, ctx) => {
self.apply_evaluate(ctx.to_owned(), function.to_owned(), value)? self.apply_evaluate(ctx.to_owned(), function.clone(), value)?
} }
Context::FrameApplyArg(arg_var_env, arg, ctx) => { Context::FrameApplyArg(arg_var_env, arg, ctx) => {
self.stack.push(MachineStep::Compute( self.stack.push(MachineStep::Compute(
@ -231,26 +233,27 @@ impl Machine {
Ok(()) Ok(())
} }
fn force_evaluate(&mut self, context: Rc<Context>, value: Value) -> Result<(), Error> { fn force_evaluate(&mut self, context: Rc<Context>, mut value: Rc<Value>) -> Result<(), Error> {
let value = Rc::make_mut(&mut value);
match value { match value {
Value::Delay(body, env) => { Value::Delay(body, env) => {
self.stack.push(MachineStep::Compute(context, env, body)); self.stack
.push(MachineStep::Compute(context, env.clone(), body.clone()));
Ok(()) Ok(())
} }
Value::Builtin { Value::Builtin { fun, term, runtime } => {
fun, let force_term = Rc::new(Term::Force(term.clone()));
term,
mut runtime,
} => {
let force_term = Rc::new(Term::Force(term));
if runtime.needs_force() { let mut_runtime = Rc::make_mut(runtime);
runtime.consume_force();
let res = self.eval_builtin_app(fun, force_term, runtime)?; if mut_runtime.needs_force() {
mut_runtime.consume_force();
self.stack.push(MachineStep::Return(context, res)); let res = self.eval_builtin_app(*fun, force_term, runtime.clone())?;
self.stack.push(MachineStep::Return(context, res.into()));
Ok(()) Ok(())
} else { } else {
@ -259,52 +262,58 @@ impl Machine {
)) ))
} }
} }
rest => Err(Error::NonPolymorphicInstantiation(rest)), rest => Err(Error::NonPolymorphicInstantiation(rest.clone())),
} }
} }
fn apply_evaluate( fn apply_evaluate(
&mut self, &mut self,
context: Rc<Context>, context: Rc<Context>,
function: Value, mut function: Rc<Value>,
argument: Value, argument: Rc<Value>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let function = Rc::make_mut(&mut function);
match function { match function {
Value::Lambda { body, mut env, .. } => { Value::Lambda { body, env, .. } => {
let e = Rc::make_mut(&mut env); let e = Rc::make_mut(env);
e.push(argument); e.push(argument);
self.stack self.stack.push(MachineStep::Compute(
.push(MachineStep::Compute(context, Rc::new(e.clone()), body)); context,
Rc::new(e.clone()),
body.clone(),
));
Ok(()) Ok(())
} }
Value::Builtin { Value::Builtin { fun, term, runtime } => {
fun,
term,
mut runtime,
} => {
let arg_term = discharge_value(argument.clone()); let arg_term = discharge_value(argument.clone());
let t = Rc::new(Term::<NamedDeBruijn>::Apply { let t = Rc::new(Term::<NamedDeBruijn>::Apply {
function: term, function: term.clone(),
argument: arg_term, argument: arg_term,
}); });
if runtime.is_arrow() && !runtime.needs_force() { let mut_runtime = Rc::make_mut(runtime);
runtime.push(argument)?;
let res = self.eval_builtin_app(fun, t, runtime)?; if mut_runtime.is_arrow() && !mut_runtime.needs_force() {
mut_runtime.push(argument)?;
self.stack.push(MachineStep::Return(context, res)); let res = self.eval_builtin_app(*fun, t, runtime.clone())?;
self.stack.push(MachineStep::Return(context, res.into()));
Ok(()) Ok(())
} else { } else {
Err(Error::UnexpectedBuiltinTermArgument(t.as_ref().clone())) Err(Error::UnexpectedBuiltinTermArgument(t.as_ref().clone()))
} }
} }
rest => Err(Error::NonFunctionalApplication(rest, argument)), rest => Err(Error::NonFunctionalApplication(
rest.clone(),
argument.as_ref().clone(),
)),
} }
} }
@ -312,7 +321,7 @@ impl Machine {
&mut self, &mut self,
fun: DefaultFunction, fun: DefaultFunction,
term: Rc<Term<NamedDeBruijn>>, term: Rc<Term<NamedDeBruijn>>,
runtime: BuiltinRuntime, runtime: Rc<BuiltinRuntime>,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
if runtime.is_ready() { if runtime.is_ready() {
let cost = match self.version { let cost = match self.version {
@ -327,7 +336,7 @@ impl Machine {
} }
} }
fn lookup_var(&mut self, name: &NamedDeBruijn, env: Rc<Vec<Value>>) -> Result<Value, Error> { fn lookup_var(&mut self, name: &NamedDeBruijn, env: &[Rc<Value>]) -> Result<Rc<Value>, Error> {
env.get::<usize>(env.len() - usize::from(name.index)) env.get::<usize>(env.len() - usize::from(name.index))
.cloned() .cloned()
.ok_or_else(|| Error::OpenTermEvaluated(Term::Var(name.clone().into()))) .ok_or_else(|| Error::OpenTermEvaluated(Term::Var(name.clone().into())))
@ -374,19 +383,19 @@ impl Machine {
} }
} }
fn discharge_value(value: Value) -> Rc<Term<NamedDeBruijn>> { fn discharge_value(value: Rc<Value>) -> Rc<Term<NamedDeBruijn>> {
let mut stack = vec![DischargeStep::DischargeValue(value)]; let mut stack = vec![DischargeStep::DischargeValue(value)];
let mut arg_stack = vec![]; let mut arg_stack = vec![];
while let Some(stack_frame) = stack.pop() { while let Some(stack_frame) = stack.pop() {
match stack_frame { match stack_frame {
DischargeStep::DischargeValue(value) => match value { DischargeStep::DischargeValue(value) => match value.as_ref() {
Value::Con(x) => arg_stack.push(Term::Constant(x).into()), Value::Con(x) => arg_stack.push(Term::Constant(x.clone()).into()),
Value::Builtin { term, .. } => arg_stack.push(term.clone()), Value::Builtin { term, .. } => arg_stack.push(term.clone()),
Value::Delay(body, env) => { Value::Delay(body, env) => {
stack.push(DischargeStep::DischargeValueEnv( stack.push(DischargeStep::DischargeValueEnv(
0, 0,
env, env.clone(),
Term::Delay(body).into(), Term::Delay(body.clone()).into(),
)); ));
} }
Value::Lambda { Value::Lambda {
@ -396,10 +405,10 @@ fn discharge_value(value: Value) -> Rc<Term<NamedDeBruijn>> {
} => { } => {
stack.push(DischargeStep::DischargeValueEnv( stack.push(DischargeStep::DischargeValueEnv(
0, 0,
env, env.clone(),
Term::Lambda { Term::Lambda {
parameter_name: parameter_name.clone(), parameter_name: parameter_name.clone(),
body, body: body.clone(),
} }
.into(), .into(),
)); ));
@ -500,8 +509,8 @@ fn discharge_value(value: Value) -> Rc<Term<NamedDeBruijn>> {
#[derive(Clone)] #[derive(Clone)]
enum Context { enum Context {
FrameApplyFun(Value, Rc<Context>), FrameApplyFun(Rc<Value>, Rc<Context>),
FrameApplyArg(Rc<Vec<Value>>, Rc<Term<NamedDeBruijn>>, Rc<Context>), FrameApplyArg(Rc<Vec<Rc<Value>>>, Rc<Term<NamedDeBruijn>>, Rc<Context>),
FrameForce(Rc<Context>), FrameForce(Rc<Context>),
NoFrame, NoFrame,
} }
@ -509,16 +518,16 @@ enum Context {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Value { pub enum Value {
Con(Rc<Constant>), Con(Rc<Constant>),
Delay(Rc<Term<NamedDeBruijn>>, Rc<Vec<Value>>), Delay(Rc<Term<NamedDeBruijn>>, Rc<Vec<Rc<Value>>>),
Lambda { Lambda {
parameter_name: Rc<NamedDeBruijn>, parameter_name: Rc<NamedDeBruijn>,
body: Rc<Term<NamedDeBruijn>>, body: Rc<Term<NamedDeBruijn>>,
env: Rc<Vec<Value>>, env: Rc<Vec<Rc<Value>>>,
}, },
Builtin { Builtin {
fun: DefaultFunction, fun: DefaultFunction,
term: Rc<Term<NamedDeBruijn>>, term: Rc<Term<NamedDeBruijn>>,
runtime: BuiltinRuntime, runtime: Rc<BuiltinRuntime>,
}, },
} }

View File

@ -1,4 +1,4 @@
use std::collections::HashMap; use std::{collections::HashMap, rc::Rc};
use pallas_primitives::babbage::Language; use pallas_primitives::babbage::Language;
@ -973,7 +973,7 @@ impl Default for BuiltinCosts {
} }
impl BuiltinCosts { impl BuiltinCosts {
pub fn to_ex_budget_v2(&self, fun: DefaultFunction, args: &[Value]) -> ExBudget { pub fn to_ex_budget_v2(&self, fun: DefaultFunction, args: &[Rc<Value>]) -> ExBudget {
match fun { match fun {
DefaultFunction::AddInteger => ExBudget { DefaultFunction::AddInteger => ExBudget {
mem: self mem: self
@ -1378,7 +1378,7 @@ impl BuiltinCosts {
} }
} }
pub fn to_ex_budget_v1(&self, fun: DefaultFunction, args: &[Value]) -> ExBudget { pub fn to_ex_budget_v1(&self, fun: DefaultFunction, args: &[Rc<Value>]) -> ExBudget {
match fun { match fun {
DefaultFunction::AddInteger => ExBudget { DefaultFunction::AddInteger => ExBudget {
mem: self mem: self

View File

@ -21,7 +21,7 @@ use super::{
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct BuiltinRuntime { pub struct BuiltinRuntime {
args: Vec<Value>, args: Vec<Rc<Value>>,
fun: DefaultFunction, fun: DefaultFunction,
forces: u32, forces: u32,
} }
@ -55,7 +55,7 @@ impl BuiltinRuntime {
self.fun.call(&self.args, logs) self.fun.call(&self.args, logs)
} }
pub fn push(&mut self, arg: Value) -> Result<(), Error> { pub fn push(&mut self, arg: Rc<Value>) -> Result<(), Error> {
self.fun.check_type(&arg, &self.args)?; self.fun.check_type(&arg, &self.args)?;
self.args.push(arg); self.args.push(arg);
@ -197,7 +197,7 @@ impl DefaultFunction {
} }
} }
pub fn check_type(&self, arg: &Value, args: &[Value]) -> Result<(), Error> { pub fn check_type(&self, arg: &Value, args: &[Rc<Value>]) -> Result<(), Error> {
match self { match self {
DefaultFunction::AddInteger => arg.expect_type(Type::Integer), DefaultFunction::AddInteger => arg.expect_type(Type::Integer),
DefaultFunction::SubtractInteger => arg.expect_type(Type::Integer), DefaultFunction::SubtractInteger => arg.expect_type(Type::Integer),
@ -279,7 +279,7 @@ impl DefaultFunction {
if args.is_empty() { if args.is_empty() {
Ok(()) Ok(())
} else { } else {
let first = args[0].clone(); let first = args[0].as_ref().clone();
arg.expect_type(Type::List(Rc::new(first.try_into()?))) arg.expect_type(Type::List(Rc::new(first.try_into()?)))
} }
@ -324,9 +324,9 @@ impl DefaultFunction {
// This should be safe because we've already checked // This should be safe because we've already checked
// the types of the args as they were pushed. Although // the types of the args as they were pushed. Although
// the unreachables look ugly, it's the reality of the situation. // the unreachables look ugly, it's the reality of the situation.
pub fn call(&self, args: &[Value], logs: &mut Vec<String>) -> Result<Value, Error> { pub fn call(&self, args: &[Rc<Value>], logs: &mut Vec<String>) -> Result<Value, Error> {
match self { match self {
DefaultFunction::AddInteger => match (&args[0], &args[1]) { DefaultFunction::AddInteger => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(integer1), Value::Con(integer2)) => { (Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) { match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => { (Constant::Integer(arg1), Constant::Integer(arg2)) => {
@ -340,7 +340,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::SubtractInteger => match (&args[0], &args[1]) { DefaultFunction::SubtractInteger => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(integer1), Value::Con(integer2)) => { (Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) { match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => { (Constant::Integer(arg1), Constant::Integer(arg2)) => {
@ -354,7 +354,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::MultiplyInteger => match (&args[0], &args[1]) { DefaultFunction::MultiplyInteger => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(integer1), Value::Con(integer2)) => { (Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) { match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => { (Constant::Integer(arg1), Constant::Integer(arg2)) => {
@ -368,7 +368,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::DivideInteger => match (&args[0], &args[1]) { DefaultFunction::DivideInteger => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(integer1), Value::Con(integer2)) => { (Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) { match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => { (Constant::Integer(arg1), Constant::Integer(arg2)) => {
@ -385,7 +385,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::QuotientInteger => match (&args[0], &args[1]) { DefaultFunction::QuotientInteger => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(integer1), Value::Con(integer2)) => { (Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) { match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => { (Constant::Integer(arg1), Constant::Integer(arg2)) => {
@ -404,7 +404,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::RemainderInteger => match (&args[0], &args[1]) { DefaultFunction::RemainderInteger => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(integer1), Value::Con(integer2)) => { (Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) { match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => { (Constant::Integer(arg1), Constant::Integer(arg2)) => {
@ -421,7 +421,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::ModInteger => match (&args[0], &args[1]) { DefaultFunction::ModInteger => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(integer1), Value::Con(integer2)) => { (Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) { match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => { (Constant::Integer(arg1), Constant::Integer(arg2)) => {
@ -438,7 +438,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::EqualsInteger => match (&args[0], &args[1]) { DefaultFunction::EqualsInteger => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(integer1), Value::Con(integer2)) => { (Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) { match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => { (Constant::Integer(arg1), Constant::Integer(arg2)) => {
@ -449,7 +449,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::LessThanInteger => match (&args[0], &args[1]) { DefaultFunction::LessThanInteger => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(integer1), Value::Con(integer2)) => { (Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) { match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => { (Constant::Integer(arg1), Constant::Integer(arg2)) => {
@ -460,7 +460,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::LessThanEqualsInteger => match (&args[0], &args[1]) { DefaultFunction::LessThanEqualsInteger => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(integer1), Value::Con(integer2)) => { (Value::Con(integer1), Value::Con(integer2)) => {
match (integer1.as_ref(), integer2.as_ref()) { match (integer1.as_ref(), integer2.as_ref()) {
(Constant::Integer(arg1), Constant::Integer(arg2)) => { (Constant::Integer(arg1), Constant::Integer(arg2)) => {
@ -471,7 +471,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::AppendByteString => match (&args[0], &args[1]) { DefaultFunction::AppendByteString => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(byte_string1), Value::Con(byte_string2)) => { (Value::Con(byte_string1), Value::Con(byte_string2)) => {
match (byte_string1.as_ref(), byte_string2.as_ref()) { match (byte_string1.as_ref(), byte_string2.as_ref()) {
(Constant::ByteString(arg1), Constant::ByteString(arg2)) => Ok(Value::Con( (Constant::ByteString(arg1), Constant::ByteString(arg2)) => Ok(Value::Con(
@ -485,7 +485,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::ConsByteString => match (&args[0], &args[1]) { DefaultFunction::ConsByteString => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(integer), Value::Con(byte_string)) => { (Value::Con(integer), Value::Con(byte_string)) => {
match (integer.as_ref(), byte_string.as_ref()) { match (integer.as_ref(), byte_string.as_ref()) {
(Constant::Integer(arg1), Constant::ByteString(arg2)) => { (Constant::Integer(arg1), Constant::ByteString(arg2)) => {
@ -499,27 +499,30 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::SliceByteString => match (&args[0], &args[1], &args[2]) { DefaultFunction::SliceByteString => {
(Value::Con(integer1), Value::Con(integer2), Value::Con(byte_string)) => { match (args[0].as_ref(), args[1].as_ref(), args[2].as_ref()) {
match (integer1.as_ref(), integer2.as_ref(), byte_string.as_ref()) { (Value::Con(integer1), Value::Con(integer2), Value::Con(byte_string)) => {
( match (integer1.as_ref(), integer2.as_ref(), byte_string.as_ref()) {
Constant::Integer(arg1), (
Constant::Integer(arg2), Constant::Integer(arg1),
Constant::ByteString(arg3), Constant::Integer(arg2),
) => { Constant::ByteString(arg3),
let skip = if 0 > *arg1 { 0 } else { *arg1 as usize }; ) => {
let take = if 0 > *arg2 { 0 } else { *arg2 as usize }; let skip = if 0 > *arg1 { 0 } else { *arg1 as usize };
let take = if 0 > *arg2 { 0 } else { *arg2 as usize };
let ret: Vec<u8> = arg3.iter().skip(skip).take(take).cloned().collect(); let ret: Vec<u8> =
arg3.iter().skip(skip).take(take).cloned().collect();
Ok(Value::Con(Constant::ByteString(ret).into())) Ok(Value::Con(Constant::ByteString(ret).into()))
}
_ => unreachable!(),
} }
_ => unreachable!(),
} }
_ => unreachable!(),
} }
_ => unreachable!(), }
}, DefaultFunction::LengthOfByteString => match args[0].as_ref() {
DefaultFunction::LengthOfByteString => match &args[0] {
Value::Con(byte_string) => match byte_string.as_ref() { Value::Con(byte_string) => match byte_string.as_ref() {
Constant::ByteString(arg1) => { Constant::ByteString(arg1) => {
Ok(Value::Con(Constant::Integer(arg1.len() as i128).into())) Ok(Value::Con(Constant::Integer(arg1.len() as i128).into()))
@ -528,7 +531,7 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::IndexByteString => match (&args[0], &args[1]) { DefaultFunction::IndexByteString => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(byte_string), Value::Con(integer)) => { (Value::Con(byte_string), Value::Con(integer)) => {
match (byte_string.as_ref(), integer.as_ref()) { match (byte_string.as_ref(), integer.as_ref()) {
(Constant::ByteString(arg1), Constant::Integer(arg2)) => { (Constant::ByteString(arg1), Constant::Integer(arg2)) => {
@ -547,7 +550,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::EqualsByteString => match (&args[0], &args[1]) { DefaultFunction::EqualsByteString => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(byte_string1), Value::Con(byte_string2)) => { (Value::Con(byte_string1), Value::Con(byte_string2)) => {
match (byte_string1.as_ref(), byte_string2.as_ref()) { match (byte_string1.as_ref(), byte_string2.as_ref()) {
(Constant::ByteString(arg1), Constant::ByteString(arg2)) => { (Constant::ByteString(arg1), Constant::ByteString(arg2)) => {
@ -558,7 +561,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::LessThanByteString => match (&args[0], &args[1]) { DefaultFunction::LessThanByteString => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(byte_string1), Value::Con(byte_string2)) => { (Value::Con(byte_string1), Value::Con(byte_string2)) => {
match (byte_string1.as_ref(), byte_string2.as_ref()) { match (byte_string1.as_ref(), byte_string2.as_ref()) {
(Constant::ByteString(arg1), Constant::ByteString(arg2)) => { (Constant::ByteString(arg1), Constant::ByteString(arg2)) => {
@ -569,7 +572,8 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::LessThanEqualsByteString => match (&args[0], &args[1]) { DefaultFunction::LessThanEqualsByteString => match (args[0].as_ref(), args[1].as_ref())
{
(Value::Con(byte_string1), Value::Con(byte_string2)) => { (Value::Con(byte_string1), Value::Con(byte_string2)) => {
match (byte_string1.as_ref(), byte_string2.as_ref()) { match (byte_string1.as_ref(), byte_string2.as_ref()) {
(Constant::ByteString(arg1), Constant::ByteString(arg2)) => { (Constant::ByteString(arg1), Constant::ByteString(arg2)) => {
@ -580,7 +584,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::Sha2_256 => match &args[0] { DefaultFunction::Sha2_256 => match args[0].as_ref() {
Value::Con(byte_string) => match byte_string.as_ref() { Value::Con(byte_string) => match byte_string.as_ref() {
Constant::ByteString(arg1) => { Constant::ByteString(arg1) => {
use cryptoxide::{digest::Digest, sha2::Sha256}; use cryptoxide::{digest::Digest, sha2::Sha256};
@ -599,7 +603,7 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::Sha3_256 => match &args[0] { DefaultFunction::Sha3_256 => match args[0].as_ref() {
Value::Con(byte_string) => match byte_string.as_ref() { Value::Con(byte_string) => match byte_string.as_ref() {
Constant::ByteString(arg1) => { Constant::ByteString(arg1) => {
use cryptoxide::{digest::Digest, sha3::Sha3_256}; use cryptoxide::{digest::Digest, sha3::Sha3_256};
@ -618,7 +622,7 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::Blake2b_256 => match &args[0] { DefaultFunction::Blake2b_256 => match args[0].as_ref() {
Value::Con(byte_string) => match byte_string.as_ref() { Value::Con(byte_string) => match byte_string.as_ref() {
Constant::ByteString(arg1) => { Constant::ByteString(arg1) => {
use cryptoxide::{blake2b::Blake2b, digest::Digest}; use cryptoxide::{blake2b::Blake2b, digest::Digest};
@ -635,38 +639,40 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::VerifyEd25519Signature => match (&args[0], &args[1], &args[2]) { DefaultFunction::VerifyEd25519Signature => {
(Value::Con(public_key), Value::Con(message), Value::Con(signature)) => { match (args[0].as_ref(), args[1].as_ref(), args[2].as_ref()) {
match (public_key.as_ref(), message.as_ref(), signature.as_ref()) { (Value::Con(public_key), Value::Con(message), Value::Con(signature)) => {
( match (public_key.as_ref(), message.as_ref(), signature.as_ref()) {
Constant::ByteString(public_key), (
Constant::ByteString(message), Constant::ByteString(public_key),
Constant::ByteString(signature), Constant::ByteString(message),
) => { Constant::ByteString(signature),
use cryptoxide::ed25519; ) => {
use cryptoxide::ed25519;
let public_key: [u8; 32] = let public_key: [u8; 32] =
public_key.clone().try_into().map_err(|e: Vec<u8>| { public_key.clone().try_into().map_err(|e: Vec<u8>| {
Error::UnexpectedEd25519PublicKeyLength(e.len()) Error::UnexpectedEd25519PublicKeyLength(e.len())
})?; })?;
let signature: [u8; 64] = let signature: [u8; 64] =
signature.clone().try_into().map_err(|e: Vec<u8>| { signature.clone().try_into().map_err(|e: Vec<u8>| {
Error::UnexpectedEd25519SignatureLength(e.len()) Error::UnexpectedEd25519SignatureLength(e.len())
})?; })?;
let valid = ed25519::verify(message, &public_key, &signature); let valid = ed25519::verify(message, &public_key, &signature);
Ok(Value::Con(Constant::Bool(valid).into())) Ok(Value::Con(Constant::Bool(valid).into()))
}
_ => unreachable!(),
} }
_ => unreachable!(),
} }
_ => unreachable!(),
} }
_ => unreachable!(), }
},
DefaultFunction::VerifyEcdsaSecp256k1Signature => todo!(), DefaultFunction::VerifyEcdsaSecp256k1Signature => todo!(),
DefaultFunction::VerifySchnorrSecp256k1Signature => todo!(), DefaultFunction::VerifySchnorrSecp256k1Signature => todo!(),
DefaultFunction::AppendString => match (&args[0], &args[1]) { DefaultFunction::AppendString => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(string1), Value::Con(string2)) => { (Value::Con(string1), Value::Con(string2)) => {
match (string1.as_ref(), string2.as_ref()) { match (string1.as_ref(), string2.as_ref()) {
(Constant::String(arg1), Constant::String(arg2)) => Ok(Value::Con( (Constant::String(arg1), Constant::String(arg2)) => Ok(Value::Con(
@ -677,7 +683,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::EqualsString => match (&args[0], &args[1]) { DefaultFunction::EqualsString => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(string1), Value::Con(string2)) => { (Value::Con(string1), Value::Con(string2)) => {
match (string1.as_ref(), string2.as_ref()) { match (string1.as_ref(), string2.as_ref()) {
(Constant::String(arg1), Constant::String(arg2)) => { (Constant::String(arg1), Constant::String(arg2)) => {
@ -688,7 +694,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::EncodeUtf8 => match &args[0] { DefaultFunction::EncodeUtf8 => match args[0].as_ref() {
Value::Con(string) => match string.as_ref() { Value::Con(string) => match string.as_ref() {
Constant::String(arg1) => { Constant::String(arg1) => {
let bytes = arg1.as_bytes().to_vec(); let bytes = arg1.as_bytes().to_vec();
@ -699,7 +705,7 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::DecodeUtf8 => match &args[0] { DefaultFunction::DecodeUtf8 => match args[0].as_ref() {
Value::Con(byte_string) => match byte_string.as_ref() { Value::Con(byte_string) => match byte_string.as_ref() {
Constant::ByteString(arg1) => { Constant::ByteString(arg1) => {
let string = String::from_utf8(arg1.clone())?; let string = String::from_utf8(arg1.clone())?;
@ -710,38 +716,38 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::IfThenElse => match &args[0] { DefaultFunction::IfThenElse => match args[0].as_ref() {
Value::Con(boolean) => match boolean.as_ref() { Value::Con(boolean) => match boolean.as_ref() {
Constant::Bool(condition) => { Constant::Bool(condition) => {
if *condition { if *condition {
Ok(args[1].clone()) Ok(args[1].as_ref().clone())
} else { } else {
Ok(args[2].clone()) Ok(args[2].as_ref().clone())
} }
} }
_ => unreachable!(), _ => unreachable!(),
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::ChooseUnit => match &args[0] { DefaultFunction::ChooseUnit => match args[0].as_ref() {
Value::Con(unit) => match unit.as_ref() { Value::Con(unit) => match unit.as_ref() {
Constant::Unit => Ok(args[1].clone()), Constant::Unit => Ok(args[1].as_ref().clone()),
_ => unreachable!(), _ => unreachable!(),
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::Trace => match &args[0] { DefaultFunction::Trace => match args[0].as_ref() {
Value::Con(string) => match string.as_ref() { Value::Con(string) => match string.as_ref() {
Constant::String(arg1) => { Constant::String(arg1) => {
logs.push(arg1.clone()); logs.push(arg1.clone());
Ok(args[1].clone()) Ok(args[1].as_ref().clone())
} }
_ => unreachable!(), _ => unreachable!(),
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::FstPair => match &args[0] { DefaultFunction::FstPair => match args[0].as_ref() {
Value::Con(pair) => match pair.as_ref() { Value::Con(pair) => match pair.as_ref() {
Constant::ProtoPair(_, _, first, _) => { Constant::ProtoPair(_, _, first, _) => {
Ok(Value::Con(first.as_ref().clone().into())) Ok(Value::Con(first.as_ref().clone().into()))
@ -750,7 +756,7 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::SndPair => match &args[0] { DefaultFunction::SndPair => match args[0].as_ref() {
Value::Con(pair) => match pair.as_ref() { Value::Con(pair) => match pair.as_ref() {
Constant::ProtoPair(_, _, _, second) => { Constant::ProtoPair(_, _, _, second) => {
Ok(Value::Con(second.as_ref().clone().into())) Ok(Value::Con(second.as_ref().clone().into()))
@ -759,20 +765,20 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::ChooseList => match &args[0] { DefaultFunction::ChooseList => match args[0].as_ref() {
Value::Con(list) => match list.as_ref() { Value::Con(list) => match list.as_ref() {
Constant::ProtoList(_, list) => { Constant::ProtoList(_, list) => {
if list.is_empty() { if list.is_empty() {
Ok(args[1].clone()) Ok(args[1].as_ref().clone())
} else { } else {
Ok(args[2].clone()) Ok(args[2].as_ref().clone())
} }
} }
_ => unreachable!(), _ => unreachable!(),
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::MkCons => match (&args[0], &args[1]) { DefaultFunction::MkCons => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(item), Value::Con(list)) => match list.as_ref() { (Value::Con(item), Value::Con(list)) => match list.as_ref() {
Constant::ProtoList(r#type, list) => { Constant::ProtoList(r#type, list) => {
let mut ret = vec![item.as_ref().clone()]; let mut ret = vec![item.as_ref().clone()];
@ -784,7 +790,7 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::HeadList => match &args[0] { DefaultFunction::HeadList => match args[0].as_ref() {
c @ Value::Con(list) => match list.as_ref() { c @ Value::Con(list) => match list.as_ref() {
Constant::ProtoList(_, list) => { Constant::ProtoList(_, list) => {
if list.is_empty() { if list.is_empty() {
@ -797,7 +803,7 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::TailList => match &args[0] { DefaultFunction::TailList => match args[0].as_ref() {
c @ Value::Con(list) => match list.as_ref() { c @ Value::Con(list) => match list.as_ref() {
Constant::ProtoList(r#type, list) => { Constant::ProtoList(r#type, list) => {
if list.is_empty() { if list.is_empty() {
@ -812,7 +818,7 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::NullList => match &args[0] { DefaultFunction::NullList => match args[0].as_ref() {
Value::Con(list) => match list.as_ref() { Value::Con(list) => match list.as_ref() {
Constant::ProtoList(_, list) => { Constant::ProtoList(_, list) => {
Ok(Value::Con(Constant::Bool(list.is_empty()).into())) Ok(Value::Con(Constant::Bool(list.is_empty()).into()))
@ -821,18 +827,18 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::ChooseData => match &args[0] { DefaultFunction::ChooseData => match args[0].as_ref() {
Value::Con(con) => match con.as_ref() { Value::Con(con) => match con.as_ref() {
Constant::Data(PlutusData::Constr(_)) => Ok(args[1].clone()), Constant::Data(PlutusData::Constr(_)) => Ok(args[1].as_ref().clone()),
Constant::Data(PlutusData::Map(_)) => Ok(args[2].clone()), Constant::Data(PlutusData::Map(_)) => Ok(args[2].as_ref().clone()),
Constant::Data(PlutusData::Array(_)) => Ok(args[3].clone()), Constant::Data(PlutusData::Array(_)) => Ok(args[3].as_ref().clone()),
Constant::Data(PlutusData::BigInt(_)) => Ok(args[4].clone()), Constant::Data(PlutusData::BigInt(_)) => Ok(args[4].as_ref().clone()),
Constant::Data(PlutusData::BoundedBytes(_)) => Ok(args[5].clone()), Constant::Data(PlutusData::BoundedBytes(_)) => Ok(args[5].as_ref().clone()),
_ => unreachable!(), _ => unreachable!(),
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::ConstrData => match (&args[0], &args[1]) { DefaultFunction::ConstrData => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(integer), Value::Con(list)) => { (Value::Con(integer), Value::Con(list)) => {
match (integer.as_ref(), list.as_ref()) { match (integer.as_ref(), list.as_ref()) {
(Constant::Integer(i), Constant::ProtoList(Type::Data, l)) => { (Constant::Integer(i), Constant::ProtoList(Type::Data, l)) => {
@ -858,7 +864,7 @@ impl DefaultFunction {
} }
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::MapData => match &args[0] { DefaultFunction::MapData => match args[0].as_ref() {
Value::Con(list) => match list.as_ref() { Value::Con(list) => match list.as_ref() {
Constant::ProtoList(_, list) => { Constant::ProtoList(_, list) => {
let mut map = Vec::new(); let mut map = Vec::new();
@ -885,7 +891,7 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::ListData => match &args[0] { DefaultFunction::ListData => match args[0].as_ref() {
Value::Con(list) => match list.as_ref() { Value::Con(list) => match list.as_ref() {
Constant::ProtoList(_, list) => { Constant::ProtoList(_, list) => {
let data_list: Vec<PlutusData> = list let data_list: Vec<PlutusData> = list
@ -904,7 +910,7 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::IData => match &args[0] { DefaultFunction::IData => match args[0].as_ref() {
Value::Con(integer) => match integer.as_ref() { Value::Con(integer) => match integer.as_ref() {
Constant::Integer(i) => Ok(Value::Con( Constant::Integer(i) => Ok(Value::Con(
Constant::Data(PlutusData::BigInt(BigInt::Int((*i).try_into().unwrap()))) Constant::Data(PlutusData::BigInt(BigInt::Int((*i).try_into().unwrap())))
@ -914,7 +920,7 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::BData => match &args[0] { DefaultFunction::BData => match args[0].as_ref() {
Value::Con(byte_string) => match byte_string.as_ref() { Value::Con(byte_string) => match byte_string.as_ref() {
Constant::ByteString(b) => Ok(Value::Con( Constant::ByteString(b) => Ok(Value::Con(
Constant::Data(PlutusData::BoundedBytes(b.clone().try_into().unwrap())) Constant::Data(PlutusData::BoundedBytes(b.clone().try_into().unwrap()))
@ -924,7 +930,7 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::UnConstrData => match &args[0] { DefaultFunction::UnConstrData => match args[0].as_ref() {
Value::Con(con) => match con.as_ref() { Value::Con(con) => match con.as_ref() {
Constant::Data(PlutusData::Constr(c)) => { Constant::Data(PlutusData::Constr(c)) => {
Ok(Value::Con( Ok(Value::Con(
@ -955,7 +961,7 @@ impl DefaultFunction {
v.clone(), v.clone(),
)), )),
}, },
DefaultFunction::UnMapData => match &args[0] { DefaultFunction::UnMapData => match args[0].as_ref() {
Value::Con(data) => match data.as_ref() { Value::Con(data) => match data.as_ref() {
Constant::Data(PlutusData::Map(m)) => Ok(Value::Con( Constant::Data(PlutusData::Map(m)) => Ok(Value::Con(
Constant::ProtoList( Constant::ProtoList(
@ -984,7 +990,7 @@ impl DefaultFunction {
v.clone(), v.clone(),
)), )),
}, },
DefaultFunction::UnListData => match &args[0] { DefaultFunction::UnListData => match args[0].as_ref() {
Value::Con(data) => match data.as_ref() { Value::Con(data) => match data.as_ref() {
Constant::Data(PlutusData::Array(l)) => Ok(Value::Con( Constant::Data(PlutusData::Array(l)) => Ok(Value::Con(
Constant::ProtoList( Constant::ProtoList(
@ -1006,7 +1012,7 @@ impl DefaultFunction {
v.clone(), v.clone(),
)), )),
}, },
DefaultFunction::UnIData => match &args[0] { DefaultFunction::UnIData => match args[0].as_ref() {
Value::Con(data) => match data.as_ref() { Value::Con(data) => match data.as_ref() {
Constant::Data(PlutusData::BigInt(b)) => { Constant::Data(PlutusData::BigInt(b)) => {
if let BigInt::Int(i) = b { if let BigInt::Int(i) = b {
@ -1027,7 +1033,7 @@ impl DefaultFunction {
v.clone(), v.clone(),
)), )),
}, },
DefaultFunction::UnBData => match &args[0] { DefaultFunction::UnBData => match args[0].as_ref() {
Value::Con(data) => match data.as_ref() { Value::Con(data) => match data.as_ref() {
Constant::Data(PlutusData::BoundedBytes(b)) => { Constant::Data(PlutusData::BoundedBytes(b)) => {
Ok(Value::Con(Constant::ByteString(b.to_vec()).into())) Ok(Value::Con(Constant::ByteString(b.to_vec()).into()))
@ -1042,7 +1048,7 @@ impl DefaultFunction {
v.clone(), v.clone(),
)), )),
}, },
DefaultFunction::EqualsData => match (&args[0], &args[1]) { DefaultFunction::EqualsData => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(data1), Value::Con(data2)) => match (data1.as_ref(), data2.as_ref()) { (Value::Con(data1), Value::Con(data2)) => match (data1.as_ref(), data2.as_ref()) {
(Constant::Data(d1), Constant::Data(d2)) => { (Constant::Data(d1), Constant::Data(d2)) => {
Ok(Value::Con(Constant::Bool(d1.eq(d2)).into())) Ok(Value::Con(Constant::Bool(d1.eq(d2)).into()))
@ -1051,7 +1057,7 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::SerialiseData => match &args[0] { DefaultFunction::SerialiseData => match args[0].as_ref() {
Value::Con(data) => match data.as_ref() { Value::Con(data) => match data.as_ref() {
Constant::Data(d) => { Constant::Data(d) => {
let serialized_data = plutus_data_to_bytes(d).unwrap(); let serialized_data = plutus_data_to_bytes(d).unwrap();
@ -1061,7 +1067,7 @@ impl DefaultFunction {
}, },
_ => unreachable!(), _ => unreachable!(),
}, },
DefaultFunction::MkPairData => match (&args[0], &args[1]) { DefaultFunction::MkPairData => match (args[0].as_ref(), args[1].as_ref()) {
(Value::Con(data1), Value::Con(data2)) => match (data1.as_ref(), data2.as_ref()) { (Value::Con(data1), Value::Con(data2)) => match (data1.as_ref(), data2.as_ref()) {
(Constant::Data(d1), Constant::Data(d2)) => Ok(Value::Con( (Constant::Data(d1), Constant::Data(d2)) => Ok(Value::Con(
Constant::ProtoPair( Constant::ProtoPair(