Skip to content

Commit b7101cc

Browse files
runtime/stdlib: Refactor to simplify conversions
- Use the new `impl_simple_into_value` macro in more places - Implement Into<Value> for any Into<Array> type - Implement FromIterator for Array/Value - Utilize conversion traits where possible
1 parent 25db3ee commit b7101cc

File tree

11 files changed

+163
-210
lines changed

11 files changed

+163
-210
lines changed

src/macros.rs

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,29 +86,18 @@ macro_rules! impl_simple_to_value {
8686
}
8787
};
8888
}
89-
macro_rules! impl_simple_to_array {
90-
($src:ty, $var:tt, $expr:expr) => {
91-
impl_simple_to_value!($src, $var, Value::array_of($expr));
92-
};
93-
}
94-
macro_rules! impl_simple_iter_to_array {
95-
($src:ty, $var:tt, $expr:expr) => {
96-
impl_simple_to_value!($src, $var, Array($expr.map(Into::into).collect()));
97-
};
98-
}
99-
10089
macro_rules! add_tags {
10190
($struct:ident, $tags:tt, $($field:ident),+) => {
10291
$tags.extend([$(
103-
Value::array_of((stringify!($field), $struct.$field))
92+
(stringify!($field), $struct.$field).into()
10493
),+]);
10594
};
10695
}
10796
macro_rules! add_opt_tags {
10897
($struct:ident, $tags:tt, $($field:ident),+) => {
10998
$(
11099
if let Some(val) = $struct.$field {
111-
$tags.push(Value::array_of((stringify!($field), val)));
100+
$tags.push((stringify!($field), val).into());
112101
}
113102
)+
114103
};

src/runtime/array.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
22
use std::convert::{TryFrom, TryInto};
3+
use std::iter::FromIterator;
34
use std::{fmt, mem, ops, vec};
45

56
use crate::runtime::{Error, FieldAccess, FromValue, Result, Value};
@@ -165,6 +166,13 @@ impl IntoIterator for Array {
165166
}
166167
}
167168

