Skip to content

Commit 95cbde6

Browse files
committed
feat: Allow dasharrays to be expressions
1 parent e2e5338 commit 95cbde6

13 files changed

Lines changed: 162 additions & 98 deletions

File tree

galileo-maplibre/src/layer/vector_tile.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub fn try_create(
6464
/// entire tile. WE don't support this currently, and always put background at the back.
6565
fn get_background(layers: &[&MaplibreStyleLayer]) -> ColorExpr {
6666
const DEFAULT_TILE_BACKGROUND: ColorExpr =
67-
ColorExpr::new(Expr::Literal(ExprValue::Color(Color::TRANSPARENT)));
67+
ColorExpr::new(Expr::Value(ExprValue::Color(Color::TRANSPARENT)));
6868

6969
let layer = match layers {
7070
[] => return DEFAULT_TILE_BACKGROUND,
@@ -113,21 +113,21 @@ fn get_color_value(color: &MlStyleValue<MlColor>, opacity: &MlStyleValue<f64>) -
113113
})
114114
}
115115

116-
fn get_galileo_value<T: Copy + Default + std::fmt::Debug>(value: &MlStyleValue<T>) -> Option<Expr>
116+
fn get_galileo_value<T: Clone + Default + std::fmt::Debug>(value: &MlStyleValue<T>) -> Option<Expr>
117117
where
118118
for<'de> FunctionStop<T>: Deserialize<'de>,
119-
ExprValue<String>: From<T>,
119+
ExprValue<'static>: From<T>,
120120
{
121121
match value {
122-
MlStyleValue::Literal(v) => Some(Expr::Literal(ExprValue::from(*v))),
122+
MlStyleValue::Literal(v) => Some(Expr::Value(ExprValue::from(v.clone()))),
123123
MlStyleValue::Expression(expr) => expr.to_galileo_expr(),
124124
MlStyleValue::Function(function) => {
125125
let control_points = function
126126
.stops
127127
.iter()
128128
.map(|stop| ControlPoint {
129129
input: stop.input.into(),
130-
output: ExprValue::<String>::from(stop.output).into(),
130+
output: ExprValue::from(stop.output.clone()).into(),
131131
})
132132
.collect();
133133

@@ -298,7 +298,11 @@ fn line_rule(line: &LineLayer, tile_schema: &TileSchema) -> Option<StyleRule> {
298298
.minzoom
299299
.and_then(|lod| tile_schema.lod_resolution(lod.round() as u32));
300300
let filter = line.filter.as_ref().and_then(|v| v.to_galileo_expr());
301-
let dasharray = line.paint.line_dasharray.clone();
301+
let dasharray = line
302+
.paint
303+
.line_dasharray
304+
.as_ref()
305+
.and_then(|v| get_galileo_value(v).map(|v| v.into()));
302306

303307
Some(StyleRule {
304308
layer_name: Some(source_layer),

galileo-maplibre/src/style/color.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ impl From<MlColor> for Color {
2424
}
2525
}
2626

27-
impl<T> From<MlColor> for ExprValue<T> {
27+
impl From<MlColor> for ExprValue<'_> {
2828
fn from(value: MlColor) -> Self {
2929
Self::Color(value.0)
3030
}

galileo-maplibre/src/style/expression.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -806,14 +806,14 @@ impl MlExpr {
806806
})
807807
}
808808

809-
fn literal(v: &Value) -> Option<ExprValue<String>> {
809+
fn literal(v: &Value) -> Option<ExprValue<'static>> {
810810
match v {
811811
Value::Bool(v) => Some(ExprValue::Boolean(*v)),
812812
Value::Number(v) => Some(ExprValue::Number(v.as_f64()?)),
813813
Value::String(v) => Some(
814814
parse_css_color(v)
815815
.map(ExprValue::from)
816-
.unwrap_or_else(|| ExprValue::String(v.clone())),
816+
.unwrap_or_else(|| ExprValue::String(v.clone().into())),
817817
),
818818
Value::Null => Some(ExprValue::Null),
819819
_ => None,

galileo-maplibre/src/style/layer/line.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ pub struct LinePaint {
4848

4949
/// Dash pattern for the line. Supports expressions.
5050
#[serde(rename = "line-dasharray", skip_serializing_if = "Option::is_none")]
51-
pub line_dasharray: Option<Vec<f32>>,
51+
pub line_dasharray: Option<MlStyleValue<Vec<f64>>>,
5252

5353
/// Gap width for a casing effect. Supports expressions.
5454
#[serde(rename = "line-gap-width", skip_serializing_if = "Option::is_none")]

galileo/src/expr/interpolation.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub trait Interpolation {
1717
fn control_points(&self) -> &[ControlPoint];
1818
fn interpolate_num(&self, t: f64, x1: f64, out1: f64, x2: f64, out2: f64) -> f64;
1919

20-
fn eval<'a>(&'a self, f: &'a impl ExprFeature, v: ExprView) -> ExprValue<&'a str> {
20+
fn eval<'a>(&'a self, f: &'a impl ExprFeature, v: ExprView) -> ExprValue<'static> {
2121
let Some(input) = self.input().eval(f, v).as_number() else {
2222
return ExprValue::Null;
2323
};
@@ -36,8 +36,8 @@ pub trait Interpolation {
3636

3737
match (lower, upper) {
3838
(None, None) => ExprValue::Null,
39-
(Some(lower), None) => lower.1.eval(f, v),
40-
(None, Some(upper)) => upper.1.eval(f, v),
39+
(Some(lower), None) => lower.1.eval(f, v).owned(),
40+
(None, Some(upper)) => upper.1.eval(f, v).owned(),
4141
(Some(lower), Some(upper)) => self.interpolate(
4242
*input,
4343
**lower.0,
@@ -66,21 +66,25 @@ pub trait Interpolation {
6666
Some(evaluated)
6767
}
6868

69-
fn interpolate<T>(
69+
fn interpolate(
7070
&self,
7171
t: f64,
7272
x1: f64,
73-
out1: ExprValue<T>,
73+
out1: ExprValue<'_>,
7474
x2: f64,
75-
out2: ExprValue<T>,
76-
) -> ExprValue<T> {
75+
out2: ExprValue<'_>,
76+
) -> ExprValue<'static> {
7777
match (out1, out2) {
7878
(ExprValue::Number(out1), ExprValue::Number(out2)) => {
7979
self.interpolate_num(t, x1, out1, x2, out2).into()
8080
}
8181
(ExprValue::Color(out1), ExprValue::Color(out2)) => {
8282
self.interpolate_color(t, x1, out1, x2, out2).into()
8383
}
84+
(ExprValue::NumArray(out1), ExprValue::NumArray(out2)) => self
85+
.interpolate_num_array(t, x1, &out1, x2, &out2)
86+
.map(|v| v.into())
87+
.unwrap_or(ExprValue::Null),
8488
_ => ExprValue::Null,
8589
}
8690
}
@@ -93,6 +97,26 @@ pub trait Interpolation {
9397

9498
Color::rgba(r, g, b, a)
9599
}
100+
101+
fn interpolate_num_array(
102+
&self,
103+
t: f64,
104+
x1: f64,
105+
out1: &[f64],
106+
x2: f64,
107+
out2: &[f64],
108+
) -> Option<Vec<f64>> {
109+
if out1.is_empty() || out1.len() != out2.len() {
110+
return None;
111+
}
112+
113+
let mut result = vec![0.0; out1.len()];
114+
for i in 0..out1.len() {
115+
result[i] = self.interpolate_num(t, x1, out1[i], x2, out2[i]);
116+
}
117+
118+
Some(result)
119+
}
96120
}
97121

98122
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]

galileo/src/expr/match_expr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ pub struct MatchExpr {
1111

1212
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1313
pub struct MatchCase {
14-
pub in_values: Vec<ExprValue<String>>,
14+
pub in_values: Vec<ExprValue<'static>>,
1515
pub out: Expr,
1616
}
1717

1818
impl MatchExpr {
19-
pub fn eval<'a>(&'a self, f: &'a impl ExprFeature, v: ExprView) -> ExprValue<&'a str> {
19+
pub fn eval<'a>(&'a self, f: &'a impl ExprFeature, v: ExprView) -> ExprValue<'a> {
2020
let input = self.input.eval(f, v);
2121
let fallback = self.fallback.eval(f, v);
2222
if input.is_null() {

galileo/src/expr/mod.rs

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![allow(missing_docs)] //TODO: temporary allow
22

3+
use std::borrow::Cow;
34
use std::marker::PhantomData;
45

56
use itertools::Itertools;
@@ -50,7 +51,7 @@ pub enum Expr {
5051
WithOpacity(WithOpacityExpr),
5152

5253
#[serde(untagged)]
53-
Literal(ExprValue<String>),
54+
Value(ExprValue<'static>),
5455
}
5556

5657
#[derive(Debug, Clone, PartialEq, Serialize)]
@@ -63,7 +64,7 @@ pub type BoolExpr = TypedExpr<bool>;
6364

6465
impl<T> Default for TypedExpr<T> {
6566
fn default() -> Self {
66-
Self(Expr::Literal(ExprValue::Null), PhantomData)
67+
Self(Expr::Value(ExprValue::Null), PhantomData)
6768
}
6869
}
6970

@@ -91,6 +92,15 @@ impl TypedExpr<bool> {
9192
}
9293
}
9394

95+
impl TypedExpr<Vec<f64>> {
96+
pub fn eval<'a>(&'a self, f: &'a impl ExprFeature, v: ExprView) -> Option<Cow<'a, [f64]>> {
97+
match self.0.eval(f, v) {
98+
ExprValue::NumArray(arr) => Some(arr),
99+
_ => None,
100+
}
101+
}
102+
}
103+
94104
impl<Out> From<Expr> for TypedExpr<Out> {
95105
fn from(value: Expr) -> Self {
96106
Self::new(value)
@@ -99,37 +109,43 @@ impl<Out> From<Expr> for TypedExpr<Out> {
99109

100110
impl From<Color> for TypedExpr<Color> {
101111
fn from(value: Color) -> Self {
102-
Expr::Literal(value.into()).into()
112+
Expr::Value(value.into()).into()
103113
}
104114
}
105115

106116
impl From<f64> for TypedExpr<f64> {
107117
fn from(value: f64) -> Self {
108-
Expr::Literal(value.into()).into()
118+
Expr::Value(value.into()).into()
109119
}
110120
}
111121

112122
impl From<Color> for Expr {
113123
fn from(value: Color) -> Self {
114-
Expr::Literal(value.into())
124+
Expr::Value(value.into())
115125
}
116126
}
117127

118128
impl From<f64> for Expr {
119129
fn from(value: f64) -> Self {
120-
Expr::Literal(value.into())
130+
Expr::Value(value.into())
121131
}
122132
}
123133

124134
impl From<String> for Expr {
125135
fn from(value: String) -> Self {
126-
Expr::Literal(value.into())
136+
Expr::Value(value.into())
127137
}
128138
}
129139

130140
impl From<bool> for Expr {
131141
fn from(value: bool) -> Self {
132-
Expr::Literal(value.into())
142+
Expr::Value(value.into())
143+
}
144+
}
145+
146+
impl From<Vec<f64>> for Expr {
147+
fn from(value: Vec<f64>) -> Self {
148+
Expr::Value(value.into())
133149
}
134150
}
135151

@@ -161,13 +177,13 @@ impl<'de, Out> Deserialize<'de> for TypedExpr<Out> {
161177
}
162178

163179
pub trait ExprFeature {
164-
fn property(&self, property_name: &str) -> ExprValue<&str>;
180+
fn property(&self, property_name: &str) -> ExprValue<'_>;
165181
fn geom_type(&self) -> ExprGeometryType;
166182
}
167183

168184
pub struct EmptyExprFeature;
169185
impl ExprFeature for EmptyExprFeature {
170-
fn property(&self, _property_name: &str) -> ExprValue<&str> {
186+
fn property(&self, _property_name: &str) -> ExprValue<'_> {
171187
ExprValue::Null
172188
}
173189

@@ -183,9 +199,9 @@ pub struct ExprView {
183199
}
184200

185201
impl Expr {
186-
pub fn eval<'a>(&'a self, f: &'a impl ExprFeature, v: ExprView) -> ExprValue<&'a str> {
202+
pub fn eval<'a>(&'a self, f: &'a impl ExprFeature, v: ExprView) -> ExprValue<'a> {
187203
match self {
188-
Expr::Literal(x) => x.borrowed(),
204+
Expr::Value(x) => x.borrowed(),
189205
Expr::All(exprs) => exprs.iter().all(|expr| expr.eval(f, v).to_bool()).into(),
190206
Expr::Any(exprs) => exprs.iter().any(|expr| expr.eval(f, v).to_bool()).into(),
191207
Expr::Not(expr) => (!expr.eval(f, v).to_bool()).into(),
@@ -218,9 +234,9 @@ impl Expr {
218234
}
219235
}
220236

221-
impl From<ExprValue<String>> for Expr {
222-
fn from(value: ExprValue<String>) -> Self {
223-
Self::Literal(value)
237+
impl From<ExprValue<'static>> for Expr {
238+
fn from(value: ExprValue<'static>) -> Self {
239+
Self::Value(value)
224240
}
225241
}
226242

@@ -231,7 +247,7 @@ pub struct WithOpacityExpr {
231247
}
232248

233249
impl WithOpacityExpr {
234-
pub fn eval<'a>(&'a self, f: &'a impl ExprFeature, v: ExprView) -> ExprValue<&'a str> {
250+
pub fn eval<'a>(&'a self, f: &'a impl ExprFeature, v: ExprView) -> ExprValue<'a> {
235251
let Some(color) = self.color.eval(f, v).as_color() else {
236252
return ExprValue::Null;
237253
};
@@ -258,7 +274,7 @@ mod tests {
258274
expr.0,
259275
Expr::Eq(
260276
Box::new(Expr::Get("kind".to_string())),
261-
Box::new(Expr::Literal(ExprValue::String("road".to_string()))),
277+
Box::new(Expr::Value("road".to_string().into())),
262278
)
263279
);
264280
}
@@ -267,7 +283,7 @@ mod tests {
267283
fn deserialize_expr_from_num() {
268284
let json = "42";
269285
let expr: NumExpr = serde_json::from_str(json).unwrap();
270-
assert_eq!(expr.0, Expr::Literal(ExprValue::Number(42.0)));
286+
assert_eq!(expr.0, Expr::Value(ExprValue::Number(42.0)));
271287
}
272288

273289
#[test]

0 commit comments

Comments
 (0)