hecate 0.62.0

OpenStreetMap Inspired Data Storage Backend Focused on Performance and GeoJSON Interchange
use mvt::geom_encoder::{encode_geometry, encode_geometry_type};
use mvt::geom::Geometry;
use mvt::grid;
use mvt::proto;
use std::borrow::Cow;

#[derive(Debug)]
pub struct Tile<'a> {
    bbox: &'a grid::Extent,
    layers: Vec<Layer<'a>>,
}

impl<'a> Tile<'a> {
    pub fn new<'b: 'a>(bbox: &'b grid::Extent) -> Tile<'a> {
        Tile {
            bbox: bbox,
            layers: Vec::new(),
        }
    }

    pub fn add_layer<'b: 'a>(&mut self, layer: Layer<'b>) {
        self.layers.push(layer);
    }

    pub fn layers(&self) -> &[Layer<'a>] {
        self.layers.as_slice()
    }

    pub fn encode(self, grid: &grid::Grid) -> proto::Tile {
        let mut vec_tile = proto::Tile::new();
        for layer in self.layers.into_iter() {
            let mut vec_layer = proto::Tile_Layer::new();
            vec_layer.set_version(2);
            vec_layer.set_name(String::from(layer.name));
            vec_layer.set_extent(4096);
            for feature in layer.features.into_iter() {
                let mut vec_feature = proto::Tile_Feature::new();
                for property in feature.props.into_iter() {
                    let mut vec_value = proto::Tile_Value::new();
                    match property.value {
                        Value::String(ref v) => vec_value.set_string_value(v.clone()),
                        Value::F32(v) => vec_value.set_float_value(v),
                        Value::F64(v) => vec_value.set_double_value(v),
                        Value::I64(v) => vec_value.set_int_value(v),
                        Value::U64(v) => vec_value.set_uint_value(v),
                        Value::Bool(v) => vec_value.set_bool_value(v),
                    }
                    let key = match vec_layer.get_keys().iter().position(|k| *k == property.key) {
                        None => {
                            vec_layer.mut_keys().push(String::from(property.key));
                            vec_layer.get_keys().len() - 1
                        }
                        Some(idx) => idx,
                    };
                    vec_feature.mut_tags().push(key as u32);
                    let value = match vec_layer.get_values().iter().position(|v| *v == vec_value) {
                        None => {
                            vec_layer.mut_values().push(vec_value);
                            vec_layer.get_values().len() - 1
                        }
                        Some(idx) => idx,
                    };
                    vec_feature.mut_tags().push(value as u32);
                }
                vec_feature.set_field_type(encode_geometry_type(&feature.geom));
                vec_feature.set_geometry(encode_geometry(self.bbox, 4096, grid.reverse_y, feature.geom).vec());
                vec_layer.mut_features().push(vec_feature);
            }
            vec_tile.mut_layers().push(vec_layer);
        }
        vec_tile
    }
}

#[derive(Debug)]
pub struct Layer<'a> {
    name: Cow<'a, str>,
    features: Vec<Feature<'a>>,
}

impl<'a> Layer<'a> {
    pub fn new<S>(name: S) -> Layer<'a>
        where S: Into<Cow<'a, str>>
    {
        Layer {
            name: name.into(),
            features: Vec::new(),
        }
    }

    pub fn add_feature<'b: 'a>(&mut self, feature: Feature<'b>) {
        self.features.push(feature);
    }

    pub fn features(&self) -> &[Feature<'a>] {
        self.features.as_slice()
    }
}

#[derive(Debug)]
pub struct Property<'a> {
    pub key: Cow<'a, str>,
    pub value: Value,
}

#[derive(Debug)]
pub struct Feature<'a> {
    id: Option<u64>,
    geom: Geometry,
    props: Vec<Property<'a>>,
}

impl<'a> Feature<'a> {
    pub fn new(geom: Geometry) -> Feature<'a> {
        Feature {
            id: None,
            geom: geom,
            props: Vec::new(),
        }
    }

    pub fn set_id(&mut self, id: u64) {
        self.id = Some(id);
    }

    pub fn add_property<S>(&mut self, key: S, value: Value)
        where S: Into<Cow<'a, str>>
    {
        self.props.push(Property {
            key: key.into(),
            value: value,
        })
    }

    pub fn geometry(&self) -> &Geometry {
        &self.geom
    }

    pub fn properties(&self) -> &[Property] {
        self.props.as_slice()
    }
}

#[derive(Debug, Clone)]
pub enum Value {
    String(String),
    F32(f32),
    F64(f64),
    I64(i64),
    U64(u64),
    Bool(bool),
}