|
1 | 1 | use std::fmt::{self, Debug}; |
2 | 2 | use std::sync::Arc; |
3 | 3 |
|
4 | | -use super::value::TryFromValue; |
5 | | -use super::{Context, Error, Set, Value}; |
| 4 | +use ecow::eco_vec; |
| 5 | + |
| 6 | +use super::{Context, Error, Set, TryFromValue, Type, Value}; |
6 | 7 |
|
7 | 8 | /// The backing implementation for a [`Func`]. |
8 | 9 | type FuncImpl = Arc<dyn Fn(&Context, &[Value]) -> Result<Value, Error>>; |
@@ -35,150 +36,167 @@ impl Debug for Func { |
35 | 36 | impl Func { |
36 | 37 | /// Constructor for [`Set::built_in_all`]. |
37 | 38 | pub fn built_in_all(ctx: &Context, args: &[Value]) -> Result<Value, Error> { |
38 | | - expect_no_args("all", ctx, args)?; |
| 39 | + Self::expect_no_args("all", ctx, args)?; |
39 | 40 | Ok(Value::Set(Set::built_in_all())) |
40 | 41 | } |
41 | 42 |
|
42 | 43 | /// Constructor for [`Set::built_in_none`]. |
43 | 44 | pub fn built_in_none(ctx: &Context, args: &[Value]) -> Result<Value, Error> { |
44 | | - expect_no_args("none", ctx, args)?; |
| 45 | + Self::expect_no_args("none", ctx, args)?; |
45 | 46 | Ok(Value::Set(Set::built_in_none())) |
46 | 47 | } |
47 | 48 |
|
48 | 49 | /// Constructor for [`Set::built_in_skip`]. |
49 | 50 | pub fn built_in_skip(ctx: &Context, args: &[Value]) -> Result<Value, Error> { |
50 | | - expect_no_args("skip", ctx, args)?; |
| 51 | + Self::expect_no_args("skip", ctx, args)?; |
51 | 52 | Ok(Value::Set(Set::built_in_skip())) |
52 | 53 | } |
53 | 54 |
|
54 | 55 | /// Constructor for [`Set::built_in_compile_only`]. |
55 | 56 | pub fn built_in_compile_only(ctx: &Context, args: &[Value]) -> Result<Value, Error> { |
56 | | - expect_no_args("compile-only", ctx, args)?; |
| 57 | + Self::expect_no_args("compile-only", ctx, args)?; |
57 | 58 | Ok(Value::Set(Set::built_in_compile_only())) |
58 | 59 | } |
59 | 60 |
|
60 | 61 | /// Constructor for [`Set::built_in_ephemeral`]. |
61 | 62 | pub fn built_in_ephemeral(ctx: &Context, args: &[Value]) -> Result<Value, Error> { |
62 | | - expect_no_args("ephemeral", ctx, args)?; |
| 63 | + Self::expect_no_args("ephemeral", ctx, args)?; |
63 | 64 | Ok(Value::Set(Set::built_in_ephemeral())) |
64 | 65 | } |
65 | 66 |
|
66 | 67 | /// Constructor for [`Set::built_in_persistent`]. |
67 | 68 | pub fn built_in_persistent(ctx: &Context, args: &[Value]) -> Result<Value, Error> { |
68 | | - expect_no_args("persistent", ctx, args)?; |
| 69 | + Self::expect_no_args("persistent", ctx, args)?; |
69 | 70 | Ok(Value::Set(Set::built_in_persistent())) |
70 | 71 | } |
71 | 72 | } |
72 | 73 |
|
73 | | -/// Ensure there are no args. |
74 | | -pub fn expect_no_args(id: &str, _ctx: &Context, args: &[Value]) -> Result<(), Error> { |
75 | | - if args.is_empty() { |
76 | | - Ok(()) |
77 | | - } else { |
78 | | - Err(Error::InvalidArgumentCount { |
79 | | - func: id.into(), |
80 | | - expected: 0, |
81 | | - is_min: false, |
82 | | - found: args.len(), |
83 | | - }) |
| 74 | +impl Func { |
| 75 | + /// Ensure there are no args. |
| 76 | + pub fn expect_no_args(id: &str, _ctx: &Context, args: &[Value]) -> Result<(), Error> { |
| 77 | + if args.is_empty() { |
| 78 | + Ok(()) |
| 79 | + } else { |
| 80 | + Err(Error::InvalidArgumentCount { |
| 81 | + func: id.into(), |
| 82 | + expected: 0, |
| 83 | + is_min: false, |
| 84 | + found: args.len(), |
| 85 | + }) |
| 86 | + } |
84 | 87 | } |
85 | | -} |
86 | 88 |
|
87 | | -// TODO(tinger): see test_set module todo |
88 | | - |
89 | | -/// Extract an exact number of values from the given arguments. Validates the |
90 | | -/// types of all arguments. |
91 | | -#[allow(dead_code)] |
92 | | -pub fn expect_args_exact<T: TryFromValue + Debug, const N: usize>( |
93 | | - func: &str, |
94 | | - _ctx: &Context, |
95 | | - args: &[Value], |
96 | | -) -> Result<[T; N], Error> { |
97 | | - if args.len() < N { |
98 | | - return Err(Error::InvalidArgumentCount { |
99 | | - func: func.into(), |
100 | | - expected: N, |
101 | | - is_min: false, |
102 | | - found: args.len(), |
103 | | - }); |
| 89 | + /// Extract an exact number of values from the given arguments. Validates the |
| 90 | + /// types of all arguments. |
| 91 | + pub fn expect_args_exact<T: TryFromValue + Debug, const N: usize>( |
| 92 | + func: &str, |
| 93 | + _ctx: &Context, |
| 94 | + args: &[Value], |
| 95 | + ) -> Result<[T; N], Error> { |
| 96 | + if args.len() < N { |
| 97 | + return Err(Error::InvalidArgumentCount { |
| 98 | + func: func.into(), |
| 99 | + expected: N, |
| 100 | + is_min: false, |
| 101 | + found: args.len(), |
| 102 | + }); |
| 103 | + } |
| 104 | + |
| 105 | + Ok(args |
| 106 | + .iter() |
| 107 | + .take(N) |
| 108 | + .map(T::try_from_value) |
| 109 | + .collect::<Result<Vec<_>, _>>()? |
| 110 | + .try_into() |
| 111 | + .expect("we checked both min and max of the args")) |
104 | 112 | } |
105 | 113 |
|
106 | | - Ok(args |
107 | | - .iter() |
108 | | - .take(N) |
109 | | - .map(T::try_from_value) |
110 | | - .collect::<Result<Vec<_>, _>>()? |
111 | | - .try_into() |
112 | | - .expect("we checked both min and max of the args")) |
| 114 | + /// Extract a variadic number of values with a minimum amount given arguments. |
| 115 | + /// Validates the types of all arguments. |
| 116 | + pub fn expect_args_min<T: TryFromValue + Debug, const N: usize>( |
| 117 | + func: &str, |
| 118 | + _ctx: &Context, |
| 119 | + args: &[Value], |
| 120 | + ) -> Result<([T; N], Vec<T>), Error> { |
| 121 | + if args.len() < N { |
| 122 | + return Err(Error::InvalidArgumentCount { |
| 123 | + func: func.into(), |
| 124 | + expected: N, |
| 125 | + is_min: true, |
| 126 | + found: args.len(), |
| 127 | + }); |
| 128 | + } |
| 129 | + |
| 130 | + let min = args |
| 131 | + .iter() |
| 132 | + .take(N) |
| 133 | + .map(T::try_from_value) |
| 134 | + .collect::<Result<Vec<_>, _>>()? |
| 135 | + .try_into() |
| 136 | + .expect("we checked both min and max of the args"); |
| 137 | + |
| 138 | + Ok(( |
| 139 | + min, |
| 140 | + args[N..] |
| 141 | + .iter() |
| 142 | + .map(T::try_from_value) |
| 143 | + .collect::<Result<_, _>>()?, |
| 144 | + )) |
| 145 | + } |
113 | 146 | } |
114 | 147 |
|
115 | | -/// Extract a variadic number of values with a minimum amount given arguments. |
116 | | -/// Validates the types of all arguments. |
117 | | -#[allow(dead_code)] |
118 | | -pub fn expect_args_min<T: TryFromValue + Debug, const N: usize>( |
119 | | - func: &str, |
120 | | - _ctx: &Context, |
121 | | - args: &[Value], |
122 | | -) -> Result<([T; N], Vec<T>), Error> { |
123 | | - if args.len() < N { |
124 | | - return Err(Error::InvalidArgumentCount { |
125 | | - func: func.into(), |
126 | | - expected: N, |
127 | | - is_min: true, |
128 | | - found: args.len(), |
129 | | - }); |
| 148 | +impl TryFromValue for Func { |
| 149 | + fn try_from_value(value: &Value) -> Result<Self, Error> { |
| 150 | + Ok(match value { |
| 151 | + Value::Func(set) => set.clone(), |
| 152 | + _ => { |
| 153 | + return Err(Error::TypeMismatch { |
| 154 | + expected: eco_vec![Type::Func], |
| 155 | + found: value.as_type(), |
| 156 | + }) |
| 157 | + } |
| 158 | + }) |
130 | 159 | } |
131 | | - |
132 | | - let min = args |
133 | | - .iter() |
134 | | - .take(N) |
135 | | - .map(T::try_from_value) |
136 | | - .collect::<Result<Vec<_>, _>>()? |
137 | | - .try_into() |
138 | | - .expect("we checked both min and max of the args"); |
139 | | - |
140 | | - Ok(( |
141 | | - min, |
142 | | - args[N..] |
143 | | - .iter() |
144 | | - .map(T::try_from_value) |
145 | | - .collect::<Result<_, _>>()?, |
146 | | - )) |
147 | 160 | } |
148 | 161 |
|
149 | 162 | #[cfg(test)] |
150 | 163 | mod tests { |
151 | 164 | use super::*; |
152 | | - use crate::test_set::parse::Num; |
153 | 165 |
|
154 | | - const NUM: Num = Num(0); |
| 166 | + const NUM: usize = 0; |
155 | 167 | const VAL: Value = Value::Num(NUM); |
156 | 168 |
|
157 | 169 | #[test] |
158 | 170 | fn test_expect_args_variadic_min_length() { |
159 | | - let ctx = Context::new(); |
| 171 | + let ctx = Context::empty(); |
160 | 172 |
|
161 | 173 | assert_eq!( |
162 | | - expect_args_min::<Num, 0>("f", &ctx, &[]).unwrap(), |
| 174 | + Func::expect_args_min::<usize, 0>("f", &ctx, &[]).unwrap(), |
163 | 175 | ([], vec![]), |
164 | 176 | ); |
165 | | - assert_eq!(expect_args_min("f", &ctx, &[VAL]).unwrap(), ([], vec![NUM]),); |
166 | 177 | assert_eq!( |
167 | | - expect_args_min("f", &ctx, &[VAL, VAL]).unwrap(), |
| 178 | + Func::expect_args_min("f", &ctx, &[VAL]).unwrap(), |
| 179 | + ([], vec![NUM]), |
| 180 | + ); |
| 181 | + assert_eq!( |
| 182 | + Func::expect_args_min("f", &ctx, &[VAL, VAL]).unwrap(), |
168 | 183 | ([], vec![NUM, NUM]), |
169 | 184 | ); |
170 | 185 |
|
171 | | - assert!(expect_args_min::<Num, 1>("f", &ctx, &[]).is_err()); |
172 | | - assert_eq!(expect_args_min("f", &ctx, &[VAL]).unwrap(), ([NUM], vec![]),); |
| 186 | + assert!(Func::expect_args_min::<usize, 1>("f", &ctx, &[]).is_err()); |
| 187 | + assert_eq!( |
| 188 | + Func::expect_args_min("f", &ctx, &[VAL]).unwrap(), |
| 189 | + ([NUM], vec![]), |
| 190 | + ); |
173 | 191 | assert_eq!( |
174 | | - expect_args_min("f", &ctx, &[VAL, VAL]).unwrap(), |
| 192 | + Func::expect_args_min("f", &ctx, &[VAL, VAL]).unwrap(), |
175 | 193 | ([NUM], vec![NUM]), |
176 | 194 | ); |
177 | 195 |
|
178 | | - assert!(expect_args_min::<Num, 2>("f", &ctx, &[]).is_err()); |
179 | | - assert!(expect_args_min::<Num, 2>("f", &ctx, &[VAL]).is_err(),); |
| 196 | + assert!(Func::expect_args_min::<usize, 2>("f", &ctx, &[]).is_err()); |
| 197 | + assert!(Func::expect_args_min::<usize, 2>("f", &ctx, &[VAL]).is_err(),); |
180 | 198 | assert_eq!( |
181 | | - expect_args_min("f", &ctx, &[VAL, VAL]).unwrap(), |
| 199 | + Func::expect_args_min("f", &ctx, &[VAL, VAL]).unwrap(), |
182 | 200 | ([NUM, NUM], vec![]), |
183 | 201 | ); |
184 | 202 | } |
|
0 commit comments