1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
use crate::osm_types;
use crate::tag_priorities;
use crate::varint;
use failure::Error;
use regex::Regex;
use std::collections::HashMap;

#[test]
fn two_tags_one_has_no_priority() {
    use crate::node::Point;
    use desert::ToBytesLE;
    let id = 1831881213;
    let lon = 12.253938100000001;
    let lat = 54.09006660000001;
    let tags = vec![
        ("name", "I am Stoplight"),
        ("highway", "traffic_signals"),
        ("power", "cable"),
    ];
    let node = Point::from_tags(id, (lon, lat), &tags);
    let bytes = node.unwrap().to_bytes_le().unwrap();
    assert_eq!(
        hex::encode(bytes),
        "01d305fd93c1e906211044413a5c58420f3d4920616d2053746f706c6967687400"
    );
}

#[test]
fn two_tags_both_valid_priorities() {
    use crate::node::Point;
    use desert::ToBytesLE;
    let id = 1831881213;
    let lon = 12.253938100000001;
    let lat = 54.09006660000001;
    let tags = vec![
        ("name", "I am Stoplight"),
        ("route", "canoe"),
        ("power", "cable"),
    ];
    let node = Point::from_tags(id, (lon, lat), &tags);

    let bytes = node.unwrap().to_bytes_le().unwrap();
    assert_eq!(
        hex::encode(bytes),
        "01d305fd93c1e906211044413a5c58420f3d4920616d2053746f706c6967687400"
    );
}

#[test]
fn two_tags_same_priority() {
    use crate::node::Point;
    use desert::ToBytesLE;
    let id = 1831881213;
    let lon = 12.253938100000001;
    let lat = 54.09006660000001;
    let tags = vec![
        ("name", "I am Stoplight"),
        ("railway", "wash"),
        ("power", "cable"),
    ];
    let node = Point::from_tags(id, (lon, lat), &tags);

    let bytes = node.unwrap().to_bytes_le().unwrap();
    assert_eq!(
        hex::encode(bytes),
        "01d305fd93c1e906211044413a5c58420f3d4920616d2053746f706c6967687400"
    );

    let tags = vec![
        ("name", "I am Stoplight"),
        ("power", "cable"),
        ("railway", "wash"),
    ];
    let node = Point::from_tags(id, (lon, lat), &tags);

    let bytes = node.unwrap().to_bytes_le().unwrap();
    assert_eq!(
        hex::encode(bytes),
        "01d305fd93c1e906211044413a5c58420f3d4920616d2053746f706c6967687400"
    );
}

pub fn get_tag(tag: &(&str, &str)) -> String {
    lazy_static! {
        static ref RE: Regex = Regex::new("^(|[^:]+_)name($|:)").unwrap();
    }
    let pre = RE.replace(tag.0, "");
    return (pre + "=" + tag.1).to_string();
}

pub fn get_tag_length(tag: &(&str, &str)) -> usize {
    get_tag(tag).len()
}

pub fn get_label_length(tags: &[(&str, &str)]) -> usize {
    lazy_static! {
        static ref RE: Regex = Regex::new("^(|[^:]+_)name($|:)").unwrap();
    }
    let mut label_len = 1;
    for tag in tags {
        // skip all tags that aren't the name tag
        let is_name_tag = RE.find(tag.0);
        match is_name_tag {
            Some(_) => {
                let data_len = get_tag_length(tag);
                label_len += data_len + varint::length(data_len as u64);
            }
            None => {}
        }
    }
    return label_len;
}

pub fn get_tag_priority(tag: &(&str, &str)) -> Option<u64> {
    lazy_static! {
        static ref ALL_PRIORITIES: Vec<(&'static str, u64)> = tag_priorities::get_priorities();
    }

    let mut res: u64 = 0;
    for (s, p) in ALL_PRIORITIES.iter() {
        let wildcard = &format!("{}.*", tag.0);
        let formatted_key: &str = &format!("{}.{}", tag.0, tag.1);

        if *s == formatted_key || s == wildcard {
            if *p > res {
                res = *p;
            }
        }
    }
    return Some(res.clone());
}

pub fn parse(tags: &[(&str, &str)]) -> Result<(u64, Vec<u8>), Error> {
    lazy_static! {
        static ref RE: Regex = Regex::new("^(|[^:]+_)name($|:)").unwrap();
        static ref ALL_TYPES: HashMap<&'static str, u64> = osm_types::get_types();
        static ref DEFAULT_PRIORITY: u64 = 50;
    }

    let place_other: u64 = *ALL_TYPES.get("place.other").unwrap();
    let mut label = vec![0u8; get_label_length(tags)];
    let mut top_type = place_other;
    let mut top_priority = 0;
    let mut offset = 0;

    for tag in tags {
        let formatted_key: &str = &format!("{}.{}", tag.0, tag.1);
        let priority: u64;

        match ALL_TYPES.get(formatted_key) {
            Some(this_type) => {
                //println!("Found type {} for {}", this_type, formatted_key);
                match get_tag_priority(tag) {
                    Some(_priority) => {
                        //println!("Found priority {} for {}", _priority, formatted_key);
                        priority = _priority
                    }
                    None => {
                        priority = DEFAULT_PRIORITY.clone();
                        //println!("Using default priority {} for {}", priority, formatted_key);
                    }
                }

                //println!("comparing {} top and {} priority", top_priority, priority);
                if top_priority <= priority {
                    top_priority = priority;
                    top_type = *this_type;
                    //println!("top priority {} {}", top_priority, top_type);
                }
            }
            None => {
                //println!("Found no type for {}", formatted_key);
            }
        }

        // skip all tags that aren't the name tag
        let is_name_tag = RE.find(tag.0);
        match is_name_tag {
            Some(_) => {
                let tag_length = get_tag_length(tag);

                let maybe_offset =
                    varint::encode(tag_length as u64, &mut label[offset..]);
                match maybe_offset {
                    Ok(is_offset) => {
                        offset += is_offset;
                    }
                    Err(_) => {
                        bail!("Failed to encode tag {}.{}", tag.0, tag.1);
                    }
                }
                let tstr = get_tag(tag);
                tstr.bytes().for_each(|b| {
                    label[offset] = b;
                    offset += 1;
                });
            }
            None => {}
        }
    }

    label[offset] = 0x00;

    //println!("top type {}", top_type);
    return Ok((top_type, label));
}