summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSébastien d'Herbais de Thun <sebastien.d.herbais@gmail.com>2023-10-10 11:44:59 +0200
committerGitHub <noreply@github.com>2023-10-10 11:44:59 +0200
commita8af6b449ac8ad607595649efde08e2d2b46d668 (patch)
treecc7baa4157670f805882e5ece2dd4283363253c4
parentcef2d3afcae87230dbe361ef48ecb5dad50ad0a5 (diff)
Adds a default value to `.remove()` on `dict` and `array` (#2346)
-rw-r--r--crates/typst/src/eval/array.rs9
-rw-r--r--crates/typst/src/eval/dict.rs16
-rw-r--r--crates/typst/src/eval/methods.rs11
-rw-r--r--tests/typ/compiler/array.typ13
-rw-r--r--tests/typ/compiler/dict.typ12
5 files changed, 52 insertions, 9 deletions
diff --git a/crates/typst/src/eval/array.rs b/crates/typst/src/eval/array.rs
index 92642702..bee3fae7 100644
--- a/crates/typst/src/eval/array.rs
+++ b/crates/typst/src/eval/array.rs
@@ -247,9 +247,14 @@ impl Array {
/// The index at which to remove the item. If negative, indexes from
/// the back.
index: i64,
+ /// A default value to return if the index is out of bounds.
+ #[named]
+ default: Option<Value>,
) -> StrResult<Value> {
- let i = self.locate(index, false)?;
- Ok(self.0.remove(i))
+ self.locate_opt(index, false)
+ .map(|i| self.0.remove(i))
+ .or(default)
+ .ok_or_else(|| out_of_bounds_no_default(index, self.len()))
}
/// Extracts a subslice of the array. Fails with an error if the start or
diff --git a/crates/typst/src/eval/dict.rs b/crates/typst/src/eval/dict.rs
index c5da7c15..b77686fe 100644
--- a/crates/typst/src/eval/dict.rs
+++ b/crates/typst/src/eval/dict.rs
@@ -169,11 +169,17 @@ impl Dict {
/// Removes a pair from the dictionary by key and return the value.
#[func]
- pub fn remove(&mut self, key: Str) -> StrResult<Value> {
- match Arc::make_mut(&mut self.0).shift_remove(&key) {
- Some(value) => Ok(value),
- None => Err(missing_key(&key)),
- }
+ pub fn remove(
+ &mut self,
+ key: Str,
+ /// A default value to return if the key does not exist.
+ #[named]
+ default: Option<Value>,
+ ) -> StrResult<Value> {
+ Arc::make_mut(&mut self.0)
+ .shift_remove(&key)
+ .or(default)
+ .ok_or_else(|| missing_key(&key))
}
/// Returns the keys of the dictionary as an array in insertion order.
diff --git a/crates/typst/src/eval/methods.rs b/crates/typst/src/eval/methods.rs
index b8d71c76..843549e6 100644
--- a/crates/typst/src/eval/methods.rs
+++ b/crates/typst/src/eval/methods.rs
@@ -51,13 +51,20 @@ pub fn call_mut(
"insert" => {
array.insert(args.expect("index")?, args.expect("value")?).at(span)?
}
- "remove" => output = array.remove(args.expect("index")?).at(span)?,
+ "remove" => {
+ output = array
+ .remove(args.expect("index")?, args.named("default")?)
+ .at(span)?
+ }
_ => return missing(),
},
Value::Dict(dict) => match method {
"insert" => dict.insert(args.expect::<Str>("key")?, args.expect("value")?),
- "remove" => output = dict.remove(args.expect::<Str>("key")?).at(span)?,
+ "remove" => {
+ output =
+ dict.remove(args.expect("key")?, args.named("default")?).at(span)?
+ }
_ => return missing(),
},
diff --git a/tests/typ/compiler/array.typ b/tests/typ/compiler/array.typ
index 92d926a0..12c3c3a0 100644
--- a/tests/typ/compiler/array.typ
+++ b/tests/typ/compiler/array.typ
@@ -64,6 +64,19 @@
#test((1, 2, 3).at(3, default: 5), 5)
---
+// Test remove with default value.
+
+#{
+ let array = (1, 2, 3)
+ test(array.remove(2, default: 5), 3)
+}
+
+#{
+ let array = (1, 2, 3)
+ test(array.remove(3, default: 5), 5)
+}
+
+---
// Test bad lvalue.
// Error: 2:3-2:14 cannot mutate a temporary value
#let array = (1, 2, 3)
diff --git a/tests/typ/compiler/dict.typ b/tests/typ/compiler/dict.typ
index 2668f347..f3a70c2b 100644
--- a/tests/typ/compiler/dict.typ
+++ b/tests/typ/compiler/dict.typ
@@ -41,6 +41,18 @@
#test((a: 1, b: 2).at("c", default: 3), 3)
---
+// Test remove with default value.
+#{
+ let dict = (a: 1, b: 2)
+ test(dict.remove("b", default: 3), 2)
+}
+
+#{
+ let dict = (a: 1, b: 2)
+ test(dict.remove("c", default: 3), 3)
+}
+
+---
// Missing lvalue is not automatically none-initialized.
#{
let dict = (:)