Skip to content

Commit 0a33c05

Browse files
committed
add utils and numeric ops for Value
1 parent 23eb5df commit 0a33c05

File tree

6 files changed

+342
-1
lines changed

6 files changed

+342
-1
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ true = { version = "0.1.0", optional = true }
1717
data-encoding = { version = "2.4.0", optional = true }
1818
thiserror = "1.0.50"
1919
linked-hash-map = "0.5.6"
20+
num-traits = "0.2.17"
2021

2122
[features]
2223
serde = ["dep:serde", "num-bigint/serde"]

src/utils.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use std::iter::{empty, once};
1+
use std::{
2+
collections::BTreeMap,
3+
iter::{empty, once},
4+
};
25

36
/// Create a container C from one element.
47
pub fn singleton<T, C>(value: T) -> C
@@ -15,3 +18,18 @@ where
1518
{
1619
empty::<T>().collect()
1720
}
21+
22+
pub fn union_b_tree_maps_with<const N: usize, K: Clone + Ord, V: Clone, F: Fn(&V, &V) -> V>(
23+
f: F,
24+
maps: [&BTreeMap<K, V>; N],
25+
) -> BTreeMap<K, V> {
26+
maps.into_iter().fold(BTreeMap::new(), |acc, m| {
27+
m.into_iter().fold(acc, |mut acc, (k, v)| {
28+
acc.entry(k.clone())
29+
.and_modify(|va: &mut V| *va = f(va, v))
30+
.or_insert(v.clone());
31+
32+
acc
33+
})
34+
})
35+
}

src/v1/value/macros.rs

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#![allow(unused_macros)]
2+
3+
macro_rules! forward_val_val_binop {
4+
(impl $imp:ident for $res:ty, $method:ident) => {
5+
impl $imp<$res> for $res {
6+
type Output = $res;
7+
8+
#[inline]
9+
fn $method(self, other: $res) -> $res {
10+
// forward to val-ref
11+
$imp::$method(self, &other)
12+
}
13+
}
14+
};
15+
}
16+
17+
macro_rules! forward_ref_val_binop {
18+
(impl $imp:ident for $res:ty, $method:ident) => {
19+
impl $imp<$res> for &$res {
20+
type Output = $res;
21+
22+
#[inline]
23+
fn $method(self, other: $res) -> $res {
24+
// forward to ref-ref
25+
$imp::$method(self, &other)
26+
}
27+
}
28+
};
29+
}
30+
31+
macro_rules! forward_val_ref_binop {
32+
(impl $imp:ident for $res:ty, $method:ident) => {
33+
impl $imp<&$res> for $res {
34+
type Output = $res;
35+
36+
#[inline]
37+
fn $method(self, other: &$res) -> $res {
38+
// forward to ref-ref
39+
$imp::$method(&self, other)
40+
}
41+
}
42+
};
43+
}
44+
45+
macro_rules! forward_scalar_val_val_binop_to_ref_val {
46+
(impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
47+
impl $imp<$scalar> for $res {
48+
type Output = $res;
49+
50+
#[inline]
51+
fn $method(self, other: $scalar) -> $res {
52+
$imp::$method(&self, other)
53+
}
54+
}
55+
56+
impl $imp<$res> for $scalar {
57+
type Output = $res;
58+
59+
#[inline]
60+
fn $method(self, other: $res) -> $res {
61+
$imp::$method(self, &other)
62+
}
63+
}
64+
};
65+
}
66+
67+
macro_rules! forward_scalar_ref_val_binop_to_ref_ref {
68+
(impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
69+
impl $imp<$scalar> for &$res {
70+
type Output = $res;
71+
72+
#[inline]
73+
fn $method(self, other: $scalar) -> $res {
74+
$imp::$method(self, &other)
75+
}
76+
}
77+
78+
impl $imp<$res> for &$scalar {
79+
type Output = $res;
80+
81+
#[inline]
82+
fn $method(self, other: $res) -> $res {
83+
$imp::$method(self, &other)
84+
}
85+
}
86+
};
87+
}
88+
89+
macro_rules! forward_scalar_val_ref_binop_to_ref_val {
90+
(impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
91+
impl $imp<&$scalar> for $res {
92+
type Output = $res;
93+
94+
#[inline]
95+
fn $method(self, other: &$scalar) -> $res {
96+
$imp::$method(&self, other)
97+
}
98+
}
99+
100+
impl $imp<&$res> for $scalar {
101+
type Output = $res;
102+
103+
#[inline]
104+
fn $method(self, other: &$res) -> $res {
105+
$imp::$method(&self, other)
106+
}
107+
}
108+
};
109+
}
110+
111+
macro_rules! forward_scalar_ref_ref_binop_commutative {
112+
(impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
113+
impl $imp<&$res> for &$scalar {
114+
type Output = $res;
115+
116+
#[inline]
117+
fn $method(self, other: &$res) -> $res {
118+
$imp::$method(other, self)
119+
}
120+
}
121+
};
122+
}
123+
124+
macro_rules! forward_into_bigint_scalar_ref_val_binop_to_ref_ref {
125+
(impl $imp:ident<$scalar:ty> for $res:ty, $method:ident) => {
126+
impl $imp<$scalar> for &$res {
127+
type Output = $res;
128+
129+
#[inline]
130+
fn $method(self, other: $scalar) -> $res {
131+
$imp::$method(self, &BigInt::from(other))
132+
}
133+
}
134+
135+
impl $imp<&$res> for $scalar {
136+
type Output = $res;
137+
138+
#[inline]
139+
fn $method(self, other: &$res) -> $res {
140+
$imp::$method(&BigInt::from(self), other)
141+
}
142+
}
143+
};
144+
}

