elastic_types/ip/
impls.rs

1use std::borrow::Borrow;
2use std::marker::PhantomData;
3use std::net::Ipv4Addr;
4use std::str::FromStr;
5use std::error::Error as StdError;
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7use serde::de::{Error, Visitor};
8use super::mapping::{DefaultIpMapping, IpFieldType, IpMapping};
9
10impl IpFieldType<DefaultIpMapping> for Ipv4Addr {}
11
12/**
13An Elasticsearch `ip` with a mapping.
14
15Where the mapping isn't custom, you can use the standard library `Ipv4Addr` instead.
16
17# Examples
18
19Defining an `ip` with a mapping:
20
21```
22use std::net::Ipv4Addr;
23use elastic_types::ip::mapping::DefaultIpMapping;
24use elastic_types::ip::Ip;
25
26let ip = Ip::<DefaultIpMapping>::new(Ipv4Addr::new(127, 0, 0, 1));
27```
28*/
29#[derive(Debug, Clone, PartialEq)]
30pub struct Ip<TMapping>
31where
32    TMapping: IpMapping,
33{
34    value: Ipv4Addr,
35    _m: PhantomData<TMapping>,
36}
37
38impl<TMapping> Ip<TMapping>
39where
40    TMapping: IpMapping,
41{
42    /**
43    Creates a new `Ip` with the given mapping.
44    
45    # Examples
46    
47    Create a new `Ip` from a `Ip4vAddr`:
48    
49    ```
50    use std::net::Ipv4Addr;
51    use elastic_types::ip::mapping::DefaultIpMapping;
52    use elastic_types::ip::Ip;
53    
54    let ip = Ip::<DefaultIpMapping>::new(Ipv4Addr::new(127, 0, 0, 1));
55    ```
56    */
57    pub fn new<I>(ip: I) -> Ip<TMapping>
58    where
59        I: Into<Ipv4Addr>,
60    {
61        Ip {
62            value: ip.into(),
63            _m: PhantomData,
64        }
65    }
66
67    /**
68    Change the mapping of this ip.
69    
70    # Examples
71    
72    Change the mapping for a given `Ip`:
73    
74    ```
75    # extern crate serde;
76    # #[macro_use]
77    # extern crate elastic_types;
78    # fn main() {
79    # use std::net::Ipv4Addr;
80    # use elastic_types::prelude::*;
81    # #[derive(Default)]
82    # struct MyIpMapping;
83    # impl IpMapping for MyIpMapping { }
84    let es_ip = Ip::<DefaultIpMapping>::new(Ipv4Addr::new(127, 0, 0, 1));
85    
86    let ip: Ip<MyIpMapping> = Ip::remap(es_ip);
87    # }
88    ```
89    */
90    pub fn remap<TNewMapping>(ip: Ip<TMapping>) -> Ip<TNewMapping>
91    where
92        TNewMapping: IpMapping,
93    {
94        Ip::new(ip.value)
95    }
96}
97
98impl<TMapping> IpFieldType<TMapping> for Ip<TMapping>
99where
100    TMapping: IpMapping,
101{
102}
103
104impl_mapping_type!(Ipv4Addr, Ip, IpMapping);
105
106// Serialize elastic ip
107impl<TMapping> Serialize for Ip<TMapping>
108where
109    TMapping: IpMapping,
110{
111    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
112    where
113        S: Serializer,
114    {
115        serializer.serialize_str(&self.value.to_string())
116    }
117}
118
119// Deserialize elastic ip
120impl<'de, TMapping> Deserialize<'de> for Ip<TMapping>
121where
122    TMapping: IpMapping,
123{
124    fn deserialize<D>(deserializer: D) -> Result<Ip<TMapping>, D::Error>
125    where
126        D: Deserializer<'de>,
127    {
128        #[derive(Default)]
129        struct IpVisitor<TMapping> {
130            _m: PhantomData<TMapping>,
131        }
132
133        impl<'de, TMapping> Visitor<'de> for IpVisitor<TMapping>
134        where
135            TMapping: IpMapping,
136        {
137            type Value = Ip<TMapping>;
138
139            fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
140                write!(formatter, "a json string containing an IpV4 address")
141            }
142
143            fn visit_string<E>(self, v: String) -> Result<Ip<TMapping>, E>
144            where
145                E: Error,
146            {
147                let de = try!(Ipv4Addr::from_str(&v).map_err(|e| E::custom(e.description().to_string())));
148
149                Ok(Ip::new(de))
150            }
151
152            fn visit_str<E>(self, v: &str) -> Result<Ip<TMapping>, E>
153            where
154                E: Error,
155            {
156                let de = try!(Ipv4Addr::from_str(v).map_err(|e| E::custom(e.description().to_string())));
157
158                Ok(Ip::new(de))
159            }
160        }
161
162        deserializer.deserialize_any(IpVisitor::<TMapping>::default())
163    }
164}
165
166#[cfg(test)]
167mod tests {
168    use serde_json;
169    use std::net::Ipv4Addr;
170
171    use prelude::*;
172
173    #[derive(Default)]
174    struct MyIpMapping;
175    impl IpMapping for MyIpMapping {}
176
177    #[test]
178    fn can_change_ip_mapping() {
179        fn takes_custom_mapping(_: Ip<MyIpMapping>) -> bool {
180            true
181        }
182
183        let ip: Ip<DefaultIpMapping> = Ip::new(Ipv4Addr::new(127, 0, 0, 1));
184
185        assert!(takes_custom_mapping(Ip::remap(ip)));
186    }
187
188    #[test]
189    fn serialise_elastic_ip() {
190        let ip: Ip<DefaultIpMapping> = Ip::new(Ipv4Addr::new(127, 0, 0, 1));
191
192        let ser = serde_json::to_string(&ip).unwrap();
193
194        assert_eq!(r#""127.0.0.1""#, ser);
195    }
196
197    #[test]
198    fn deserialise_elastic_ip() {
199        let ip: Ip<DefaultIpMapping> = serde_json::from_str(r#""127.0.0.1""#).unwrap();
200
201        assert_eq!(Ipv4Addr::new(127, 0, 0, 1), ip);
202    }
203
204}