typst_library/foundations/
fields.rs1use ecow::{eco_format, EcoString};
4
5use crate::diag::StrResult;
6use crate::foundations::{IntoValue, Type, Value, Version};
7use crate::layout::{Alignment, Length, Rel};
8use crate::visualize::Stroke;
9
10pub(crate) fn field(value: &Value, field: &str) -> StrResult<Value> {
15 let ty = value.ty();
16 let nope = || Err(no_fields(ty));
17 let missing = || Err(missing_field(ty, field));
18
19 let result = match value {
21 Value::Version(version) => match version.component(field) {
22 Ok(i) => i.into_value(),
23 Err(_) => return missing(),
24 },
25 Value::Length(length) => match field {
26 "em" => length.em.get().into_value(),
27 "abs" => length.abs.into_value(),
28 _ => return missing(),
29 },
30 Value::Relative(rel) => match field {
31 "ratio" => rel.rel.into_value(),
32 "length" => rel.abs.into_value(),
33 _ => return missing(),
34 },
35 Value::Dyn(dynamic) => {
36 if let Some(stroke) = dynamic.downcast::<Stroke>() {
37 match field {
38 "paint" => stroke.paint.clone().into_value(),
39 "thickness" => stroke.thickness.into_value(),
40 "cap" => stroke.cap.into_value(),
41 "join" => stroke.join.into_value(),
42 "dash" => stroke.dash.clone().into_value(),
43 "miter-limit" => {
44 stroke.miter_limit.map(|limit| limit.get()).into_value()
45 }
46 _ => return missing(),
47 }
48 } else if let Some(align) = dynamic.downcast::<Alignment>() {
49 match field {
50 "x" => align.x().into_value(),
51 "y" => align.y().into_value(),
52 _ => return missing(),
53 }
54 } else {
55 return nope();
56 }
57 }
58 _ => return nope(),
59 };
60
61 Ok(result)
62}
63
64#[cold]
66fn no_fields(ty: Type) -> EcoString {
67 eco_format!("cannot access fields on type {ty}")
68}
69
70#[cold]
72fn missing_field(ty: Type, field: &str) -> EcoString {
73 eco_format!("{ty} does not contain field \"{field}\"")
74}
75
76pub fn fields_on(ty: Type) -> &'static [&'static str] {
78 if ty == Type::of::<Version>() {
79 &Version::COMPONENTS
80 } else if ty == Type::of::<Length>() {
81 &["em", "abs"]
82 } else if ty == Type::of::<Rel>() {
83 &["ratio", "length"]
84 } else if ty == Type::of::<Stroke>() {
85 &["paint", "thickness", "cap", "join", "dash", "miter-limit"]
86 } else if ty == Type::of::<Alignment>() {
87 &["x", "y"]
88 } else {
89 &[]
90 }
91}