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
/// Helper macro to create the many enums used in this library.
#[macro_export]
macro_rules! create_enum {
    ($($enum:ident [$($variant:ident),*$(,)*]),*$(,)*) => {
        $(
            #[derive(Debug, Clone, Copy)]
            pub enum $enum {
                $(
                    $variant,
                )*
            }
        )*
    }
}

/// You can find all features at https://wiki.openstreetmap.org/wiki/Map_Features
#[macro_export]
macro_rules! implement_geotile {
    ($($variant:ident [$($attr:ident),*]),*$(,)*) => {
        paste! {
           // First generate the giant enum of GeoTiles.
           #[derive(Debug, Clone)]
           pub enum GeoTile {
               $(
                   $variant {
                       [<$variant:snake _type>]: [<$variant:camel Type>],
                       geometry: Geometry,
                       osm_id: String,
                       address: Option<Address>,
                       $(
                           $attr: Option<String>,
                       )*
                   },
               )*
           }
           // Now generate the display implementation.
           impl fmt::Display for GeoTile {
               fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                   match self {
                       $(
                           GeoTile::$variant {
                               $(
                                   $attr,
                               )*
                               [<$variant:snake _type>],
                               ..
                           } => {
                               let variant_str = stringify!($variant);
                               write!(f, "Feature: {}\n", variant_str)?;
                               write!(f, "Type: {:?}\n", [<$variant:snake _type>])?;
                               print_geotile_attributes!(f => $($attr),*);
                               Ok(())
                           },
                       )*
                   }
               }
            }
        }
    }
}

///
/// Helper macro to pretty-print all the Option<String> attributes of a particular GeoTile variant.
/// print_geotile_attributes!(f => field1, field2, ...)
/// Where f is a &mut fmt::Formatter (available when implementing fmt::Display).
/// 
#[macro_export]
macro_rules! print_geotile_attributes {
    ($f:expr => $($attr: ident),*$(,)*) => {
        {
            $(
                // Extract every Option<String> attribute and print it's value.
                if let Some($attr) = $attr {
                    let mut attr_str = stringify!($attr).to_string();
                    // Replace underscores with spaces and capitalize.
                    attr_str = attr_str.replace("_", " ");
                    let mut c = attr_str.chars();
                    attr_str = match c.next() {
                        None => String::new(),
                        Some(x) => x.to_uppercase().collect::<String>() + c.as_str(),
                    };
                    // Add our print statement.
                    write!($f, "{}: {}\n", attr_str, $attr)?;
                }
            )*
        }
    };
}


#[macro_export]
macro_rules! extract_type_from_string {
    ($type_str:ident<$props:ident> => $enum:ident [$($variant:ident),*$(,)*]) => {
        paste! {
            match $type_str {
                $(
                    stringify!([<$variant:snake>]) => $enum::$variant,
                )*
                _ => {
                    warn!("Unclassified {} {}: {:?}", stringify!($enum), $type_str, $props);
                    $enum::Unclassified
                }
            }
        }
    }
}

#[macro_export]
macro_rules! geotile_from_properties {
    ($geometry:ident<$props:ident> => $geotile_type:ident<$type:ident> [$($property:ident),*$(,)*]) => {
        let address = address_from_properties($props);
        let osm_id = $props["id"].to_string();
        $(
            let $property = property_to_option_string($props, stringify!($property));
        )*
        return GeoTile::$geotile_type {
            osm_id,
            $geometry,
            $type,
            address,
            $(
                $property,
            )*
        }
    }
}