169+
// Generic conversion from an iterator of any convertible type into an Array
170+
impl<V: Into<Value>> FromIterator<V> for Array {
171+
fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
172+
Self(iter.into_iter().map(Into::into).collect())
173+
}
174+
}
175+
168176
// Generic conversion from 1/2/3/4-tuples of any convertible type into an Array
169177
impl<A: Into<Value>> From<(A,)> for Array {
170178
fn from((a,): (A,)) -> Self {
@@ -189,18 +197,13 @@ impl<A: Into<Value>, B: Into<Value>, C: Into<Value>, D: Into<Value>> From<(A, B,
189197

190198
// Generic conversion from native set types into Array
191199
impl<T: Into<Value>> From<Vec<T>> for Array {
192-
fn from(value: Vec<T>) -> Self {
193-
Array(value.into_iter().map(Into::into).collect())
200+
fn from(vec: Vec<T>) -> Self {
201+
Array::from_iter(vec)
194202
}
195203
}
196204
impl<K: Into<Value>, V: Into<Value>> From<BTreeMap<K, V>> for Array {
197-
fn from(value: BTreeMap<K, V>) -> Self {
198-
Array(
199-
value
200-
.into_iter()
201-
.map(|(k, v)| Value::array_of((k, v)))
202-
.collect(),
203-
)
205+
fn from(map: BTreeMap<K, V>) -> Self {
206+
Array::from_iter(map)
204207
}
205208
}
206209

src/runtime/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ impl Execute for ast::Assign {
4545
impl Execute for ast::FnDef {
4646
fn exec(&self, scope: &ScopeRef<Mutable>) -> Result<()> {
4747
let func = Function::from_def(self.clone(), scope.as_readonly());
48-
scope.borrow_mut().set(self.ident.clone(), func)
48+
scope
49+
.borrow_mut()
50+
.set(self.ident.clone(), Value::function(func))
4951
}
5052
}
5153

@@ -258,7 +260,7 @@ impl FieldAccess for Value {
258260
impl Evaluate for ast::FnExpr {
259261
fn eval(&self, scope: &ScopeRef) -> Result<Value> {
260262
let func = Function::from_expr(self.clone(), scope.make_ref());
261-
Ok(func.into())
263+
Ok(Value::function(func))
262264
}
263265
}
264266

src/runtime/scope.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ impl Scope {
4343
pub fn set_fn<K: Into<Ident>>(&mut self, key: K, pt: NativeFunctionPt) -> Result<()> {
4444
let key = key.into();
4545
let func = NativeFunction::new(pt, Some(key.clone()));
46-
self.set(key, func)
46+
self.set(key, Value::function(func))
4747
}
4848

4949
/// Get a builtin variable, which must be available in scope

src/runtime/value.rs

Lines changed: 21 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -63,44 +63,25 @@ pub struct Symbol {
6363
// Value conversions
6464
//
6565

66-
// From primitive numbers to Value
67-
impl From<i64> for Value {
68-
fn from(n: i64) -> Value {
69-
Number::Int(n).into()
70-
}
71-
}
72-
impl From<f64> for Value {
73-
fn from(n: f64) -> Value {
74-
Number::Float(n).into()
75-
}
76-
}
77-
impl From<u32> for Value {
78-
fn from(num: u32) -> Value {
79-
(num as i64).into()
80-
}
81-
}
82-
impl From<i32> for Value {
83-
fn from(num: i32) -> Value {
84-
(num as i64).into()
85-
}
86-
}
87-
impl From<usize> for Value {
88-
fn from(num: usize) -> Value {
89-
// TODO this should use TryFrom
90-
Number::Int(num.try_into().unwrap()).into()
91-
}
92-
}
66+
// From primitive types to Value
67+
impl_simple_to_value!(i64, n, Number::Int(n));
68+
impl_simple_to_value!(f64, n, Number::Float(n));
69+
impl_simple_to_value!(u32, n, n as i64);
70+
impl_simple_to_value!(i32, n, n as i64);
71+
impl_simple_to_value!(usize, n, i64::try_from(n).unwrap()); // XXX should not panic
72+
impl_simple_to_value!(&str, s, s.to_string());
73+
9374
impl TryFrom<u64> for Value {
9475
type Error = Error;
9576
fn try_from(num: u64) -> Result<Self> {
9677
Ok(Value::Number(Number::Int(num.try_into()?)))
9778
}
9879
}
9980

100-
// From NativeFunction/UserFunction to Value
101-
impl<T: Into<Function>> From<T> for Value {
81+
// From any Into<Array> type to Value
82+
impl<T: Into<Array>> From<T> for Value {
10283
fn from(f: T) -> Self {
103-
Value::Function(f.into())
84+
Value::Array(f.into())
10485
}
10586
}
10687

@@ -109,7 +90,6 @@ impl_from_variant!(bool, Value, Bool);
10990
impl_from_variant!(Number, Value);
11091
impl_from_variant!(String, Value);
11192
impl_from_variant!(Vec<u8>, Value, Bytes);
112-
impl_from_variant!(Array, Value);
11393
impl_from_variant!(Symbol, Value);
11494
impl_from_variant!(Policy, Value);
11595
impl_from_variant!(Descriptor, Value);
@@ -123,12 +103,6 @@ impl_from_variant!(TaprootSpendInfo, Value, TapInfo);
123103
impl_from_variant!(WshScript, Value);
124104
impl_from_variant!(Psbt, Value);
125105

126-
impl From<&str> for Value {
127-
fn from(s: &str) -> Self {
128-
Value::String(s.to_string())
129-
}
130-
}
131-
132106
// From Value to the underlying enum inner type
133107
// Simple extraction of the enum variant, with no specialized type coercion logic
134108
impl_simple_into_variant!(bool, Bool, into_bool, NotBool);
@@ -138,6 +112,7 @@ impl_simple_into_variant!(Function, Function, into_fn, NotFn);
138112
impl_simple_into_variant!(String, String, into_string, NotString);
139113
impl_simple_into_variant!(WshScript, WshScript, into_wsh_script, NotWshScript);
140114

115+
141116
// From Value to f64 primitive, with auto-coercion for integers
142117
impl TryFrom<Value> for f64 {
143118
type Error = Error;
@@ -310,23 +285,6 @@ impl_delegate_array_conv!((A, ), A: FromValue);
310285
impl_delegate_array_conv!((A, B), A: FromValue, B: FromValue);
311286
impl_delegate_array_conv!((A, B, C), A: FromValue, B: FromValue, C: FromValue);
312287

313-
// Generic conversion from sets into a Value
314-
impl<A: Into<Value>, B: Into<Value>> From<(A, B)> for Value {
315-
fn from(value: (A, B)) -> Self {
316-
Value::Array(value.into())
317-
}
318-
}
319-
impl<T: Into<Value>> From<Vec<T>> for Value {
320-
fn from(value: Vec<T>) -> Self {
321-
Value::Array(value.into())
322-
}
323-
}
324-
impl<K: Into<Value>, V: Into<Value>> From<BTreeMap<K, V>> for Value {
325-
fn from(value: BTreeMap<K, V>) -> Self {
326-
Value::Array(value.into())
327-
}
328-
}
329-
330288
//
331289
// Value impl
332290
//
@@ -421,8 +379,15 @@ impl Value {
421379
pub fn array(elements: Vec<Value>) -> Self {
422380
Value::Array(Array(elements))
423381
}
424-
pub fn array_of(array: impl Into<Array>) -> Self {
425-
Value::Array(array.into())
382+
383+
pub fn function(func: impl Into<Function>) -> Self {
384+
Value::Function(func.into())
385+
}
386+
}
387+
388+
impl<V: Into<Value>> std::iter::FromIterator<V> for Value {
389+
fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
390+
Array::from_iter(iter).into()
426391
}
427392
}
428393

src/stdlib/btc.rs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ pub struct WshScript(pub ScriptBuf);
7676
impl Evaluate for ast::BtcAmount {
7777
fn eval(&self, scope: &ScopeRef) -> Result<Value> {
7878
let amount_n = self.0.eval(scope)?.into_f64()?;
79-
let amount = SignedAmount::from_float_in(amount_n, self.1)?;
80-
Ok(Value::from(amount.to_sat()))
79+
Ok(SignedAmount::from_float_in(amount_n, self.1)?.into())
8180
}
8281
}
8382

@@ -474,17 +473,23 @@ impl TryFrom<Value> for Witness {
474473
impl_simple_to_value!(Version, ver, ver.0);
475474
impl_simple_to_value!(Sequence, seq, seq.to_consensus_u32());
476475
impl_simple_to_value!(AbsLockTime, time, time.to_consensus_u32());
477-
impl_simple_to_array!(OutPoint, outpoint, (outpoint.txid, outpoint.vout));
478-
impl_simple_iter_to_array!(Witness, wit, wit.to_vec().into_iter());
479-
impl_simple_to_array!(
476+
impl_simple_to_value!(OutPoint, outpoint, (outpoint.txid, outpoint.vout));
477+
impl_simple_to_value!(Witness, wit, wit.to_vec());
478+
impl_simple_to_value!(SignedAmount, amt, amt.to_sat());
479+
// Panics for out-of-range `Amount`s (i64 can represent up to ~92 billion BTC, ~4400x more than can exists),
480+
// which should be impossible to construct within Minsc (but can be passed from Rust code).
481+
// Uses to_signed() to convert from u64 to i64 with a useful OutOfRangeError message.
482+
impl_simple_to_value!(Amount, amt, amt.to_signed().unwrap());
483+
484+
impl_simple_to_value!(
480485
bitcoin::transaction::TxOut,
481486
txout,
482487
(
483488
("script_pubkey", txout.script_pubkey),
484-
("amount", i64::try_from(txout.value.to_sat()).unwrap()),
489+
("amount", txout.value),
485490
)
486491
);
487-
impl_simple_to_array!(
492+
impl_simple_to_value!(
488493
bitcoin::transaction::TxIn,
489494
txin,
490495
(
@@ -501,15 +506,26 @@ impl_simple_to_value!(Txid, txid, {
501506
txid.reverse();
502507
txid
503508
});
509+
// Panics for out-of-range `Weight`s, which should be impossible to construct
510+
impl_simple_to_value!(
511+
bitcoin::Weight,
512+
w,
513+
i64::try_from(w.to_wu()).expect("out of range weight")
514+
);
504515

505516
// Transaction fields accessors
506517
impl FieldAccess for Transaction {
507518
fn get_field(self, field: &Value) -> Option<Value> {
508519
Some(match field.as_str()? {
509520
"version" => self.version.into(),
510-
"lock_time" => self.lock_time.into(),
511-
"input" | "inputs" => Value::array_of(self.input),
512-
"output" | "outputs" => Value::array_of(self.output),
521+
"locktime" => self.lock_time.into(),
522+
"input" | "inputs" => self.input.into(),
523+
"output" | "outputs" => self.output.into(),
524+
525+
"txid" => self.compute_txid().into(),
526+
"weight" => self.weight().into(),
527+
"vsize" => self.vsize().into(),
528+
"size" => self.total_size().into(),
513529
_ => {
514530
return None;
515531
}

src/stdlib/crypto.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,6 @@ pub mod fns {
9090
} else {
9191
EC.sign_schnorr_no_aux_rand(&msg, &keypair)
9292
}
93-
.serialize()
94-
.to_vec()
9593
.into())
9694
}
9795

@@ -156,6 +154,8 @@ impl TryFrom<Value> for bitcoin::ecdsa::Signature {
156154

157155
// Convert from native types to Value
158156
impl_simple_to_value!(bitcoin::ecdsa::Signature, sig, sig.to_vec());
157+
impl_simple_to_value!(secp256k1::schnorr::Signature, sig, sig.serialize().to_vec());
158+
impl_simple_to_value!(secp256k1::Message, msg, msg[..].to_vec());
159159

160160
// Convert Value <-> Hash types
161161
macro_rules! impl_hash_conv {

0 commit comments

Comments
 (0)