summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/typst/src/foundations/dict.rs29
-rw-r--r--tests/typ/compiler/dict.typ5
2 files changed, 33 insertions, 1 deletions
diff --git a/crates/typst/src/foundations/dict.rs b/crates/typst/src/foundations/dict.rs
index 06c8f0e4..e77d33ff 100644
--- a/crates/typst/src/foundations/dict.rs
+++ b/crates/typst/src/foundations/dict.rs
@@ -8,7 +8,9 @@ use indexmap::IndexMap;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::diag::{Hint, HintedStrResult, StrResult};
-use crate::foundations::{array, func, repr, scope, ty, Array, Repr, Str, Value};
+use crate::foundations::{
+ array, cast, func, repr, scope, ty, Array, Module, Repr, Str, Value,
+};
use crate::syntax::is_ident;
use crate::util::ArcExt;
@@ -158,6 +160,23 @@ impl Dict {
#[scope]
impl Dict {
+ /// Converts a value into a dictionary.
+ ///
+ /// Note that this function is only intended for conversion of a
+ /// dictionary-like value to a dictionary, not for creation of a dictionary
+ /// from individual pairs. Use the dictionary syntax `(key: value)` instead.
+ ///
+ /// ```example
+ /// #dictionary(sys).at("version")
+ /// ```
+ #[func(constructor)]
+ pub fn construct(
+ /// The value that should be converted to a dictionary.
+ value: ToDict,
+ ) -> Dict {
+ value.0
+ }
+
/// The number of pairs in the dictionary.
#[func(title = "Length")]
pub fn len(&self) -> usize {
@@ -237,6 +256,14 @@ impl Dict {
}
}
+/// A value that can be cast to dictionary.
+pub struct ToDict(Dict);
+
+cast! {
+ ToDict,
+ v: Module => Self(v.scope().iter().map(|(k, v)| (Str::from(k.clone()), v.clone())).collect()),
+}
+
impl Debug for Dict {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_map().entries(self.0.iter()).finish()
diff --git a/tests/typ/compiler/dict.typ b/tests/typ/compiler/dict.typ
index eca1c458..8a5be5cd 100644
--- a/tests/typ/compiler/dict.typ
+++ b/tests/typ/compiler/dict.typ
@@ -84,6 +84,11 @@
#test(dict, (a: 3, b: 1))
---
+// Test dictionary constructor
+#dictionary(sys).at("version")
+#dictionary(sys).at("no_crash", default: none)
+
+---
// Test that removal keeps order.
#let dict = (a: 1, b: 2, c: 3, d: 4)
#dict.remove("b")