src/v1/value.rs renamed to src/v1/value/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
use crate::plutus_data::{
33
verify_constr_fields, IsPlutusData, PlutusData, PlutusDataError, PlutusType,
44
};
5+
56
use crate::v1::crypto::LedgerBytes;
67
use crate::v1::script::{MintingPolicyHash, ScriptHash};
78
#[cfg(feature = "lbf")]
@@ -12,6 +13,9 @@ use serde::{Deserialize, Serialize};
1213
#[cfg(feature = "lbf")]
1314
use serde_json;
1415
use std::collections::BTreeMap;
16+
#[macro_use]
17+
mod macros;
18+
mod value_utils;
1519

1620
/// Identifier of a currency, which could be either Ada (or tAda), or a native token represented by
1721
/// it's minting policy hash. A currency may be associated with multiple `AssetClass`es.

src/v1/value/value_utils.rs

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
use crate::utils::{singleton, union_b_tree_maps_with};
2+
use num_bigint::BigInt;
3+
use num_traits::Zero;
4+
use std::{
5+
collections::BTreeMap,
6+
ops::{Add, Mul, Not, Sub},
7+
};
8+
9+
use super::{CurrencySymbol, TokenName, Value};
10+
11+
impl Value {
12+
pub fn ada_value(amount: &BigInt) -> Self {
13+
Self::token_value(&CurrencySymbol::Ada, &TokenName::ada(), amount)
14+
}
15+
16+
pub fn token_value(cs: &CurrencySymbol, tn: &TokenName, amount: &BigInt) -> Self {
17+
Value(singleton((
18+
cs.clone(),
19+
singleton((tn.clone(), amount.clone())),
20+
)))
21+
}
22+
23+
pub fn get_token_amount(&self, cs: &CurrencySymbol, tn: &TokenName) -> BigInt {
24+
self.0
25+
.get(cs)
26+
.and_then(|tn_map| tn_map.get(&tn))
27+
.map_or(BigInt::zero(), Clone::clone)
28+
}
29+
30+
pub fn get_ada_amount(&self) -> BigInt {
31+
self.get_token_amount(&CurrencySymbol::Ada, &TokenName::ada())
32+
}
33+
34+
pub fn insert_token(&self, cs: &CurrencySymbol, tn: &TokenName, a: &BigInt) -> Self {
35+
let mut result_map = self.0.clone();
36+
37+
result_map
38+
.entry(cs.clone())
39+
.and_modify(|tn_map| {
40+
tn_map
41+
.entry(tn.clone())
42+
.and_modify(|old_a| {
43+
*old_a = a.clone();
44+
})
45+
.or_insert_with(|| a.clone());
46+
})
47+
.or_insert_with(|| singleton((tn.clone(), a.clone())));
48+
49+
Self(result_map)
50+
}
51+
52+
pub fn is_empty(&self) -> bool {
53+
self.0.is_empty()
54+
}
55+
56+
pub fn normalize(&self) -> Self {
57+
self.filter_map_amount(|_, _, a| a.is_zero().not().then(|| a.clone()))
58+
}
59+
60+
pub fn map_amount<F>(&self, mut f: F) -> Self
61+
where
62+
F: FnMut(&CurrencySymbol, &TokenName, &BigInt) -> BigInt,
63+
{
64+
self.filter_map_amount(|cs, tn, a| Some(f(cs, tn, a)))
65+
}
66+
67+
pub fn filter_map_amount<F>(&self, mut f: F) -> Self
68+
where
69+
F: FnMut(&CurrencySymbol, &TokenName, &BigInt) -> Option<BigInt>,
70+
{
71+
Value(
72+
(&self.0)
73+
.into_iter()
74+
.filter_map(|(cs, tn_map)| {
75+
let filtered_tn_map = tn_map
76+
.into_iter()
77+
.filter_map(|(tn, a)| f(cs, tn, a).map(|a| (tn.clone(), a)))
78+
.collect::<BTreeMap<TokenName, BigInt>>();
79+
80+
if filtered_tn_map.is_empty() {
81+
None
82+
} else {
83+
Some((cs.clone(), filtered_tn_map))
84+
}
85+
})
86+
.collect(),
87+
)
88+
}
89+
}
90+
91+
impl Default for Value {
92+
fn default() -> Self {
93+
Self(BTreeMap::new())
94+
}
95+
}
96+
97+
impl Zero for Value {
98+
fn zero() -> Self {
99+
Default::default()
100+
}
101+
102+
fn is_zero(&self) -> bool {
103+
self.is_empty()
104+
}
105+
}
106+
107+
forward_val_val_binop!(impl Add for Value, add);
108+
forward_ref_val_binop!(impl Add for Value, add);
109+
forward_val_ref_binop!(impl Add for Value, add);
110+
111+
impl Add<&Value> for &Value {
112+
type Output = Value;
113+
114+
fn add(self, rhs: &Value) -> Self::Output {
115+
Value(union_b_tree_maps_with(
116+
|lhs, rhs| union_b_tree_maps_with(|lhs, rhs| lhs + rhs, [lhs, rhs]),
117+
[&self.0, &rhs.0],
118+
))
119+
}
120+
}
121+
122+
forward_val_val_binop!(impl Sub for Value, sub);
123+
forward_ref_val_binop!(impl Sub for Value, sub);
124+
forward_val_ref_binop!(impl Sub for Value, sub);
125+
126+
impl Sub<&Value> for &Value {
127+
type Output = Value;
128+
129+
fn sub(self, rhs: &Value) -> Self::Output {
130+
Value(union_b_tree_maps_with(
131+
|lhs, rhs| union_b_tree_maps_with(|lhs, rhs| lhs - rhs, [lhs, rhs]),
132+
[&self.0, &rhs.0],
133+
))
134+
}
135+
}
136+
137+
forward_scalar_val_val_binop_to_ref_val!(impl Mul<BigInt> for Value, mul);
138+
forward_scalar_ref_val_binop_to_ref_ref!(impl Mul<BigInt> for Value, mul);
139+
forward_scalar_val_ref_binop_to_ref_val!(impl Mul<BigInt> for Value, mul);
140+
forward_scalar_ref_ref_binop_commutative!(impl Mul<BigInt> for Value, mul);
141+
142+
forward_into_bigint_scalar_ref_val_binop_to_ref_ref!(impl Mul<i8> for Value, mul);
143+
forward_into_bigint_scalar_ref_val_binop_to_ref_ref!(impl Mul<i16> for Value, mul);
144+
forward_into_bigint_scalar_ref_val_binop_to_ref_ref!(impl Mul<i32> for Value, mul);
145+
forward_into_bigint_scalar_ref_val_binop_to_ref_ref!(impl Mul<i64> for Value, mul);
146+
forward_into_bigint_scalar_ref_val_binop_to_ref_ref!(impl Mul<i128> for Value, mul);
147+
148+
forward_into_bigint_scalar_ref_val_binop_to_ref_ref!(impl Mul<u8> for Value, mul);
149+
forward_into_bigint_scalar_ref_val_binop_to_ref_ref!(impl Mul<u16> for Value, mul);
150+
forward_into_bigint_scalar_ref_val_binop_to_ref_ref!(impl Mul<u32> for Value, mul);
151+
forward_into_bigint_scalar_ref_val_binop_to_ref_ref!(impl Mul<u64> for Value, mul);
152+
forward_into_bigint_scalar_ref_val_binop_to_ref_ref!(impl Mul<u128> for Value, mul);
153+
154+
impl Mul<&BigInt> for &Value {
155+
type Output = Value;
156+
157+
fn mul(self, rhs: &BigInt) -> Self::Output {
158+
Value(
159+
(&self.0)
160+
.into_iter()
161+
.map(|(cs, tn_map)| {
162+
(
163+
cs.clone(),
164+
tn_map
165+
.into_iter()
166+
.map(|(tn, q)| (tn.clone(), q * rhs))
167+
.collect(),
168+
)
169+
})
170+
.collect(),
171+
)
172+
}
173+
}

0 commit comments

Comments
 (0)