<commit_before>// Copyright (c) 2014 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Miscellaneous utilities for low level networking

use bindings::libc;

//use libc::consts::os::bsd44 as bsd44;
use std::fmt;
use std::mem;
use std::io::net::ip::IpAddr;

#[cfg(not(windows))] use internal;

/// A MAC address
#[deriving(PartialEq, Eq, Clone)]
pub enum MacAddr {
    /// A MAC address
    MacAddr(u8, u8, u8, u8, u8, u8)
}

impl fmt::Show for MacAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MacAddr(a, b, c, d, e, f) =>
                write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
                       a, b, c, d, e, f)
        }
    }
}

/// Represents a network interface and its associated addresses
#[deriving(Clone, PartialEq, Eq, Show)]
pub struct NetworkInterface {
    /// The name of the interface
    pub name: String,
    /// The interface index (operating system specific)
    pub index: u32,
    /// A MAC address for the interface
    pub mac: Option<MacAddr>,
    /// An IP addresses for the interface
    pub ips: Option<Vec<IpAddr>>,
    /// Operating system specific flags for the interface
    pub flags: u32,
}

impl NetworkInterface {
    /// Retreive the MAC address associated with the interface
    pub fn mac_address(&self) -> MacAddr {
        self.mac.unwrap()
    }

    /// Is the interface a loopback interface?
    pub fn is_loopback(&self) -> bool {
        self.flags & (libc::IFF_LOOPBACK as u32) != 0
    }
}

#[cfg(target_os = "linux")]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == libc::AF_PACKET {
            let sll: *const libc::sockaddr_ll = mem::transmute(sa);
            let mac = MacAddr((*sll).sll_addr[0], (*sll).sll_addr[1],
                              (*sll).sll_addr[2], (*sll).sll_addr[3],
                              (*sll).sll_addr[4], (*sll).sll_addr[5]);
            return (Some(mac), None);
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                        mem::size_of::<libc::sockaddr_storage>());
            return match addr {
                Ok(sa) => (None, Some(sa.ip)),
                Err(_) => (None, None)
            };
        }
    }
}

#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use bindings::bpf;
    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == bpf::AF_LINK {
            let sdl: *const bpf::sockaddr_dl = mem::transmute(sa);
            let nlen = (*sdl).sdl_nlen as uint;
            let mac = MacAddr((*sdl).sdl_data[nlen + 0] as u8,
                              (*sdl).sdl_data[nlen + 1] as u8,
                              (*sdl).sdl_data[nlen + 2] as u8,
                              (*sdl).sdl_data[nlen + 3] as u8,
                              (*sdl).sdl_data[nlen + 4] as u8,
                              (*sdl).sdl_data[nlen + 5] as u8
                      );
            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                        mem::size_of::<libc::sockaddr_storage>());
            match addr {
                Ok(sa) => (None, Some(sa.ip)),
                Err(_) => (None, None)
            }
        }
    }
}

/// Get a list of available network interfaces for the current machine.
#[inline]
pub fn get_network_interfaces() -> Vec<NetworkInterface> {
    get_network_interfaces_impl()
}

#[cfg(not(windows))]
fn get_network_interfaces_impl() -> Vec<NetworkInterface> {
    use std::string::raw as strraw;

    let mut ifaces: Vec<NetworkInterface> = Vec::new();
    unsafe {
        let mut addrs: *mut libc::ifaddrs = mem::uninitialized();
        if libc::getifaddrs(&mut addrs) != 0 {
            return ifaces;
        }
        let mut addr = addrs;
        while addr.is_not_null() {
            let name = strraw::from_buf((*addr).ifa_name as *const u8);
            let (mac, ip) = sockaddr_to_network_addr((*addr).ifa_addr as *const libc::sockaddr);
            let ni = NetworkInterface {
                name: name.clone(),
                index: 0,
                mac: mac,
                ips: ip.map(|ip| Vec::from_slice([ip])),
                flags: (*addr).ifa_flags
            };
            let mut found: bool = false;
            for iface in ifaces.mut_iter() {
                if name == iface.name {
                    merge(iface, &ni);
                    found = true;
                }
            }
            if !found {
                ifaces.push(ni);
            }

            addr = (*addr).ifa_next;
        }
        libc::freeifaddrs(addrs);

        for iface in ifaces.mut_iter() {
            iface.index = iface.name.with_c_str(
                |name| libc::if_nametoindex(name)
            );
        }
        return ifaces;
    }

    fn merge(old: &mut NetworkInterface, new: &NetworkInterface) {
        old.mac = match new.mac {
            None => old.mac,
            _ => new.mac
        };
        match (&mut old.ips, &new.ips) {
            (&Some(ref mut old_ips), &Some(ref new_ips)) => old_ips.push_all(new_ips.as_slice()),
            _ => {}
        };
        old.flags = old.flags | new.flags;
    }

}

#[cfg(windows)]
fn get_network_interfaces_impl() -> Vec<NetworkInterface> {
    use std::str::from_utf8;
    use std::string::raw;

    use bindings::winpcap;

    let mut adapters_size = 0u32;

    unsafe {
        let mut tmp: winpcap::IP_ADAPTER_INFO = mem::zeroed();
        // FIXME [windows] This only gets IPv4 addresses - should use GetAdaptersAddresses
        winpcap::GetAdaptersInfo(
            &mut tmp,
            &mut adapters_size
        );
    }

    let vec_size = adapters_size / mem::size_of::<winpcap::IP_ADAPTER_INFO>() as u32;

    let mut adapters = Vec::with_capacity(vec_size as uint);

    // FIXME [windows] Check return code
    unsafe {
        winpcap::GetAdaptersInfo(adapters.as_mut_ptr(), &mut adapters_size);
    }

    // Create a complete list of NetworkInterfaces for the machine
    let mut cursor = adapters.as_mut_ptr();
    let mut all_ifaces = Vec::with_capacity(vec_size as uint);
    while cursor.is_not_null() {
        let mac = unsafe {
                    MacAddr((*cursor).Address[0],
                            (*cursor).Address[1],
                            (*cursor).Address[2],
                            (*cursor).Address[3],
                            (*cursor).Address[4],
                            (*cursor).Address[5])
                  };
        let mut ip_cursor = unsafe { &mut (*cursor).IpAddressList as winpcap::PIP_ADDR_STRING};
        let mut ips: Vec<IpAddr> = Vec::new();
        while ip_cursor.is_not_null() {
            let ip_str = unsafe {
                            raw::from_buf((*ip_cursor).IpAddress.String.as_ptr() as *const u8)
                         };
            ips.push(from_str(ip_str.as_slice()).unwrap());
            ip_cursor = unsafe { (*ip_cursor).Next };
        }
        unsafe {
            all_ifaces.push(NetworkInterface {
                        name: raw::from_buf((*cursor).AdapterName.as_ptr() as *const u8),
                        index: (*cursor).Index,
                        mac: Some(mac),
                        ips: Some(ips),
                        //flags: (*cursor).Type, // FIXME [windows]
                        flags: 0,
                     });

            cursor = (*cursor).Next;
        }
    }

    let mut buf = [0u8, ..4096];
    let mut buflen = buf.len() as u32;

    // Gets list of supported adapters in form:
    // adapter1\0adapter2\0\0desc1\0desc2\0\0
    if unsafe { winpcap::PacketGetAdapterNames(buf.as_mut_ptr() as *mut i8, &mut buflen) } == 0 {
        // FIXME [windows] Should allocate a buffer big enough and try again
        //        - size should be buf.len() + buflen (buflen is overwritten)
        fail!("FIXME [windows] unable to get interface list");
    }

    let buf_str = from_utf8(buf).unwrap();
    let iface_names = buf_str.split_str("\0\0").next();
    let mut vec = Vec::new();

    // Return only supported adapters
    match iface_names {
        Some(iface_names) => {
            for iface in iface_names.split('\0') {
                let name = iface.to_string();
                let next = all_ifaces.iter()
                                     .filter(|x| name.as_slice().ends_with(x.name.as_slice()))
                                     .next();
                if next.is_some() {
                    let mut iface = next.unwrap().clone();
                    iface.name = name;
                    vec.push(iface);
                }
            }
        },
        None => ()
    };

    vec
}

<commit_msg>Implement FromStr for MacAddr.<commit_after>// Copyright (c) 2014 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Miscellaneous utilities for low level networking

use bindings::libc;

use std::fmt;
use std::from_str;
use std::mem;
use std::num::from_str_radix;
use std::io::net::ip::IpAddr;

#[cfg(not(windows))] use internal;

/// A MAC address
#[deriving(PartialEq, Eq, Clone)]
pub enum MacAddr {
    /// A MAC address
    MacAddr(u8, u8, u8, u8, u8, u8)
}

impl fmt::Show for MacAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MacAddr(a, b, c, d, e, f) =>
                write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
                       a, b, c, d, e, f)
        }
    }
}

impl from_str::FromStr for MacAddr {
    fn from_str(s: &str) -> Option<MacAddr> {
        let mut parts = [0u8, ..6];
        let mut splits = s.split(':');
        let mut i = 0;
        for split in splits {
            if i == 6 {
                return None;
            }
            match from_str_radix(split, 16) {
                Some(b) if split.len() != 0 => parts[i] = b,
                _ => return None,
            }
            i += 1;
        }

        if i == 6 {
            Some(MacAddr(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5]))
        } else {
            None
        }
    }
}

