cassandra_cpp/cassandra/
inet.rs

1use crate::cassandra::error::*;
2use crate::cassandra::util::{Protected, ProtectedInner};
3use crate::cassandra_sys::cass_inet_from_string_n;
4use crate::cassandra_sys::cass_inet_init_v4;
5use crate::cassandra_sys::cass_inet_init_v6;
6use crate::cassandra_sys::cass_inet_string;
7use crate::cassandra_sys::CassInet as _Inet;
8use std::default::Default;
9use std::ffi::CStr;
10use std::fmt;
11use std::fmt::{Debug, Formatter};
12
13use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
14use std::os::raw::c_char;
15use std::str::FromStr;
16use std::string::ToString;
17
18#[repr(C)]
19/// Cassandra's version of an IP address
20#[derive(Copy, Clone)]
21pub struct Inet(_Inet);
22
23impl Debug for Inet {
24    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
25        write!(f, "{}", self.to_string())
26    }
27}
28
29impl PartialEq for Inet {
30    fn eq(&self, other: &Inet) -> bool {
31        if self.0.address_length != other.0.address_length {
32            return false;
33        }
34        let length = self.0.address_length as usize;
35        self.0.address[0..length] == other.0.address[0..length]
36    }
37}
38
39impl ProtectedInner<_Inet> for Inet {
40    fn inner(&self) -> _Inet {
41        self.0
42    }
43}
44
45impl Protected<_Inet> for Inet {
46    fn build(inner: _Inet) -> Self {
47        Inet(inner)
48    }
49}
50
51impl Default for Inet {
52    fn default() -> Inet {
53        Inet(_Inet {
54            address: [0; 16],
55            address_length: 4,
56        })
57    }
58}
59
60impl Inet {
61    /// Constructs an inet v4 object.
62    pub fn cass_inet_init_v4(address: &Ipv4Addr) -> Inet {
63        unsafe { Inet(cass_inet_init_v4(address.octets().as_ptr())) }
64    }
65
66    /// Constructs an inet v6 object.
67    pub fn cass_inet_init_v6(address: &Ipv6Addr) -> Inet {
68        unsafe { Inet(cass_inet_init_v6(address.octets().as_ptr())) }
69    }
70}
71
72impl<'a> From<&'a IpAddr> for Inet {
73    fn from(ip_addr: &IpAddr) -> Inet {
74        match *ip_addr {
75            IpAddr::V4(ref ipv4_addr) => Inet::cass_inet_init_v4(ipv4_addr),
76            IpAddr::V6(ref ipv6_addr) => Inet::cass_inet_init_v6(ipv6_addr),
77        }
78    }
79}
80
81/// The types of errors that can occur when trying to parse an Inet String
82// pub enum InetParseError {
83//    ///Don't put a null in a string, silly!
84//    NulInString(NulError),
85//    ///Not a valiid address
86//    LibBadParams(CassLibError),
87// }
88
89impl FromStr for Inet {
90    type Err = Error;
91
92    fn from_str(s: &str) -> Result<Self> {
93        let s_ptr = s.as_ptr() as *const c_char;
94        let mut inet = _Inet {
95            address: [0; 16],
96            address_length: 0,
97        };
98        unsafe {
99            cass_inet_from_string_n(s_ptr, s.len(), &mut inet)
100                .to_result(())
101                .map(|_| Inet(inet))
102        }
103    }
104}
105
106impl ToString for Inet {
107    fn to_string(&self) -> String {
108        unsafe {
109            let mut inet_str = [0i8; cassandra_cpp_sys::CASS_INET_STRING_LENGTH as usize];
110            cass_inet_string(self.0, inet_str.as_mut_ptr() as *mut libc::c_char);
111            CStr::from_ptr(inet_str.as_ptr() as *const libc::c_char)
112                .to_string_lossy()
113                .into_owned()
114        }
115    }
116}
117
118impl<'a> From<&'a Inet> for IpAddr {
119    fn from(inet: &Inet) -> Self {
120        match inet.0.address_length {
121            4 => {
122                let mut octets = [0u8; 4];
123                octets.copy_from_slice(&inet.0.address[0..4]);
124                IpAddr::from(octets)
125            }
126            16 => IpAddr::from(inet.0.address),
127            unsupported => panic!("impossible inet type: {}", unsupported),
128        }
129    }
130}
131
132#[test]
133fn ipv4_conversion() {
134    let ipv4_in = Ipv4Addr::new(127, 0, 0, 1);
135    let inet = Inet::cass_inet_init_v4(&ipv4_in);
136    let ip_out = IpAddr::from(&inet);
137    assert_eq!(IpAddr::V4(ipv4_in), ip_out);
138}
139
140#[test]
141fn ipv6_conversion() {
142    let ipv6_in = Ipv6Addr::new(0x2001, 0x0db8, 0, 0, 0, 0, 0, 1);
143    let inet = Inet::cass_inet_init_v6(&ipv6_in);
144    let ip_out = IpAddr::from(&inet);
145    assert_eq!(IpAddr::V6(ipv6_in), ip_out);
146}
147
148#[test]
149fn ipv4_to_string() {
150    let ipv4_in = Ipv4Addr::new(127, 0, 0, 1);
151    let inet = Inet::cass_inet_init_v4(&ipv4_in);
152    assert_eq!("127.0.0.1", inet.to_string());
153}