use std::collections::HashMap; pub enum Selector { MinZoom(i32), MaxZoom(i32), HasTag(&'static str), TagEquals(&'static str, &'static str), And(&'static [Selector]), Or(&'static [Selector]), } impl Selector { fn matches(&self, zoom: &i32, tags: &HashMap) -> bool { match self { Selector::MinZoom(min_zoom) => zoom >= min_zoom, Selector::MaxZoom(max_zoom) => zoom <= max_zoom, Selector::HasTag(name) => tags.contains_key(*name), Selector::TagEquals(name, value) => tags.get(*name).map(|s| s.as_str()) == Some(*value), Selector::And(selectors) => selectors.iter().all(|selector| selector.matches(zoom, tags)), Selector::Or(selectors) => selectors.iter().any(|selector| selector.matches(zoom, tags)), } } } type Color = (f64, f64, f64, f64); pub struct Style { pub z_index: i32, pub stroke: Option<(f64, Color)>, pub fill: Option, } impl Style { const DEFAULT: Style = Style { z_index: 0, stroke: None, fill: None, }; } const STYLES: &[(Selector, Style)] = &[ (Selector::HasTag("tunnel"), Style { z_index: -10, ..Style::DEFAULT }), (Selector::TagEquals("landuse", "forest"), Style { z_index: -8, fill: Some((0.2, 0.7, 0.2, 0.8)), ..Style::DEFAULT }), (Selector::TagEquals("leisure", "park"), Style { z_index: -8, fill: Some((0.3, 0.7, 0.3, 0.8)), ..Style::DEFAULT }), (Selector::TagEquals("landuse", "meadow"), Style { z_index: -6, fill: Some((0.2, 0.8, 0.2, 0.8)), ..Style::DEFAULT }), (Selector::TagEquals("landuse", "grass"), Style { z_index: -5, fill: Some((0.3, 0.9, 0.3, 0.8)), ..Style::DEFAULT }), (Selector::TagEquals("landuse", "industrial"), Style { z_index: -9, fill: Some((0.3, 0.3, 0.2, 0.8)), ..Style::DEFAULT }), (Selector::TagEquals("landuse", "construction"), Style { z_index: -9, fill: Some((0.5, 0.5, 0.3, 0.8)), ..Style::DEFAULT }), (Selector::TagEquals("highway", "motorway"), Style { z_index: 10, stroke: Some((50., (1., 1., 1., 1.))), ..Style::DEFAULT }), (Selector::TagEquals("highway", "trunk"), Style { z_index: 9, stroke: Some((35., (1., 1., 1., 1.))), ..Style::DEFAULT }), (Selector::TagEquals("highway", "primary"), Style { z_index: 8, stroke: Some((25., (1., 1., 1., 1.))), ..Style::DEFAULT }), (Selector::And(&[Selector::TagEquals("highway", "secondary"), Selector::MinZoom(12)]), Style { z_index: 7, stroke: Some((20., (1., 1., 1., 1.))), ..Style::DEFAULT }), (Selector::And(&[Selector::TagEquals("highway", "tertiary"), Selector::MinZoom(14)]), Style { z_index: 6, stroke: Some((15., (1., 1., 1., 1.))), ..Style::DEFAULT }), (Selector::And(&[Selector::TagEquals("highway", "residential"), Selector::MinZoom(16)]), Style { z_index: 5, stroke: Some((10., (1., 1., 1., 1.))), ..Style::DEFAULT }), (Selector::And(&[Selector::TagEquals("highway", "living_street"), Selector::MinZoom(16)]), Style { z_index: 4, stroke: Some((8., (1., 1., 1., 1.))), ..Style::DEFAULT }), (Selector::And(&[Selector::HasTag("highway"), Selector::MinZoom(18)]), Style { z_index: 3, stroke: Some((6., (1., 1., 1., 1.))), ..Style::DEFAULT }), (Selector::And(&[Selector::HasTag("railway"), Selector::MinZoom(10)]), Style { z_index: 20, stroke: Some((3., (0., 0., 0., 1.))), ..Style::DEFAULT }), (Selector::Or(&[Selector::HasTag("waterway"), Selector::TagEquals("natural", "water")]), Style { z_index: -2, fill: Some((0.5, 0.5, 0.7, 1.)), ..Style::DEFAULT }), (Selector::And(&[Selector::HasTag("building"), Selector::MinZoom(16)]), Style { z_index: 30, fill: Some((0.7, 0.7, 0.7, 1.)), stroke: Some((1., (0., 0., 0., 1.))), ..Style::DEFAULT }), ]; pub fn find(zoom: &i32, tags: &HashMap) -> Option<&'static Style> { for (selector, style) in STYLES { if selector.matches(zoom, tags) { return Some(&style); } } None }