#[test]
fn mac_addr_from_str() {
    assert_eq!(from_str::<MacAddr>("00:00:00:00:00:00"), Some(MacAddr(0, 0, 0, 0, 0, 0)));
    assert_eq!(from_str::<MacAddr>("ff:ff:ff:ff:ff:ff"), Some(MacAddr(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)));
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:ab"), Some(MacAddr(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB)));
    assert_eq!(from_str::<MacAddr>("::::::"), None);
    assert_eq!(from_str::<MacAddr>("0::::::"), None);
    assert_eq!(from_str::<MacAddr>("::::0::"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:00:00"), None);
    assert_eq!(from_str::<MacAddr>("xx:xx:xx:xx:xx:xx"), None);
}

/// Represents a network interface and its associated addresses
#[deriving(Clone, PartialEq, Eq, Show)]
pub struct NetworkInterface {
    /// The name of the interface
    pub name: String,
    /// The interface index (operating system specific)
    pub index: u32,
    /// A MAC address for the interface
    pub mac: Option<MacAddr>,
    /// An IP addresses for the interface
    pub ips: Option<Vec<IpAddr>>,
    /// Operating system specific flags for the interface
    pub flags: u32,
}

impl NetworkInterface {
    /// Retreive the MAC address associated with the interface
    pub fn mac_address(&self) -> MacAddr {
        self.mac.unwrap()
    }

    /// Is the interface a loopback interface?
    pub fn is_loopback(&self) -> bool {
        self.flags & (libc::IFF_LOOPBACK as u32) != 0
    }
}

#[cfg(target_os = "linux")]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == libc::AF_PACKET {
            let sll: *const libc::sockaddr_ll = mem::transmute(sa);
            let mac = MacAddr((*sll).sll_addr[0], (*sll).sll_addr[1],
                              (*sll).sll_addr[2], (*sll).sll_addr[3],
                              (*sll).sll_addr[4], (*sll).sll_addr[5]);
            return (Some(mac), None);
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                        mem::size_of::<libc::sockaddr_storage>());
            return match addr {
                Ok(sa) => (None, Some(sa.ip)),
                Err(_) => (None, None)
            };
        }
    }
}

#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use bindings::bpf;
    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == bpf::AF_LINK {
            let sdl: *const bpf::sockaddr_dl = mem::transmute(sa);
            let nlen = (*sdl).sdl_nlen as uint;
            let mac = MacAddr((*sdl).sdl_data[nlen + 0] as u8,
                              (*sdl).sdl_data[nlen + 1] as u8,
                              (*sdl).sdl_data[nlen + 2] as u8,
                              (*sdl).sdl_data[nlen + 3] as u8,
                              (*sdl).sdl_data[nlen + 4] as u8,
                              (*sdl).sdl_data[nlen + 5] as u8
                      );
            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                        mem::size_of::<libc::sockaddr_storage>());
            match addr {
                Ok(sa) => (None, Some(sa.ip)),
                Err(_) => (None, None)
            }
        }
    }
}

/// Get a list of available network interfaces for the current machine.
#[inline]
pub fn get_network_interfaces() -> Vec<NetworkInterface> {
    get_network_interfaces_impl()
}

#[cfg(not(windows))]
fn get_network_interfaces_impl() -> Vec<NetworkInterface> {
    use std::string::raw as strraw;

    let mut ifaces: Vec<NetworkInterface> = Vec::new();
    unsafe {
        let mut addrs: *mut libc::ifaddrs = mem::uninitialized();
        if libc::getifaddrs(&mut addrs) != 0 {
            return ifaces;
        }
        let mut addr = addrs;
        while addr.is_not_null() {
            let name = strraw::from_buf((*addr).ifa_name as *const u8);
            let (mac, ip) = sockaddr_to_network_addr((*addr).ifa_addr as *const libc::sockaddr);
            let ni = NetworkInterface {
                name: name.clone(),
                index: 0,
                mac: mac,
                ips: ip.map(|ip| Vec::from_slice([ip])),
                flags: (*addr).ifa_flags
            };
            let mut found: bool = false;
            for iface in ifaces.mut_iter() {
                if name == iface.name {
                    merge(iface, &ni);
                    found = true;
                }
            }
            if !found {
                ifaces.push(ni);
            }

            addr = (*addr).ifa_next;
        }
        libc::freeifaddrs(addrs);

        for iface in ifaces.mut_iter() {
            iface.index = iface.name.with_c_str(
                |name| libc::if_nametoindex(name)
            );
        }
        return ifaces;
    }

    fn merge(old: &mut NetworkInterface, new: &NetworkInterface) {
        old.mac = match new.mac {
            None => old.mac,
            _ => new.mac
        };
        match (&mut old.ips, &new.ips) {
            (&Some(ref mut old_ips), &Some(ref new_ips)) => old_ips.push_all(new_ips.as_slice()),
            _ => {}
        };
        old.flags = old.flags | new.flags;
    }

}

#[cfg(windows)]
fn get_network_interfaces_impl() -> Vec<NetworkInterface> {
    use std::str::from_utf8;
    use std::string::raw;

    use bindings::winpcap;

    let mut adapters_size = 0u32;

    unsafe {
        let mut tmp: winpcap::IP_ADAPTER_INFO = mem::zeroed();
        // FIXME [windows] This only gets IPv4 addresses - should use GetAdaptersAddresses
        winpcap::GetAdaptersInfo(
            &mut tmp,
            &mut adapters_size
        );
    }

    let vec_size = adapters_size / mem::size_of::<winpcap::IP_ADAPTER_INFO>() as u32;

    let mut adapters = Vec::with_capacity(vec_size as uint);

    // FIXME [windows] Check return code
    unsafe {
        winpcap::GetAdaptersInfo(adapters.as_mut_ptr(), &mut adapters_size);
    }

    // Create a complete list of NetworkInterfaces for the machine
    let mut cursor = adapters.as_mut_ptr();
    let mut all_ifaces = Vec::with_capacity(vec_size as uint);
    while cursor.is_not_null() {
        let mac = unsafe {
                    MacAddr((*cursor).Address[0],
                            (*cursor).Address[1],
                            (*cursor).Address[2],
                            (*cursor).Address[3],
                            (*cursor).Address[4],
                            (*cursor).Address[5])
                  };
        let mut ip_cursor = unsafe { &mut (*cursor).IpAddressList as winpcap::PIP_ADDR_STRING};
        let mut ips: Vec<IpAddr> = Vec::new();
        while ip_cursor.is_not_null() {
            let ip_str = unsafe {
                            raw::from_buf((*ip_cursor).IpAddress.String.as_ptr() as *const u8)
                         };
            ips.push(from_str(ip_str.as_slice()).unwrap());
            ip_cursor = unsafe { (*ip_cursor).Next };
        }
        unsafe {
            all_ifaces.push(NetworkInterface {
                        name: raw::from_buf((*cursor).AdapterName.as_ptr() as *const u8),
                        index: (*cursor).Index,
                        mac: Some(mac),
                        ips: Some(ips),
                        //flags: (*cursor).Type, // FIXME [windows]
                        flags: 0,
                     });

            cursor = (*cursor).Next;
        }
    }

    let mut buf = [0u8, ..4096];
    let mut buflen = buf.len() as u32;

    // Gets list of supported adapters in form:
    // adapter1\0adapter2\0\0desc1\0desc2\0\0
    if unsafe { winpcap::PacketGetAdapterNames(buf.as_mut_ptr() as *mut i8, &mut buflen) } == 0 {
        // FIXME [windows] Should allocate a buffer big enough and try again
        //        - size should be buf.len() + buflen (buflen is overwritten)
        fail!("FIXME [windows] unable to get interface list");
    }

    let buf_str = from_utf8(buf).unwrap();
    let iface_names = buf_str.split_str("\0\0").next();
    let mut vec = Vec::new();

    // Return only supported adapters
    match iface_names {
        Some(iface_names) => {
            for iface in iface_names.split('\0') {
                let name = iface.to_string();
                let next = all_ifaces.iter()
                                     .filter(|x| name.as_slice().ends_with(x.name.as_slice()))
                                     .next();
                if next.is_some() {
                    let mut iface = next.unwrap().clone();
                    iface.name = name;
                    vec.push(iface);
                }
            }
        },
        None => ()
    };

    vec
}

<|endoftext|>


<commit_before>//! Various convenience functions for `built` at runtime.

/// Parses version-strings with `semver::Version::parse()`.
///
/// This function is only available if `built` was compiled with the
/// `semver` feature.
///
/// The function takes a reference to an array of names and version numbers as
/// serialized by `built` and returns an iterator over the unchanged names
/// and parsed version numbers.
///
/// ```
/// extern crate built;
/// extern crate semver;
/// pub mod build_info {
///     pub const DEPENDENCIES: [(&'static str, &'static str); 1] = [("built", "0.1.0")];
/// }
///
/// let deps = build_info::DEPENDENCIES;
/// assert!(built::util::parse_versions(&deps)
///                      .any(|(name, ver)| name == "built" &&
///                                         ver >= semver::Version::parse("0.1.0").unwrap()));
/// ```
///
/// # Panics
/// If a version can't be parsed by `semver::Version::parse()`. This should never
/// happen with version strings provided by Cargo and `built`.
#[cfg(feature = "semver")]
pub fn parse_versions<'a, T>(
    name_and_versions: T,
) -> impl Iterator<Item = (&'a str, semver::Version)>
where
    T: IntoIterator<Item = &'a (&'a str, &'a str)>,
{
    fn parse_version<'a>(t: &'a (&'a str, &'a str)) -> (&'a str, semver::Version) {
        (t.0, t.1.parse().unwrap())
    }
    name_and_versions.into_iter().map(parse_version)
}

/// Parse a time-string as formatted by `built`.
///
/// ```
/// use chrono::Datelike;
///
/// pub mod build_info {
///     pub const BUILT_TIME_UTC: &'static str = "Tue, 14 Feb 2017 05:21:41 GMT";
/// }
///
/// assert_eq!(built::util::strptime(&build_info::BUILT_TIME_UTC).year(), 2017);
/// ```
///
/// # Panics
/// If the string can't be parsed. This should never happen with input provided
/// by `built`.
#[cfg(feature = "chrono")]
pub fn strptime(s: &str) -> chrono::DateTime<chrono::offset::Utc> {
    chrono::DateTime::parse_from_rfc2822(s)
        .unwrap()
        .with_timezone(&chrono::offset::Utc)
}

/// Retrieves the git-tag or hash describing the exact version.
///
/// If a valid git-repo can't be discovered at or above the given path,
/// `Ok(None)` is returned instead of an `Err`-value.
///
/// # Errors
/// Errors from `git2` are returned if the repository does exists at all.
#[cfg(feature = "git2")]
pub fn get_repo_description<P: AsRef<std::path::Path>>(
    root: P,
) -> Result<Option<String>, git2::Error> {
    match git2::Repository::discover(root) {
        Ok(repo) => {
            let mut desc_opt = git2::DescribeOptions::new();
            desc_opt.describe_tags().show_commit_oid_as_fallback(true);
            Ok(Some(
                repo.describe(&desc_opt)
                    .and_then(|desc| desc.format(None))?,
            ))
        }
        Err(ref e)
            if e.class() == git2::ErrorClass::Repository
                && e.code() == git2::ErrorCode::NotFound =>
        {
            Ok(None)
        }
        Err(e) => Err(e),
    }
}

/// Detect execution on various Continiuous Integration platforms.
///
/// CI-platforms are detected by the presence of known environment variables.
/// This allows to detect specific CI-platform (like `GitLab`); various
/// generic environment variables are also checked, which may result in
/// `CIPlatform::Generic`.
///
/// Since some platforms have fairly generic environment variables to begin with
/// (e.g. `TASK_ID`), this function may have false positives.
pub fn detect_ci() -> Option<super::CIPlatform> {
    super::CIPlatform::detect_from_envmap(&super::get_environment())
}
<commit_msg>Remove unneeded type params<commit_after>//! Various convenience functions for `built` at runtime.

/// Parses version-strings with `semver::Version::parse()`.
///
/// This function is only available if `built` was compiled with the
/// `semver` feature.
///
/// The function takes a reference to an array of names and version numbers as
/// serialized by `built` and returns an iterator over the unchanged names
/// and parsed version numbers.
///
/// ```
/// extern crate built;
/// extern crate semver;
/// pub mod build_info {
///     pub const DEPENDENCIES: [(&'static str, &'static str); 1] = [("built", "0.1.0")];
/// }
///
/// let deps = build_info::DEPENDENCIES;
/// assert!(built::util::parse_versions(&deps)
///                      .any(|(name, ver)| name == "built" &&
///                                         ver >= semver::Version::parse("0.1.0").unwrap()));
/// ```
///
/// # Panics
/// If a version can't be parsed by `semver::Version::parse()`. This should never
/// happen with version strings provided by Cargo and `built`.
#[cfg(feature = "semver")]
pub fn parse_versions<'a, T>(
    name_and_versions: T,
) -> impl Iterator<Item = (&'a str, semver::Version)>
where
    T: IntoIterator<Item = &'a (&'a str, &'a str)>,
{
    fn parse_version<'a>(t: &'a (&'a str, &'a str)) -> (&'a str, semver::Version) {
        (t.0, t.1.parse().unwrap())
    }
    name_and_versions.into_iter().map(parse_version)
}

/// Parse a time-string as formatted by `built`.
///
/// ```
/// use chrono::Datelike;
///
/// pub mod build_info {
///     pub const BUILT_TIME_UTC: &'static str = "Tue, 14 Feb 2017 05:21:41 GMT";
/// }
///
/// assert_eq!(built::util::strptime(&build_info::BUILT_TIME_UTC).year(), 2017);
/// ```
///
/// # Panics
/// If the string can't be parsed. This should never happen with input provided
/// by `built`.
#[cfg(feature = "chrono")]
pub fn strptime(s: &str) -> chrono::DateTime<chrono::offset::Utc> {
    chrono::DateTime::parse_from_rfc2822(s)
        .unwrap()
        .with_timezone(&chrono::offset::Utc)
}

/// Retrieves the git-tag or hash describing the exact version.
///
/// If a valid git-repo can't be discovered at or above the given path,
/// `Ok(None)` is returned instead of an `Err`-value.
///
/// # Errors
/// Errors from `git2` are returned if the repository does exists at all.
#[cfg(feature = "git2")]
pub fn get_repo_description(root: &std::path::Path) -> Result<Option<String>, git2::Error> {
    match git2::Repository::discover(root) {
        Ok(repo) => {
            let mut desc_opt = git2::DescribeOptions::new();
            desc_opt.describe_tags().show_commit_oid_as_fallback(true);
            Ok(Some(
                repo.describe(&desc_opt)
                    .and_then(|desc| desc.format(None))?,
            ))
        }
        Err(ref e)
            if e.class() == git2::ErrorClass::Repository
                && e.code() == git2::ErrorCode::NotFound =>
        {
            Ok(None)
        }
        Err(e) => Err(e),
    }
}

/// Detect execution on various Continiuous Integration platforms.
///
/// CI-platforms are detected by the presence of known environment variables.
/// This allows to detect specific CI-platform (like `GitLab`); various
/// generic environment variables are also checked, which may result in
/// `CIPlatform::Generic`.
///
/// Since some platforms have fairly generic environment variables to begin with
/// (e.g. `TASK_ID`), this function may have false positives.
pub fn detect_ci() -> Option<super::CIPlatform> {
    super::CIPlatform::detect_from_envmap(&super::get_environment())
}
<|endoftext|>


<commit_before>// vim: tw=80
use super::*;

use quote::ToTokens;

use crate::{
    mockable_item::{MockableItem, MockableModule}
};

/// A Mock item
pub(crate) enum MockItem {
    Module(MockItemModule)
}

impl From<MockableItem> for MockItem {
    fn from(mockable: MockableItem) -> MockItem {
        match mockable {
            MockableItem::Manual(_) => unimplemented!("1"),
            MockableItem::Module(mod_) => MockItem::Module(
                MockItemModule::from(mod_)
            )
        }
    }
}

impl ToTokens for MockItem {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        match self {
            MockItem::Module(mod_) => mod_.to_tokens(tokens),
            _ => unimplemented!("2")
        }
    }
}

struct MockFunction {
    /// Names of the method arguments
    argnames: Vec<Pat>,
    /// Types of the method arguments
    argty: Vec<Type>,
    /// Type Generics of the Expectation object
    egenerics: Generics,
    /// Is this for a static method or free function?
    is_static: bool,
    /// The mockable version of the function
    item_fn: ItemFn,
    /// name of the function's parent module
    mod_ident: Ident,
    /// Expressions that create the predicate arguments from the call arguments
    predexprs: Vec<TokenStream>,
    /// Types used for Predicates.  Will be almost the same as args, but every
    /// type will be a non-reference type.
    predty: Vec<Type>,
}

impl From<(&Ident, ItemFn)> for MockFunction {
    /// Create a MockFunction from its mockable version and the name of its
    /// parent module
    fn from((ident, f): (&Ident, ItemFn)) -> MockFunction {
        let egenerics = Generics::default();    // TODO
        let mut argnames = Vec::new();
        let mut argty = Vec::new();
        let mut is_static = true;
        let mut predexprs = Vec::new();
        let mut predty = Vec::new();
        for fa in f.sig.inputs.iter() {
            if let FnArg::Typed(pt) = fa {
                let argname = (*pt.pat).clone();
                let aty = &pt.ty;
                //let aty = supersuperfy(&pt.ty, levels);
                if let Type::Reference(tr) = &**aty {
                    predexprs.push(quote!(#argname));
                    predty.push((*tr.elem).clone());
                } else {
                    predexprs.push(quote!(&#argname));
                    predty.push((**aty).clone());
                };
                argnames.push(argname);
                argty.push((**aty).clone());
            } else {
                is_static = false;
                ()    // Strip out the "&self" argument
            }
        }
        MockFunction {
            argnames,
            argty,
            is_static,
            predexprs,
            predty,
            egenerics,
            item_fn: f,
            mod_ident: ident.clone(),
        }
    }
}

impl ToTokens for MockFunction {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let matcher = &Matcher{f: self};
        let mod_ident = format_ident!("__{}", &self.item_fn.sig.ident);
        let orig_signature = &self.item_fn.sig;
        quote!(
            #[allow(missing_docs)]
            pub mod #mod_ident {
                use super::*;
                use ::mockall::CaseTreeExt;
                use ::std::sync::MutexGuard;
                use ::std::{
                    mem,
                    ops::{DerefMut, Range},
                    sync::Mutex
                };
                enum Rfunc {} // 42 lines
                #matcher
                struct Common{} // 106 lines
                pub struct Expectation{}    // 208 lines
                pub struct Expectations{}   // 43 lines
                pub struct ExpectationGuard {} // 114 lines
                pub struct Context {}   // 44 lines
            }
            #orig_signature {}
            pub fn bar_context() {}
        ).to_tokens(tokens);
    }
}

struct Matcher<'a> {
    f: &'a MockFunction
}

impl<'a> ToTokens for Matcher<'a> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
        let hrtb = Visibility::Inherited;   // TODO
        let refpredty = Visibility::Inherited; // TODO
        let preds = Visibility::Inherited; // TODO
        let predty = &self.f.predty;
        let fn_params = Visibility::Inherited; // TODO
        let argnames = &self.f.argnames;
        let pred_matches = Visibility::Inherited; // TODO
        let lg = Visibility::Inherited; // TODO
        let braces = Visibility::Inherited; // TODO
        let indices = [Visibility::Inherited]; // TODO
        quote!(
            enum Matcher #ig #wc {
                Always,
                Func(Box<dyn #hrtb Fn(#refpredty) -> bool + Send>),
                // Version of Matcher::Func for closures that aren't Send
                FuncST(::mockall::Fragile<Box<dyn #hrtb Fn(#refpredty) -> bool>>),
                Pred(Box<(#preds)>),
                // Prevent "unused type parameter" errors
                // Surprisingly, PhantomData<Fn(generics)> is Send even if
                // generics are not, unlike PhantomData<generics>
                _Phantom(Box<dyn Fn(#fn_params) -> () + Send>)
            }
            impl #ig Matcher #tg #wc {
                fn matches #lg (&self, #( #argnames: &#predty, )*) -> bool {
                    match self {
                        Matcher::Always => true,
                        Matcher::Func(__mockall_f) =>
                            __mockall_f(#(#argnames, )*),
                        Matcher::FuncST(__mockall_f) =>
                            (__mockall_f.get())(#(#argnames, )*),
                        Matcher::Pred(__mockall_pred) =>
                            [#pred_matches]
                            .iter()
                            .all(|__mockall_x| *__mockall_x),
                        _ => unreachable!()
                    }
                }
            }

            impl #ig Default for Matcher #tg #wc {
                #[allow(unused_variables)]
                fn default() -> Self {
                    Matcher::Always
                }
            }

            impl #ig ::std::fmt::Display for Matcher #tg #wc {
                fn fmt(&self, __mockall_fmt: &mut ::std::fmt::Formatter<'_>)
                    -> ::std::fmt::Result
                {
                    match self {
                        Matcher::Always => write!(__mockall_fmt, "<anything>"),
                        Matcher::Func(_) => write!(__mockall_fmt, "<function>"),
                        Matcher::FuncST(_) => write!(__mockall_fmt, "<single threaded function>"),
                        Matcher::Pred(__mockall_p) => {
                            write!(__mockall_fmt, #braces,
                                #(__mockall_p.#indices,)*)
                        }
                        _ => unreachable!(),
                    }
                }
            }
        ).to_tokens(tokens);
    }
}enum MockItemContent {
    Fn(MockFunction),
    Tokens(TokenStream)
}

pub(crate) struct MockItemModule {
    vis: Visibility,
    mock_ident: Ident,
    orig_ident: Option<Ident>,
    content: Vec<MockItemContent>
}

fn mock_fn(item_fn: ItemFn) -> ItemMod {
    let ident = format_ident!("__{}", item_fn.sig.ident);
    unimplemented!("5")
}

/// Generate a whole mod module from the mockable sort
impl From<MockableModule> for ItemMod {
    fn from(mod_: MockableModule) -> ItemMod {
        let attrs = Vec::new();
        let vis = mod_.vis;
        let mod_token = mod_.mod_token;
        let ident = mod_.mock_ident;
        let semi = None;
        let brace = token::Brace::default();

        let mut contents = Vec::<Item>::new();
        contents.push(Item::Verbatim(quote!(use super::T;)));
        for item in mod_.content.into_iter() {
            match item {
                Item::Fn(item_fn) => {
                    contents.push(
                        Item::Verbatim(quote!(#[allow(missing_docs)]))
                    );
                    contents.push(Item::Mod(mock_fn(item_fn)));
                },
                _ => {
                    compile_error(item.span(),
                        "Unsupported item type when mocking modules");
                }
            }
        }

        let content = Some((brace, contents));
        ItemMod {
            attrs,
            vis,
            mod_token,
            ident,
            content,
            semi
        }
    }
}

impl From<MockableModule> for MockItemModule {
    fn from(mod_: MockableModule) -> MockItemModule {
        let mock_ident = mod_.mock_ident.clone();
        let orig_ident = mod_.orig_ident;
        let content = mod_.content.into_iter().filter_map(|item| {
            let span = item.span();
            match item {
                Item::ExternCrate(_) | Item::Impl(_) =>
                {
                    // Ignore
                    None
                },
                Item::Static(is) => {
                    Some(MockItemContent::Tokens(is.into_token_stream()))
                },
                Item::Const(ic) => {
                    Some(MockItemContent::Tokens(ic.into_token_stream()))
                },
                Item::Fn(f) => {
                    Some(MockItemContent::Fn(
                        MockFunction::from((&mock_ident, f))
                    ))
                },
                Item::Mod(_) | Item::ForeignMod(_)
                    | Item::Struct(_) | Item::Enum(_)
                    | Item::Union(_) | Item::Trait(_) =>
                {
                    compile_error(span,
                        "Mockall does not yet support deriving nested mocks");
                    None
                },
                Item::Type(ty) => {
                    Some(MockItemContent::Tokens(ty.into_token_stream()))
                },
                Item::TraitAlias(ta) => {
                    Some(MockItemContent::Tokens(ta.into_token_stream()))
                },
                Item::Use(u) => {
                    Some(MockItemContent::Tokens(u.into_token_stream()))
                },
                _ => {
                    compile_error(span, "Unsupported item");
                    None
                }
            }
        }).collect::<Vec<_>>();

        MockItemModule {
            vis: mod_.vis,
            mock_ident: mod_.mock_ident,
            orig_ident,
            content
        }
    }
}

impl ToTokens for MockItemModule {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let mut body = TokenStream::new();
        let mut cp_body = TokenStream::new();
        let modname = &self.mock_ident;

        for item in self.content.iter() {
            match item {
                MockItemContent::Tokens(ts) => ts.to_tokens(&mut body),
                MockItemContent::Fn(f) => {
                    //let mod_ident = format_ident!("__{}", &f.sig.ident);
                    //quote!(
                        //let __mockall_timeses = #mod_ident::EXPECTATIONS.lock()
                            //.unwrap()
                            //.checkpoint()
                            //.collect::<Vec<_>>();
                    //).to_tokens(&mut cp_body);
                    f.to_tokens(&mut body);
                },
            }
        }

        quote!(
            /// Verify that all current expectations for this function are
            /// satisfied and clear them.
            pub fn checkpoint() { #cp_body }
        ).to_tokens(&mut body);
        let docstr = {
            let inner_ds = if let Some(ident) = &self.orig_ident {
                format!("Mock version of the `{}` module", ident)
            } else {
                format!("TODO: write doc string")
            };
            quote!( #[doc = #inner_ds])
        };
        quote!(
            #docstr
            pub mod #modname { #body }
        ).to_tokens(tokens);
    }
}
<commit_msg>Now generating correct code for the Matcher<commit_after>// vim: tw=80
use super::*;

use quote::ToTokens;

use crate::{
    mockable_item::{MockableItem, MockableModule}
};

/// A Mock item
pub(crate) enum MockItem {
    Module(MockItemModule)
}

impl From<MockableItem> for MockItem {
    fn from(mockable: MockableItem) -> MockItem {
        match mockable {
            MockableItem::Manual(_) => unimplemented!("1"),
            MockableItem::Module(mod_) => MockItem::Module(
                MockItemModule::from(mod_)
            )
        }
    }
}

impl ToTokens for MockItem {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        match self {
            MockItem::Module(mod_) => mod_.to_tokens(tokens),
            _ => unimplemented!("2")
        }
    }
}

struct MockFunction {
    /// Lifetime Generics of the mocked method that relate to the arguments but
    /// not the return value
    alifetimes: Generics,
    /// Names of the method arguments
    argnames: Vec<Pat>,
    /// Types of the method arguments
    argty: Vec<Type>,
    /// Type Generics of the Expectation object
    egenerics: Generics,
    /// The mock function's generic types as a list of types
    fn_params: Punctuated<Ident, Token![,]>,
    /// Is this for a static method or free function?
    is_static: bool,
    /// The mockable version of the function
    item_fn: ItemFn,
    /// name of the function's parent module
    mod_ident: Ident,
    /// Expressions that create the predicate arguments from the call arguments
    predexprs: Vec<TokenStream>,
    /// Types used for Predicates.  Will be almost the same as args, but every
    /// type will be a non-reference type.
    predty: Vec<Type>,
    /// References to every type in `predty`.
    refpredty: Vec<Type>
}

impl MockFunction {
    // TODO: return a Syn object instead of a TokenStream
    fn hrtb(&self) -> TokenStream {
        if self.alifetimes.params.is_empty() {
            TokenStream::default()
        } else {
            let ig = &self.alifetimes;
            quote!(for #ig)
        }
    }

}

impl From<(&Ident, ItemFn)> for MockFunction {
    /// Create a MockFunction from its mockable version and the name of its
    /// parent module
    fn from((ident, f): (&Ident, ItemFn)) -> MockFunction {
        let egenerics = Generics::default();    // TODO
        let mut argnames = Vec::new();
        let mut argty = Vec::new();
        let mut is_static = true;
        let mut predexprs = Vec::new();
        let mut predty = Vec::new();
        let mut refpredty = Vec::new();
        for fa in f.sig.inputs.iter() {
            if let FnArg::Typed(pt) = fa {
                let argname = (*pt.pat).clone();
                let aty = &pt.ty;
                //let aty = supersuperfy(&pt.ty, levels);
                if let Type::Reference(tr) = &**aty {
                    predexprs.push(quote!(#argname));
                    predty.push((*tr.elem).clone());
                    refpredty.push((**aty).clone());
                } else {
                    predexprs.push(quote!(&#argname));
                    predty.push((**aty).clone());
                    let tr = TypeReference {
                        and_token: Token![&](Span::call_site()),
                        lifetime: None,
                        mutability: None,
                        elem: Box::new((**aty).clone())
                    };
                    refpredty.push(Type::Reference(tr));
                };
                argnames.push(argname);
                argty.push((**aty).clone());
            } else {
                is_static = false;
                ()    // Strip out the "&self" argument
            }
        }
        let (mut egenerics, alifetimes, rlifetimes) = split_lifetimes(
            f.sig.generics.clone(),
            &f.sig.inputs,
            // TODO: supersuperfy the output
            &f.sig.output
        );
        let fn_params = Punctuated::<Ident, Token![,]>::from_iter(
            egenerics.type_params().map(|tp| tp.ident.clone())
        );
        MockFunction {
            alifetimes,
            argnames,
            argty,
            egenerics,
            fn_params,
            is_static,
            item_fn: f,
            mod_ident: ident.clone(),
            predexprs,
            predty,
            refpredty,
        }
    }
}

impl ToTokens for MockFunction {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let matcher = &Matcher{f: self};
        let mod_ident = format_ident!("__{}", &self.item_fn.sig.ident);
        let orig_signature = &self.item_fn.sig;
        quote!(
            #[allow(missing_docs)]
            pub mod #mod_ident {
                use super::*;
                use ::mockall::CaseTreeExt;
                use ::std::sync::MutexGuard;
                use ::std::{
                    mem,
                    ops::{DerefMut, Range},
                    sync::Mutex
                };
                enum Rfunc {} // 42 lines
                #matcher
                struct Common{} // 106 lines
                pub struct Expectation{}    // 208 lines
                pub struct Expectations{}   // 43 lines
                pub struct ExpectationGuard {} // 114 lines
                pub struct Context {}   // 44 lines
            }
            #orig_signature {}
            pub fn bar_context() {}
        ).to_tokens(tokens);
    }
}

struct Matcher<'a> {
    f: &'a MockFunction
}

impl<'a> ToTokens for Matcher<'a> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let (ig, tg, wc) = self.f.egenerics.split_for_impl();
        let argnames = &self.f.argnames;
        let braces = argnames.iter()
            .fold(String::new(), |mut acc, _argname| {
                if acc.is_empty() {
                    acc.push_str("{}");
                } else {
                    acc.push_str(", {}");
                }
                acc
            });
        let fn_params = &self.f.fn_params;
        let hrtb = self.f.hrtb();
        let indices = (0..argnames.len())
            .map(|i| {
                syn::Index::from(i)
            }).collect::<Vec<_>>();
        let lg = &self.f.alifetimes;
        let pred_matches = TokenStream::from_iter(
            argnames.iter().enumerate()
            .map(|(i, argname)| {
                let idx = syn::Index::from(i);
                quote!(__mockall_pred.#idx.eval(#argname),)
            })
        );
        let preds = TokenStream::from_iter(
            self.f.predty.iter().map(|t|
                quote!(Box<dyn #hrtb ::mockall::Predicate<#t> + Send>,)
            )
        );
        let predty = &self.f.predty;
        let refpredty = &self.f.refpredty;
        quote!(
            enum Matcher #ig #wc {
                Always,
                Func(Box<dyn #hrtb Fn(#( #refpredty, )*) -> bool + Send>),
                // Version of Matcher::Func for closures that aren't Send
                FuncST(::mockall::Fragile<Box<dyn #hrtb Fn(#( #refpredty, )*) -> bool>>),
                Pred(Box<(#preds)>),
                // Prevent "unused type parameter" errors
                // Surprisingly, PhantomData<Fn(generics)> is Send even if
                // generics are not, unlike PhantomData<generics>
                _Phantom(Box<dyn Fn(#fn_params) -> () + Send>)
            }
            impl #ig Matcher #tg #wc {
                fn matches #lg (&self, #( #argnames: &#predty, )*) -> bool {
                    match self {
                        Matcher::Always => true,
                        Matcher::Func(__mockall_f) =>
                            __mockall_f(#(#argnames, )*),
                        Matcher::FuncST(__mockall_f) =>
                            (__mockall_f.get())(#(#argnames, )*),
                        Matcher::Pred(__mockall_pred) =>
                            [#pred_matches]
                            .iter()
                            .all(|__mockall_x| *__mockall_x),
                        _ => unreachable!()
                    }
                }
            }

            impl #ig Default for Matcher #tg #wc {
                #[allow(unused_variables)]
                fn default() -> Self {
                    Matcher::Always
                }
            }

            impl #ig ::std::fmt::Display for Matcher #tg #wc {
                fn fmt(&self, __mockall_fmt: &mut ::std::fmt::Formatter<'_>)
                    -> ::std::fmt::Result
                {
                    match self {
                        Matcher::Always => write!(__mockall_fmt, "<anything>"),
                        Matcher::Func(_) => write!(__mockall_fmt, "<function>"),
                        Matcher::FuncST(_) => write!(__mockall_fmt, "<single threaded function>"),
                        Matcher::Pred(__mockall_p) => {
                            write!(__mockall_fmt, #braces,
                                #(__mockall_p.#indices,)*)
                        }
                        _ => unreachable!(),
                    }
                }
            }
        ).to_tokens(tokens);
    }
}enum MockItemContent {
    Fn(MockFunction),
    Tokens(TokenStream)
}

pub(crate) struct MockItemModule {
    vis: Visibility,
    mock_ident: Ident,
    orig_ident: Option<Ident>,
    content: Vec<MockItemContent>
}

fn mock_fn(item_fn: ItemFn) -> ItemMod {
    let ident = format_ident!("__{}", item_fn.sig.ident);
    unimplemented!("5")
}

/// Generate a whole mod module from the mockable sort
impl From<MockableModule> for ItemMod {
    fn from(mod_: MockableModule) -> ItemMod {
        let attrs = Vec::new();
        let vis = mod_.vis;
        let mod_token = mod_.mod_token;
        let ident = mod_.mock_ident;
        let semi = None;
        let brace = token::Brace::default();

        let mut contents = Vec::<Item>::new();
        contents.push(Item::Verbatim(quote!(use super::T;)));
        for item in mod_.content.into_iter() {
            match item {
                Item::Fn(item_fn) => {
                    contents.push(
                        Item::Verbatim(quote!(#[allow(missing_docs)]))
                    );
                    contents.push(Item::Mod(mock_fn(item_fn)));
                },
                _ => {
                    compile_error(item.span(),
                        "Unsupported item type when mocking modules");
                }
            }
        }

        let content = Some((brace, contents));
        ItemMod {
            attrs,
            vis,
            mod_token,
            ident,
            content,
            semi
        }
    }
}

impl From<MockableModule> for MockItemModule {
    fn from(mod_: MockableModule) -> MockItemModule {
        let mock_ident = mod_.mock_ident.clone();
        let orig_ident = mod_.orig_ident;
        let content = mod_.content.into_iter().filter_map(|item| {
            let span = item.span();
            match item {
                Item::ExternCrate(_) | Item::Impl(_) =>
                {
                    // Ignore
                    None
                },
                Item::Static(is) => {
                    Some(MockItemContent::Tokens(is.into_token_stream()))
                },
                Item::Const(ic) => {
                    Some(MockItemContent::Tokens(ic.into_token_stream()))
                },
                Item::Fn(f) => {
                    Some(MockItemContent::Fn(
                        MockFunction::from((&mock_ident, f))
                    ))
                },
                Item::Mod(_) | Item::ForeignMod(_)
                    | Item::Struct(_) | Item::Enum(_)
                    | Item::Union(_) | Item::Trait(_) =>
                {
                    compile_error(span,
                        "Mockall does not yet support deriving nested mocks");
                    None
                },
                Item::Type(ty) => {
                    Some(MockItemContent::Tokens(ty.into_token_stream()))
                },
                Item::TraitAlias(ta) => {
                    Some(MockItemContent::Tokens(ta.into_token_stream()))
                },
                Item::Use(u) => {
                    Some(MockItemContent::Tokens(u.into_token_stream()))
                },
                _ => {
                    compile_error(span, "Unsupported item");
                    None
                }
            }
        }).collect::<Vec<_>>();

        MockItemModule {
            vis: mod_.vis,
            mock_ident: mod_.mock_ident,
            orig_ident,
            content
        }
    }
}

impl ToTokens for MockItemModule {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let mut body = TokenStream::new();
        let mut cp_body = TokenStream::new();
        let modname = &self.mock_ident;

        for item in self.content.iter() {
            match item {
                MockItemContent::Tokens(ts) => ts.to_tokens(&mut body),
                MockItemContent::Fn(f) => {
                    //let mod_ident = format_ident!("__{}", &f.sig.ident);
                    //quote!(
                        //let __mockall_timeses = #mod_ident::EXPECTATIONS.lock()
                            //.unwrap()
                            //.checkpoint()
                            //.collect::<Vec<_>>();
                    //).to_tokens(&mut cp_body);
                    f.to_tokens(&mut body);
                },
            }
        }

        quote!(
            /// Verify that all current expectations for this function are
            /// satisfied and clear them.
            pub fn checkpoint() { #cp_body }
        ).to_tokens(&mut body);
        let docstr = {
            let inner_ds = if let Some(ident) = &self.orig_ident {
                format!("Mock version of the `{}` module", ident)
            } else {
                format!("TODO: write doc string")
            };
            quote!( #[doc = #inner_ds])
        };
        quote!(
            #docstr
            pub mod #modname { #body }
        ).to_tokens(tokens);
    }
}
<|endoftext|>


<commit_before>use super::*;

use std::mem;

pub(crate) fn with_cstr<R, F>(s: &str, f: F) -> R
where
    F: FnOnce(*const c_char) -> R,
{
    let allocated;
    let mut buffer: [u8; 256] = unsafe { mem::uninitialized() };
    let ptr: *const c_char = if s.len() < buffer.len() {
        buffer[0..s.len()].clone_from_slice(s.as_bytes());
        buffer[s.len()] = 0;
        buffer.as_ptr() as *const c_char
    } else {
        allocated = Some(CString::new(s).unwrap());
        allocated.as_ref().unwrap().as_ptr()
    };
    f(ptr)
}

pub(crate) fn with_opt_cstr<R, F>(s: Option<&str>, f: F) -> R
where
    F: FnOnce(*const c_char) -> R,
{
    match s {
        Some(s) => with_cstr(s, f),
        None => f(ptr::null()),
    }
}

pub(crate) fn get_cstring<F>(f: F) -> CString
where
    F: Fn(*mut c_char, usize) -> usize,
{
    // Some SB API return the required size of the full string (SBThread::GetStopDescription()),
    // while others return the number of bytes actually written into the buffer (SBPath::GetPath()).
    // In the latter case we have to increase buffer capacity in a loop until the string fits.
    // There also seems to be lack of consensus on whether the terminating NUL should be included in the count or not...

    let buffer: [u8; 1024] = unsafe { mem::uninitialized() };
    let c_ptr = buffer.as_ptr() as *mut c_char;
    let size = f(c_ptr, buffer.len());
    assert!((size as isize) >= 0);
    if size < buffer.len() - 1 {
        // Must have at least 1 unused byte to be sure that we've received the whole string
        unsafe {
            return CStr::from_ptr(c_ptr).to_owned();
        }
    }

    let size_is_reliable = size > buffer.len();
    let capacity = if size_is_reliable {
        size + 1
    } else {
        buffer.len() * 2
    };
    let mut buffer = Vec::with_capacity(capacity);
    loop {
        let c_ptr = buffer.as_ptr() as *mut c_char;
        let size = f(c_ptr, buffer.capacity());
        assert!((size as isize) >= 0);
        if size < buffer.capacity() - 1 || size_is_reliable {
            assert!(size < buffer.capacity()); // should be true if size_is_reliable
            unsafe {
                let s = CStr::from_ptr(c_ptr); // Count bytes to NUL
                buffer.set_len(s.to_bytes().len());
                return CString::from_vec_unchecked(buffer);
            };
        }
        let capacity = buffer.capacity() * 2;
        buffer.reserve(capacity);
    }
}

pub(crate) unsafe fn get_str<'a>(ptr: *const c_char) -> &'a str {
    if ptr.is_null() {
        ""
    } else {
        CStr::from_ptr(ptr).to_str().unwrap()
    }
}

#[cfg(test)]
mod test {
    use super::*;

    fn store_as_cstr(s: &str, buff: *mut c_char, size: usize) -> usize {
        let b = unsafe { slice::from_raw_parts_mut(buff as *mut u8, size) };
        let s = s.as_bytes();
        if b.len() > s.len() {
            b[..s.len()].clone_from_slice(s);
            b[s.len()] = 0;
            s.len()
        } else {
            let max = b.len() - 1;
            b[..max].clone_from_slice(&s[..max]);
            b[max] = 0;
            max
        }
    }

    #[test]
    fn test_get_cstring() {
        use std::cell::RefCell;
        for n in 0..200 {
            let string = "0123456789ABC".repeat(n);
            let cstring = CString::new(string.clone()).unwrap();

            let iters = RefCell::new(0..2);
            assert_eq!(
                cstring,
                get_cstring(|buff, size| {
                    assert!(iters.borrow_mut().next().is_some());
                    store_as_cstr(&string, buff, size);
                    // Returns the required storage length
                    string.len()
                })
            );
            let iters = RefCell::new(0..2);
            assert_eq!(
                cstring,
                get_cstring(|buff, size| {
                    assert!(iters.borrow_mut().next().is_some());
                    store_as_cstr(&string, buff, size);
                    // Returns the required storage length, including NUL
                    string.len() + 1
                })
            );
            let iters = RefCell::new(0..100);
            assert_eq!(
                cstring,
                get_cstring(|buff, size| {
                    assert!(iters.borrow_mut().next().is_some());
                    // Returns stored length
                    store_as_cstr(&string, buff, size)
                })
            );
            let iters = RefCell::new(0..100);
            assert_eq!(
                cstring,
                get_cstring(|buff, size| {
                    assert!(iters.borrow_mut().next().is_some());
                    // Returns stored length, including NUL
                    store_as_cstr(&string, buff, size) + 1
                })
            );
        }
    }
}
<commit_msg>Don't panic on invalid UTF8 returned from LLDB.<commit_after>use super::*;

use std::mem;

pub(crate) fn with_cstr<R, F>(s: &str, f: F) -> R
where
    F: FnOnce(*const c_char) -> R,
{
    let allocated;
    let mut buffer: [u8; 256] = unsafe { mem::uninitialized() };
    let ptr: *const c_char = if s.len() < buffer.len() {
        buffer[0..s.len()].clone_from_slice(s.as_bytes());
        buffer[s.len()] = 0;
        buffer.as_ptr() as *const c_char
    } else {
        allocated = Some(CString::new(s).unwrap());
        allocated.as_ref().unwrap().as_ptr()
    };
    f(ptr)
}

pub(crate) fn with_opt_cstr<R, F>(s: Option<&str>, f: F) -> R
where
    F: FnOnce(*const c_char) -> R,
{
    match s {
        Some(s) => with_cstr(s, f),
        None => f(ptr::null()),
    }
}

pub(crate) fn get_cstring<F>(f: F) -> CString
where
    F: Fn(*mut c_char, usize) -> usize,
{
    // Some SB API return the required size of the full string (SBThread::GetStopDescription()),
    // while others return the number of bytes actually written into the buffer (SBPath::GetPath()).
    // In the latter case we have to increase buffer capacity in a loop until the string fits.
    // There also seems to be lack of consensus on whether the terminating NUL should be included in the count or not...

    let buffer: [u8; 1024] = unsafe { mem::uninitialized() };
    let c_ptr = buffer.as_ptr() as *mut c_char;
    let size = f(c_ptr, buffer.len());
    assert!((size as isize) >= 0);
    if size < buffer.len() - 1 {
        // Must have at least 1 unused byte to be sure that we've received the whole string
        unsafe {
            return CStr::from_ptr(c_ptr).to_owned();
        }
    }

    let size_is_reliable = size > buffer.len();
    let capacity = if size_is_reliable {
        size + 1
    } else {
        buffer.len() * 2
    };
    let mut buffer = Vec::with_capacity(capacity);
    loop {
        let c_ptr = buffer.as_ptr() as *mut c_char;
        let size = f(c_ptr, buffer.capacity());
        assert!((size as isize) >= 0);
        if size < buffer.capacity() - 1 || size_is_reliable {
            assert!(size < buffer.capacity()); // should be true if size_is_reliable
            unsafe {
                let s = CStr::from_ptr(c_ptr); // Count bytes to NUL
                buffer.set_len(s.to_bytes().len());
                return CString::from_vec_unchecked(buffer);
            };
        }
        let capacity = buffer.capacity() * 2;
        buffer.reserve(capacity);
    }
}

pub(crate) unsafe fn get_str<'a>(ptr: *const c_char) -> &'a str {
    if ptr.is_null() {
        ""
    } else {
        let cstr = CStr::from_ptr(ptr);
        match cstr.to_str() {
            Ok(val) => val,
            Err(err) => str::from_utf8(&cstr.to_bytes()[..err.valid_up_to()]).unwrap(),
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    fn store_as_cstr(s: &str, buff: *mut c_char, size: usize) -> usize {
        let b = unsafe { slice::from_raw_parts_mut(buff as *mut u8, size) };
        let s = s.as_bytes();
        if b.len() > s.len() {
            b[..s.len()].clone_from_slice(s);
            b[s.len()] = 0;
            s.len()
        } else {
            let max = b.len() - 1;
            b[..max].clone_from_slice(&s[..max]);
            b[max] = 0;
            max
        }
    }

    #[test]
    fn test_get_cstring() {
        use std::cell::RefCell;
        for n in 0..200 {
            let string = "0123456789ABC".repeat(n);
            let cstring = CString::new(string.clone()).unwrap();

            let iters = RefCell::new(0..2);
            assert_eq!(
                cstring,
                get_cstring(|buff, size| {
                    assert!(iters.borrow_mut().next().is_some());
                    store_as_cstr(&string, buff, size);
                    // Returns the required storage length
                    string.len()
                })
            );
            let iters = RefCell::new(0..2);
            assert_eq!(
                cstring,
                get_cstring(|buff, size| {
                    assert!(iters.borrow_mut().next().is_some());
                    store_as_cstr(&string, buff, size);
                    // Returns the required storage length, including NUL
                    string.len() + 1
                })
            );
            let iters = RefCell::new(0..100);
            assert_eq!(
                cstring,
                get_cstring(|buff, size| {
                    assert!(iters.borrow_mut().next().is_some());
                    // Returns stored length
                    store_as_cstr(&string, buff, size)
                })
            );
            let iters = RefCell::new(0..100);
            assert_eq!(
                cstring,
                get_cstring(|buff, size| {
                    assert!(iters.borrow_mut().next().is_some());
                    // Returns stored length, including NUL
                    store_as_cstr(&string, buff, size) + 1
                })
            );
        }
    }

    #[test]
    fn test_get_str() {
        assert_eq!(unsafe { get_str(b"foo\0".as_ptr() as *const c_char) }, "foo");
        assert_eq!(unsafe { get_str(b"bar\x80\0".as_ptr() as *const c_char) }, "bar");
        assert_eq!(unsafe { get_str(b"\x80\0".as_ptr() as *const c_char) }, "");
    }
}
<|endoftext|>


<commit_before>use crate::ram::chunk;
use crate::ram::types;

pub const CHUNK_SIZE: usize = 2048;

macro_rules! test_nums {
    (
        $t:ident, $io:ident
    ) => {
        mod $t {
            use super::CHUNK_SIZE;
            use crate::ram::chunk::Chunks;
            use crate::ram::types;
            use rand;
            use std;
            #[test]
            fn test() {
                let rand_num = rand::random::<$t>();
                let test_data = vec![
                    std::$t::MIN,
                    std::$t::MAX,
                    rand_num,
                    0 as $t,
                    1 as $t,
                    2 as $t,
                    127 as $t,
                ];
                let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
                let counts = CHUNK_SIZE / types::$io::size(0) as usize;
                let chunk_addr = chunk.segments()[0].addr;
                for d in test_data {
                    for i in 0..counts {
                        let addr = chunk_addr + i * types::$io::size(0);
                        types::$io::write(&d, addr);
                        assert!(types::$io::read(addr) == d);
                    }
                    for i in 0..counts {
                        let addr = chunk_addr + i * types::$io::size(0);
                        assert!(types::$io::read(addr) == d);
                    }
                }
            }
        }
    };
}

test_nums!(i8, i8_io);
test_nums!(i16, i16_io);
test_nums!(i32, i32_io);
test_nums!(i64, i64_io);

test_nums!(u8, u8_io);
test_nums!(u16, u16_io);
test_nums!(u32, u32_io);
test_nums!(u64, u64_io);

test_nums!(f32, f32_io);
test_nums!(f64, f64_io);

mod pos2d32 {
    use super::CHUNK_SIZE;
    use crate::ram::chunk::Chunks;
    use crate::ram::types;
    use rand;
    use std;
    #[test]
    fn test() {
        let test_data = vec![
            types::Pos2d32 {
                x: std::f32::MIN,
                y: std::f32::MAX,
            },
            types::Pos2d32 {
                x: rand::random::<f32>(),
                y: rand::random::<f32>(),
            },
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos2d32_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos2d32_io::size(0);
                types::pos2d32_io::write(&d, addr);
                assert_eq!(types::pos2d32_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos2d32_io::size(0);
                assert_eq!(types::pos2d32_io::read(addr), d);
            }
        }
    }
}

mod pos2d64 {
    use super::CHUNK_SIZE;
    use crate::ram::chunk::Chunks;
    use crate::ram::types;
    use rand;
    use std;
    #[test]
    fn test() {
        let test_data = vec![
            types::Pos2d64 {
                x: std::f64::MIN,
                y: std::f64::MAX,
            },
            types::Pos2d64 {
                x: rand::random::<f64>(),
                y: rand::random::<f64>(),
            },
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos2d64_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos2d64_io::size(0);
                types::pos2d64_io::write(&d, addr);
                assert_eq!(types::pos2d64_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos2d64_io::size(0);
                assert_eq!(types::pos2d64_io::read(addr), d);
            }
        }
    }
}

mod pos3d32 {
    use super::CHUNK_SIZE;
    use crate::ram::chunk::Chunks;
    use crate::ram::types;
    use rand;
    use std;
    #[test]
    fn test() {
        let test_data = vec![
            types::Pos3d32 {
                x: std::f32::MIN,
                y: std::f32::MAX,
                z: rand::random::<f32>(),
            },
            types::Pos3d32 {
                x: rand::random::<f32>(),
                y: rand::random::<f32>(),
                z: rand::random::<f32>(),
            },
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos3d32_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos3d32_io::size(0);
                types::pos3d32_io::write(&d, addr);
                assert_eq!(types::pos3d32_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos3d32_io::size(0);
                assert_eq!(types::pos3d32_io::read(addr), d);
            }
        }
    }
}

mod pos3d64 {
    use super::CHUNK_SIZE;
    use crate::ram::chunk::Chunks;
    use crate::ram::types;
    use rand;
    use std;
    #[test]
    fn test() {
        let test_data = vec![
            types::Pos3d64 {
                x: std::f64::MIN,
                y: std::f64::MAX,
                z: rand::random::<f64>(),
            },
            types::Pos3d64 {
                x: rand::random::<f64>(),
                y: rand::random::<f64>(),
                z: rand::random::<f64>(),
            },
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos3d64_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos3d64_io::size(0);
                types::pos3d64_io::write(&d, addr);
                assert_eq!(types::pos3d64_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos3d64_io::size(0);
                assert_eq!(types::pos3d64_io::read(addr), d);
            }
        }
    }
}

mod uuid {
    use super::CHUNK_SIZE;
    use crate::ram::chunk::Chunks;
    use crate::ram::types;
    use crate::ram::types::Id;
    #[test]
    fn test() {
        let test_data = vec![Id {
            higher: 1,
            lower: 2,
        }];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::id_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::id_io::size(0);
                types::id_io::write(&d, addr);
                assert_eq!(types::id_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::id_io::size(0);
                assert_eq!(types::id_io::read(addr), d);
            }
        }
    }
}

mod string {
    use super::CHUNK_SIZE;
    use crate::ram::chunk::Chunks;
    use crate::ram::types;
    use std::string::String;
    #[test]
    fn test() {
        let test_data = vec![
            "",
            "ಬಾ ಇಲ್ಲಿ ಸಂಭವಿಸ",
            "中文测试文本",
            "Hello Test",
            "💖",
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let mut addr = chunk.segments()[0].addr;
        for d in test_data.clone() {
            let test_str = String::from(d);
            types::string_io::write(&test_str, addr);
            let len = types::string_io::size(addr);
            let dec_str = types::string_io::read(addr);
            assert_eq!(dec_str, test_str);
            println!("{}", dec_str);
            addr += len;
        }
        addr = chunk.segments()[0].addr;
        for d in test_data.clone() {
            let test_str = String::from(d);
            let len = types::string_io::size(addr);
            assert_eq!(types::string_io::read(addr), test_str);
            addr += len;
        }
    }
}

#[test]
fn array_len_type() {
    assert_eq!(
        types::u32_io::size(0),
        types::get_size(types::ARRAY_LEN_TYPE_ID, 0)
    )
}

#[test]
fn null_type() {
    assert_eq!(
        types::u8_io::size(0),
        types::get_size(types::NULL_TYPE_ID, 0)
    )
}

#[test]
fn _in_map() {
    let mut map2 = types::Map::new();
    map2.insert(&String::from("a"), types::Value::I32(1));
    map2.insert(&String::from("b"), types::Value::I64(2));

    let mut map = types::Map::new();
    map.insert(&String::from("A"), types::Value::I32(1));
    map.insert(&String::from("B"), types::Value::Map(map2));

    assert_eq!(map.get(&String::from("A")).I32().unwrap(), &1);
    assert_eq!(map.get_in(&["B", "a"]).I32().unwrap(), &1);

    map.set_in(&["B", "a"], types::Value::I32(20)).unwrap();
    assert_eq!(map.get_in(&["B", "a"]).I32().unwrap(), &20);

    map.update_in(&["B", "b"], |value: &mut types::Value| {
        assert_eq!(value.I64().unwrap(), &2);
        *value = types::Value::I64(30);
    });
    assert_eq!(map.get_in(&["B", "b"]).I64().unwrap(), &30);
}

#[test]
fn index_mut_map() {
    let mut value = types::Value::Map(types::Map::new());
    value["a"] = types::Value::String(String::from("A"));
    value["b"] = types::Value::Array(vec![types::Value::U64(5)]);
    assert_eq!(value["a"].String().unwrap(), &String::from("A"));
    assert_eq!(value["b"][0 as usize].U64().unwrap(), &5);
    value["b"][0 as usize] = types::Value::U64(10);
    assert_eq!(value["b"][0 as usize].U64().unwrap(), &10);
}

#[test]
fn num_cast() {
    assert_eq!(1u32, 1u64 as u32);
}
<commit_msg>tests relocating<commit_after>use crate::ram::chunk;
use crate::ram::types;

pub const CHUNK_SIZE: usize = 2048;

macro_rules! test_nums {
    (
        $t:ident, $io:ident
    ) => {
        mod $t {
            use super::CHUNK_SIZE;
            use crate::ram::chunk::Chunks;
            use crate::ram::types;
            use rand;
            use std;
            #[test]
            fn test() {
                let rand_num = rand::random::<$t>();
                let test_data = vec![
                    std::$t::MIN,
                    std::$t::MAX,
                    rand_num,
                    0 as $t,
                    1 as $t,
                    2 as $t,
                    127 as $t,
                ];
                let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
                let counts = CHUNK_SIZE / types::$io::size(0) as usize;
                let chunk_addr = chunk.segments()[0].addr;
                for d in test_data {
                    for i in 0..counts {
                        let addr = chunk_addr + i * types::$io::size(0);
                        types::$io::write(&d, addr);
                        assert!(types::$io::read(addr) == d);
                    }
                    for i in 0..counts {
                        let addr = chunk_addr + i * types::$io::size(0);
                        assert!(types::$io::read(addr) == d);
                    }
                }
            }
        }
    };
}

test_nums!(i8, i8_io);
test_nums!(i16, i16_io);
test_nums!(i32, i32_io);
test_nums!(i64, i64_io);

test_nums!(u8, u8_io);
test_nums!(u16, u16_io);
test_nums!(u32, u32_io);
test_nums!(u64, u64_io);

test_nums!(f32, f32_io);
test_nums!(f64, f64_io);

mod pos2d32 {
    use super::CHUNK_SIZE;
    use crate::ram::chunk::Chunks;
    use crate::ram::types;
    use rand;
    use std;
    #[test]
    fn test() {
        let test_data = vec![
            types::Pos2d32 {
                x: std::f32::MIN,
                y: std::f32::MAX,
            },
            types::Pos2d32 {
                x: rand::random::<f32>(),
                y: rand::random::<f32>(),
            },
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos2d32_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos2d32_io::size(0);
                types::pos2d32_io::write(&d, addr);
                assert_eq!(types::pos2d32_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos2d32_io::size(0);
                assert_eq!(types::pos2d32_io::read(addr), d);
            }
        }
    }
}

mod pos2d64 {
    use super::CHUNK_SIZE;
    use crate::ram::chunk::Chunks;
    use crate::ram::types;
    use rand;
    use std;
    #[test]
    fn test() {
        let test_data = vec![
            types::Pos2d64 {
                x: std::f64::MIN,
                y: std::f64::MAX,
            },
            types::Pos2d64 {
                x: rand::random::<f64>(),
                y: rand::random::<f64>(),
            },
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos2d64_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos2d64_io::size(0);
                types::pos2d64_io::write(&d, addr);
                assert_eq!(types::pos2d64_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos2d64_io::size(0);
                assert_eq!(types::pos2d64_io::read(addr), d);
            }
        }
    }
}

mod pos3d32 {
    use super::CHUNK_SIZE;
    use crate::ram::chunk::Chunks;
    use crate::ram::types;
    use rand;
    use std;
    #[test]
    fn test() {
        let test_data = vec![
            types::Pos3d32 {
                x: std::f32::MIN,
                y: std::f32::MAX,
                z: rand::random::<f32>(),
            },
            types::Pos3d32 {
                x: rand::random::<f32>(),
                y: rand::random::<f32>(),
                z: rand::random::<f32>(),
            },
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos3d32_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos3d32_io::size(0);
                types::pos3d32_io::write(&d, addr);
                assert_eq!(types::pos3d32_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos3d32_io::size(0);
                assert_eq!(types::pos3d32_io::read(addr), d);
            }
        }
    }
}

mod pos3d64 {
    use super::CHUNK_SIZE;
    use crate::ram::chunk::Chunks;
    use crate::ram::types;
    use rand;
    use std;
    #[test]
    fn test() {
        let test_data = vec![
            types::Pos3d64 {
                x: std::f64::MIN,
                y: std::f64::MAX,
                z: rand::random::<f64>(),
            },
            types::Pos3d64 {
                x: rand::random::<f64>(),
                y: rand::random::<f64>(),
                z: rand::random::<f64>(),
            },
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::pos3d64_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos3d64_io::size(0);
                types::pos3d64_io::write(&d, addr);
                assert_eq!(types::pos3d64_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::pos3d64_io::size(0);
                assert_eq!(types::pos3d64_io::read(addr), d);
            }
        }
    }
}

mod uuid {
    use super::CHUNK_SIZE;
    use crate::ram::chunk::Chunks;
    use crate::ram::types;
    use crate::ram::types::Id;
    #[test]
    fn test() {
        let test_data = vec![Id {
            higher: 1,
            lower: 2,
        }];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let counts = CHUNK_SIZE / types::id_io::size(0) as usize;
        let chunk_addr = chunk.segments()[0].addr;
        for d in test_data {
            for i in 0..counts {
                let addr = chunk_addr + i * types::id_io::size(0);
                types::id_io::write(&d, addr);
                assert_eq!(types::id_io::read(addr), d);
            }
            for i in 0..counts {
                let addr = chunk_addr + i * types::id_io::size(0);
                assert_eq!(types::id_io::read(addr), d);
            }
        }
    }
}

mod string {
    use super::CHUNK_SIZE;
    use crate::ram::chunk::Chunks;
    use crate::ram::types;
    use std::string::String;
    #[test]
    fn test() {
        let test_data = vec![
            "",
            "ಬಾ ಇಲ್ಲಿ ಸಂಭವಿಸ",
            "中文测试文本",
            "Hello Test",
            "🏳🌈",
        ];
        let chunk = &Chunks::new_dummy(1, CHUNK_SIZE).list[0];
        let mut addr = chunk.segments()[0].addr;
        for d in test_data.clone() {
            let test_str = String::from(d);
            types::string_io::write(&test_str, addr);
            let len = types::string_io::size(addr);
            let dec_str = types::string_io::read(addr);
            assert_eq!(dec_str, test_str);
            println!("{}", dec_str);
            addr += len;
        }
        addr = chunk.segments()[0].addr;
        for d in test_data.clone() {
            let test_str = String::from(d);
            let len = types::string_io::size(addr);
            assert_eq!(types::string_io::read(addr), test_str);
            addr += len;
        }
    }
}

#[test]
fn array_len_type() {
    assert_eq!(
        types::u32_io::size(0),
        types::get_size(types::ARRAY_LEN_TYPE_ID, 0)
    )
}

#[test]
fn null_type() {
    assert_eq!(
        types::u8_io::size(0),
        types::get_size(types::NULL_TYPE_ID, 0)
    )
}

#[test]
fn _in_map() {
    let mut map2 = types::Map::new();
    map2.insert(&String::from("a"), types::Value::I32(1));
    map2.insert(&String::from("b"), types::Value::I64(2));

    let mut map = types::Map::new();
    map.insert(&String::from("A"), types::Value::I32(1));
    map.insert(&String::from("B"), types::Value::Map(map2));

    assert_eq!(map.get(&String::from("A")).I32().unwrap(), &1);
    assert_eq!(map.get_in(&["B", "a"]).I32().unwrap(), &1);

    map.set_in(&["B", "a"], types::Value::I32(20)).unwrap();
    assert_eq!(map.get_in(&["B", "a"]).I32().unwrap(), &20);

    map.update_in(&["B", "b"], |value: &mut types::Value| {
        assert_eq!(value.I64().unwrap(), &2);
        *value = types::Value::I64(30);
    });
    assert_eq!(map.get_in(&["B", "b"]).I64().unwrap(), &30);
}

#[test]
fn index_mut_map() {
    let mut value = types::Value::Map(types::Map::new());
    value["a"] = types::Value::String(String::from("A"));
    value["b"] = types::Value::Array(vec![types::Value::U64(5)]);
    assert_eq!(value["a"].String().unwrap(), &String::from("A"));
    assert_eq!(value["b"][0 as usize].U64().unwrap(), &5);
    value["b"][0 as usize] = types::Value::U64(10);
    assert_eq!(value["b"][0 as usize].U64().unwrap(), &10);
}

#[test]
fn num_cast() {
    assert_eq!(1u32, 1u64 as u32);
}
<|endoftext|>