<commit_before>// (C)opyleft 2013 Frank Denis

/*!
 * Bindings for the GeoIP library
 */
#![desc = "Bindings for the GeoIP library."]
#![license = "BSD"]
#![crate_id = "geoip#0.1"]
#![crate_type = "rlib"]

#![warn(non_camel_case_types,
        non_uppercase_statics,
        unnecessary_qualification,
        managed_heap_memory)]

extern crate libc;

use libc::{c_void, c_char, c_int, c_ulong, c_float};
use std::c_str::CString;
use std::fmt;
use std::io::net::ip::{IpAddr,Ipv4Addr,Ipv6Addr};

type GeoIP_ = *c_void;
type In6Addr = [u8, ..16];

struct GeoIPLookup_ {
    netmask: c_int
}

impl GeoIPLookup_ {
    fn new() -> GeoIPLookup_ {
        GeoIPLookup_ {
            netmask: 0
        }
    }
}

#[link(name = "GeoIP")]
extern {
    fn GeoIP_open(dbtype: *c_char, flags: c_int) -> GeoIP_;
    fn GeoIP_delete(db: GeoIP_);
    fn GeoIP_name_by_ipnum_gl(db: GeoIP_, ipnum: c_ulong, gl: &GeoIPLookup_) -> *c_char;
    fn GeoIP_name_by_ipnum_v6_gl(db: GeoIP_, ipnum: In6Addr, gl: &GeoIPLookup_) -> *c_char;
    fn GeoIP_record_by_ipnum(db: GeoIP_, ipnum: c_ulong) -> *GeoIPRecord_;
    fn GeoIP_record_by_ipnum_v6(db: GeoIP_, ipnum: In6Addr) -> *GeoIPRecord_;
    fn GeoIPRecord_delete(gir: *GeoIPRecord_);
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

pub struct GeoIP {
    db: GeoIP_
}

pub struct GeoIPRecord_ {
    country_code: *c_char,
    country_code3: *c_char,
    country_name: *c_char,
    region: *c_char,
    city: *c_char,
    postal_code: *c_char,
    latitude: c_float,
    longitude: c_float,
    dma_code: c_int,
    area_code: c_int,
    charset: c_int,
    continent_code: *c_char,
    netmask: c_int
}

pub struct ASInfo {
    pub asn: uint,
    pub name: String,
    pub netmask: uint
}

pub struct CityInfo {
    country_code: Option<String>,
    country_code3: Option<String>,
    country_name: Option<String>,
    region: Option<String>,
    city: Option<String>,
    postal_code: Option<String>,
    latitude: f32,
    longitude: f32,
    dma_code: uint,
    area_code: uint,
    charset: uint,
    continent_code: Option<String>,
    netmask: uint
}

impl CityInfo {
    fn from_geoiprecord(res: &GeoIPRecord_) -> CityInfo {
        let country_code = unsafe { if res.country_code.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.country_code, false).as_str().unwrap()))
        }};
        let country_code3 = unsafe { if res.country_code3.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.country_code3, false).as_str().unwrap()))
        }};
        let country_name = unsafe { if res.country_name.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.country_name, false).as_str().unwrap()))
        }};
        let region = unsafe { if res.region.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.region, false).as_str().unwrap()))
        }};
        let city = unsafe { if res.city.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.city, false).as_str().unwrap()))
        }};
        let postal_code = unsafe { if res.postal_code.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.postal_code, false).as_str().unwrap()))
        }};
        let continent_code = unsafe { if res.continent_code.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.continent_code, false).as_str().unwrap()))
        }};
        CityInfo {
            country_code: country_code,
            country_code3: country_code3,
            country_name: country_name,
            region: region,
            city: city,
            postal_code: postal_code,
            latitude: res.latitude as f32,
            longitude: res.longitude as f32,
            dma_code: res.dma_code as uint,
            area_code: res.area_code as uint,
            charset: res.charset as uint,
            continent_code: continent_code,
            netmask: res.netmask as uint
        }
    }
}

impl fmt::Show for ASInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}\t{}", self.asn, self.name)
    }
}

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, String> {
        let file = match path.as_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            GeoIP_open(file.to_c_str().unwrap(), options as c_int)
        };
        match db.is_null() {
            true => Err(format!("Can't open {}", file)),
            false => Ok(GeoIP {
                db: db
            })
        }
    }

    pub fn city_info_by_ip(&self, ip: IpAddr) -> Option<CityInfo> {
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_record_by_ipnum(self.db, ipnum)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_record_by_ipnum_v6(self.db, in6_addr)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let city_info = CityInfo::from_geoiprecord(&unsafe { *cres });
        unsafe { GeoIPRecord_delete(cres) };
        unsafe { std::mem::forget(cres) };
        Some(city_info)
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let gl = GeoIPLookup_::new();
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_name_by_ipnum_gl(self.db, ipnum, &gl)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_name_by_ipnum_v6_gl(self.db, in6_addr, &gl)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let description_cstr = unsafe { CString::new(cres, true) };
        let description = match description_cstr.as_str() {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(' ', 1);
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    from_str::<uint>(asn.slice_from(2)).unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let as_info = ASInfo {
            asn: asn,
            name: name.to_string(),
            netmask: gl.netmask as uint
        };
        Some(as_info)
    }
}

impl Drop for GeoIP {
    fn drop(&mut self) {
        unsafe {
            GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoIPASNum.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("91.203.184.192").unwrap();
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.as_slice().contains("Telefun"));
    assert!(res.netmask == 22);
}

#[test]
fn geoip_test_city() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoLiteCity.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("8.8.8.8").unwrap();
    let res = geoip.city_info_by_ip(ip).unwrap();
    assert!(res.city.unwrap().as_slice() == "Mountain View");
}
<commit_msg>Make CityInfo members public<commit_after>// (C)opyleft 2013 Frank Denis

/*!
 * Bindings for the GeoIP library
 */
#![desc = "Bindings for the GeoIP library."]
#![license = "BSD"]
#![crate_id = "geoip#0.1"]
#![crate_type = "rlib"]

#![warn(non_camel_case_types,
        non_uppercase_statics,
        unnecessary_qualification,
        managed_heap_memory)]

extern crate libc;

use libc::{c_void, c_char, c_int, c_ulong, c_float};
use std::c_str::CString;
use std::fmt;
use std::io::net::ip::{IpAddr,Ipv4Addr,Ipv6Addr};

type GeoIP_ = *c_void;
type In6Addr = [u8, ..16];

struct GeoIPLookup_ {
    netmask: c_int
}

impl GeoIPLookup_ {
    fn new() -> GeoIPLookup_ {
        GeoIPLookup_ {
            netmask: 0
        }
    }
}

#[link(name = "GeoIP")]
extern {
    fn GeoIP_open(dbtype: *c_char, flags: c_int) -> GeoIP_;
    fn GeoIP_delete(db: GeoIP_);
    fn GeoIP_name_by_ipnum_gl(db: GeoIP_, ipnum: c_ulong, gl: &GeoIPLookup_) -> *c_char;
    fn GeoIP_name_by_ipnum_v6_gl(db: GeoIP_, ipnum: In6Addr, gl: &GeoIPLookup_) -> *c_char;
    fn GeoIP_record_by_ipnum(db: GeoIP_, ipnum: c_ulong) -> *GeoIPRecord_;
    fn GeoIP_record_by_ipnum_v6(db: GeoIP_, ipnum: In6Addr) -> *GeoIPRecord_;
    fn GeoIPRecord_delete(gir: *GeoIPRecord_);
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

pub struct GeoIP {
    db: GeoIP_
}

pub struct GeoIPRecord_ {
    country_code: *c_char,
    country_code3: *c_char,
    country_name: *c_char,
    region: *c_char,
    city: *c_char,
    postal_code: *c_char,
    latitude: c_float,
    longitude: c_float,
    dma_code: c_int,
    area_code: c_int,
    charset: c_int,
    continent_code: *c_char,
    netmask: c_int
}

pub struct ASInfo {
    pub asn: uint,
    pub name: String,
    pub netmask: uint
}

pub struct CityInfo {
    pub country_code: Option<String>,
    pub country_code3: Option<String>,
    pub country_name: Option<String>,
    pub region: Option<String>,
    pub city: Option<String>,
    pub postal_code: Option<String>,
    pub latitude: f32,
    pub longitude: f32,
    pub dma_code: uint,
    pub area_code: uint,
    pub charset: uint,
    pub continent_code: Option<String>,
    pub netmask: uint
}

impl CityInfo {
    fn from_geoiprecord(res: &GeoIPRecord_) -> CityInfo {
        let country_code = unsafe { if res.country_code.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.country_code, false).as_str().unwrap()))
        }};
        let country_code3 = unsafe { if res.country_code3.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.country_code3, false).as_str().unwrap()))
        }};
        let country_name = unsafe { if res.country_name.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.country_name, false).as_str().unwrap()))
        }};
        let region = unsafe { if res.region.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.region, false).as_str().unwrap()))
        }};
        let city = unsafe { if res.city.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.city, false).as_str().unwrap()))
        }};
        let postal_code = unsafe { if res.postal_code.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.postal_code, false).as_str().unwrap()))
        }};
        let continent_code = unsafe { if res.continent_code.is_null() {
            None
        } else {
            Some(String::from_str(CString::new(res.continent_code, false).as_str().unwrap()))
        }};
        CityInfo {
            country_code: country_code,
            country_code3: country_code3,
            country_name: country_name,
            region: region,
            city: city,
            postal_code: postal_code,
            latitude: res.latitude as f32,
            longitude: res.longitude as f32,
            dma_code: res.dma_code as uint,
            area_code: res.area_code as uint,
            charset: res.charset as uint,
            continent_code: continent_code,
            netmask: res.netmask as uint
        }
    }
}

impl fmt::Show for ASInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}\t{}", self.asn, self.name)
    }
}

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, String> {
        let file = match path.as_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            GeoIP_open(file.to_c_str().unwrap(), options as c_int)
        };
        match db.is_null() {
            true => Err(format!("Can't open {}", file)),
            false => Ok(GeoIP {
                db: db
            })
        }
    }

    pub fn city_info_by_ip(&self, ip: IpAddr) -> Option<CityInfo> {
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_record_by_ipnum(self.db, ipnum)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_record_by_ipnum_v6(self.db, in6_addr)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let city_info = CityInfo::from_geoiprecord(&unsafe { *cres });
        unsafe { GeoIPRecord_delete(cres) };
        unsafe { std::mem::forget(cres) };
        Some(city_info)
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let gl = GeoIPLookup_::new();
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_name_by_ipnum_gl(self.db, ipnum, &gl)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_name_by_ipnum_v6_gl(self.db, in6_addr, &gl)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let description_cstr = unsafe { CString::new(cres, true) };
        let description = match description_cstr.as_str() {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(' ', 1);
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    from_str::<uint>(asn.slice_from(2)).unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let as_info = ASInfo {
            asn: asn,
            name: name.to_string(),
            netmask: gl.netmask as uint
        };
        Some(as_info)
    }
}

impl Drop for GeoIP {
    fn drop(&mut self) {
        unsafe {
            GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoIPASNum.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("91.203.184.192").unwrap();
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.as_slice().contains("Telefun"));
    assert!(res.netmask == 22);
}

#[test]
fn geoip_test_city() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoLiteCity.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("8.8.8.8").unwrap();
    let res = geoip.city_info_by_ip(ip).unwrap();
    assert!(res.city.unwrap().as_slice() == "Mountain View");
}
<|endoftext|>


<commit_before>
#![crate_name = "geoip"]
#![crate_type = "rlib"]

#![warn(non_camel_case_types,
        non_upper_case_globals,
        unused_qualifications)]
#![feature(libc)]

extern crate libc;
extern crate rustc_serialize;
extern crate geoip_sys;

use libc::{c_char, c_int, c_ulong};
use std::ffi;
use std::fmt;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::path::Path;

pub enum IpAddr {
    V4(Ipv4Addr),
    V6(Ipv6Addr)
}

enum Charset {
    UTF8 = 1
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

impl Copy for Options { }

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

impl Copy for DBType { }

pub struct GeoIp {
    db: geoip_sys::RawGeoIp
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct ASInfo {
    pub asn: u32,
    pub name: String,
    pub netmask: u32
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct CityInfo {
    pub country_code: Option<String>,
    pub country_code3: Option<String>,
    pub country_name: Option<String>,
    pub region: Option<String>,
    pub city: Option<String>,
    pub postal_code: Option<String>,
    pub latitude: f32,
    pub longitude: f32,
    pub dma_code: u32,
    pub area_code: u32,
    pub charset: u32,
    pub continent_code: Option<String>,
    pub netmask: u32
}

fn maybe_string(c_str: *const c_char) -> Option<String> {
    if c_str.is_null() {
        None
    } else {
        String::from_utf8(unsafe { ffi::CStr::from_ptr(c_str).to_bytes() }.
                          to_vec()).ok()
    }
}

impl CityInfo {
    unsafe fn from_geoiprecord(res: &geoip_sys::GeoIpRecord) -> CityInfo {
        CityInfo {
            country_code: maybe_string(res.country_code),
            country_code3: maybe_string(res.country_code3),
            country_name: maybe_string(res.country_name),
            region: maybe_string(res.region),
            city: maybe_string(res.city),
            postal_code: maybe_string(res.postal_code),
            latitude: res.latitude,
            longitude: res.longitude,
            dma_code: res.dma_code as u32,
            area_code: res.area_code as u32,
            charset: res.charset as u32,
            continent_code: maybe_string(res.continent_code),
            netmask: res.netmask as u32
        }
    }
}

impl fmt::Debug for ASInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}\t{}", self.asn, self.name)
    }
}

enum CNetworkIp {
    V4(c_ulong),
    V6(geoip_sys::In6Addr)
}

impl CNetworkIp {
    fn new(ip: IpAddr) -> CNetworkIp {
        match ip {
            IpAddr::V4(addr) => {
                let b = addr.octets();
                CNetworkIp::V4(((b[0] as c_ulong) << 24) |
                               ((b[1] as c_ulong) << 16) |
                               ((b[2] as c_ulong) << 8)  |
                               ((b[3] as c_ulong)))
            },
            IpAddr::V6(addr) => {
                let b = addr.segments();
                CNetworkIp::V6([(b[0] >> 8) as u8, b[0] as u8,
                                (b[1] >> 8) as u8, b[1] as u8,
                                (b[2] >> 8) as u8, b[2] as u8,
                                (b[3] >> 8) as u8, b[3] as u8,
                                (b[4] >> 8) as u8, b[4] as u8,
                                (b[5] >> 8) as u8, b[5] as u8,
                                (b[6] >> 8) as u8, b[6] as u8,
                                (b[7] >> 8) as u8, b[7] as u8])
            }
        }
    }
}

impl GeoIp {
    pub fn open(path: &Path, options: Options) -> Result<GeoIp, String> {
        let file = match path.to_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            geoip_sys::GeoIP_open(ffi::CString::new(file.as_bytes()).
                                  unwrap().as_ptr(), options as c_int)
        };
        if db.is_null() {
            return Err(format!("Can't open {}", file));
        }
        if unsafe { geoip_sys::GeoIP_set_charset(db, Charset::UTF8 as c_int)
        } != 0 {
            return Err("Can't set charset to UTF8".to_string());
        }
        Ok(GeoIp { db: db })
    }

    pub fn city_info_by_ip(&self, ip: IpAddr) -> Option<CityInfo> {
        let cres = match CNetworkIp::new(ip) {
            CNetworkIp::V4(ip) => unsafe {
                geoip_sys::GeoIP_record_by_ipnum(self.db, ip) },
            CNetworkIp::V6(ip) => unsafe {
                geoip_sys::GeoIP_record_by_ipnum_v6(self.db, ip) }
        };

        if cres.is_null() { return None; }

        unsafe {
            let city_info = CityInfo::from_geoiprecord(&*cres);
            geoip_sys::GeoIPRecord_delete(cres);
            std::mem::forget(cres);
            Some(city_info)
        }
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let mut gl = geoip_sys::GeoIpLookup::new();
        let cres = match CNetworkIp::new(ip) {
            CNetworkIp::V4(ip) => unsafe {
                geoip_sys::GeoIP_name_by_ipnum_gl(self.db, ip, &mut gl) },
            CNetworkIp::V6(ip) => unsafe {
                geoip_sys::GeoIP_name_by_ipnum_v6_gl(self.db, ip, &mut gl) }
        };

        if cres.is_null() {
            return None;
        }
        let description = match maybe_string(cres) {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(1, ' ');
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    asn[2..].parse::<u32>().unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let as_info = ASInfo {
            asn: asn,
            name: name.to_string(),
            netmask: gl.netmask as u32
        };
        Some(as_info)
    }
}

impl Drop for GeoIp {
    fn drop(&mut self) {
        unsafe {
            geoip_sys::GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIp::open(&Path::new("/opt/geoip/GeoIPASNum.dat"), Options::MemoryCache) {
        Err(err) => panic!(err),
        Ok(geoip) => geoip
    };
    let ip = IpAddr::V4("91.203.184.192".parse().unwrap());
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.contains("Telefun"));
    assert!(res.netmask == 22);
}

#[test]
fn geoip_test_city() {
    let geoip = match GeoIp::open(&Path::new("/opt/geoip/GeoLiteCity.dat"), Options::MemoryCache) {
        Err(err) => panic!(err),
        Ok(geoip) => geoip
    };
    let ip = IpAddr::V4("8.8.8.8".parse().unwrap());
    let res = geoip.city_info_by_ip(ip).unwrap();
    assert!(res.city.unwrap() == "Mountain View");
}
<commit_msg>IpAddr is back<commit_after>
#![crate_name = "geoip"]
#![crate_type = "rlib"]

#![warn(non_camel_case_types,
        non_upper_case_globals,
        unused_qualifications)]
#![feature(libc, ip_addr)]

extern crate libc;
extern crate rustc_serialize;
extern crate geoip_sys;

use libc::{c_char, c_int, c_ulong};
use std::ffi;
use std::fmt;
use std::net::IpAddr;
use std::path::Path;

enum Charset {
    UTF8 = 1
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

impl Copy for Options { }

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

impl Copy for DBType { }

pub struct GeoIp {
    db: geoip_sys::RawGeoIp
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct ASInfo {
    pub asn: u32,
    pub name: String,
    pub netmask: u32
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct CityInfo {
    pub country_code: Option<String>,
    pub country_code3: Option<String>,
    pub country_name: Option<String>,
    pub region: Option<String>,
    pub city: Option<String>,
    pub postal_code: Option<String>,
    pub latitude: f32,
    pub longitude: f32,
    pub dma_code: u32,
    pub area_code: u32,
    pub charset: u32,
    pub continent_code: Option<String>,
    pub netmask: u32
}

fn maybe_string(c_str: *const c_char) -> Option<String> {
    if c_str.is_null() {
        None
    } else {
        String::from_utf8(unsafe { ffi::CStr::from_ptr(c_str).to_bytes() }.
                          to_vec()).ok()
    }
}

impl CityInfo {
    unsafe fn from_geoiprecord(res: &geoip_sys::GeoIpRecord) -> CityInfo {
        CityInfo {
            country_code: maybe_string(res.country_code),
            country_code3: maybe_string(res.country_code3),
            country_name: maybe_string(res.country_name),
            region: maybe_string(res.region),
            city: maybe_string(res.city),
            postal_code: maybe_string(res.postal_code),
            latitude: res.latitude,
            longitude: res.longitude,
            dma_code: res.dma_code as u32,
            area_code: res.area_code as u32,
            charset: res.charset as u32,
            continent_code: maybe_string(res.continent_code),
            netmask: res.netmask as u32
        }
    }
}

impl fmt::Debug for ASInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}\t{}", self.asn, self.name)
    }
}

enum CNetworkIp {
    V4(c_ulong),
    V6(geoip_sys::In6Addr)
}

impl CNetworkIp {
    fn new(ip: IpAddr) -> CNetworkIp {
        match ip {
            IpAddr::V4(addr) => {
                let b = addr.octets();
                CNetworkIp::V4(((b[0] as c_ulong) << 24) |
                               ((b[1] as c_ulong) << 16) |
                               ((b[2] as c_ulong) << 8)  |
                               ((b[3] as c_ulong)))
            },
            IpAddr::V6(addr) => {
                let b = addr.segments();
                CNetworkIp::V6([(b[0] >> 8) as u8, b[0] as u8,
                                (b[1] >> 8) as u8, b[1] as u8,
                                (b[2] >> 8) as u8, b[2] as u8,
                                (b[3] >> 8) as u8, b[3] as u8,
                                (b[4] >> 8) as u8, b[4] as u8,
                                (b[5] >> 8) as u8, b[5] as u8,
                                (b[6] >> 8) as u8, b[6] as u8,
                                (b[7] >> 8) as u8, b[7] as u8])
            }
        }
    }
}

impl GeoIp {
    pub fn open(path: &Path, options: Options) -> Result<GeoIp, String> {
        let file = match path.to_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            geoip_sys::GeoIP_open(ffi::CString::new(file.as_bytes()).
                                  unwrap().as_ptr(), options as c_int)
        };
        if db.is_null() {
            return Err(format!("Can't open {}", file));
        }
        if unsafe { geoip_sys::GeoIP_set_charset(db, Charset::UTF8 as c_int)
        } != 0 {
            return Err("Can't set charset to UTF8".to_string());
        }
        Ok(GeoIp { db: db })
    }

    pub fn city_info_by_ip(&self, ip: IpAddr) -> Option<CityInfo> {
        let cres = match CNetworkIp::new(ip) {
            CNetworkIp::V4(ip) => unsafe {
                geoip_sys::GeoIP_record_by_ipnum(self.db, ip) },
            CNetworkIp::V6(ip) => unsafe {
                geoip_sys::GeoIP_record_by_ipnum_v6(self.db, ip) }
        };

        if cres.is_null() { return None; }

        unsafe {
            let city_info = CityInfo::from_geoiprecord(&*cres);
            geoip_sys::GeoIPRecord_delete(cres);
            std::mem::forget(cres);
            Some(city_info)
        }
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let mut gl = geoip_sys::GeoIpLookup::new();
        let cres = match CNetworkIp::new(ip) {
            CNetworkIp::V4(ip) => unsafe {
                geoip_sys::GeoIP_name_by_ipnum_gl(self.db, ip, &mut gl) },
            CNetworkIp::V6(ip) => unsafe {
                geoip_sys::GeoIP_name_by_ipnum_v6_gl(self.db, ip, &mut gl) }
        };

        if cres.is_null() {
            return None;
        }
        let description = match maybe_string(cres) {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(1, ' ');
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    asn[2..].parse::<u32>().unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let as_info = ASInfo {
            asn: asn,
            name: name.to_string(),
            netmask: gl.netmask as u32
        };
        Some(as_info)
    }
}

impl Drop for GeoIp {
    fn drop(&mut self) {
        unsafe {
            geoip_sys::GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIp::open(&Path::new("/opt/geoip/GeoIPASNum.dat"), Options::MemoryCache) {
        Err(err) => panic!(err),
        Ok(geoip) => geoip
    };
    let ip = IpAddr::V4("91.203.184.192".parse().unwrap());
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.contains("Telefun"));
    assert!(res.netmask == 22);
}

#[test]
fn geoip_test_city() {
    let geoip = match GeoIp::open(&Path::new("/opt/geoip/GeoLiteCity.dat"), Options::MemoryCache) {
        Err(err) => panic!(err),
        Ok(geoip) => geoip
    };
    let ip = IpAddr::V4("8.8.8.8".parse().unwrap());
    let res = geoip.city_info_by_ip(ip).unwrap();
    assert!(res.city.unwrap() == "Mountain View");
}
<|endoftext|>


<commit_before>//! Half-edge graph representation of meshes.
//!
//! This module provides a flexible representation of meshes as a [half-edge
//! graph](https://en.wikipedia.org/wiki/doubly_connected_edge_list). Meshes
//! can store arbitrary geometric data associated with any topological
//! structure (vertices, half-edges, and faces).
//!
//! Geometry is vertex-based, meaning that geometric operations depend on
//! vertices exposing some notion of positional data. See the `geometry` module
//! and `AsPosition` trait. If geometry does not have this property, then most
//! useful spatial operations will not be available.
//!
//! # Representation
//!
//! A `MeshGraph` is conceptually composed of _vertices_, _half-edges_, and
//! _faces_. The figure below summarizes the connectivity in a `MeshGraph`.
//!
//! ![Half-Edge Graph Figure](https://raw.githubusercontent.com/olson-sean-k/plexus/master/doc/heg.svg?sanitize=true)
//!
//! Half-edges are directed and connect vertices. A half-edge that is directed
//! toward a vertex **A** is an _incoming half-edge_ with respect to **A**.
//! Similarly, a half-edge directed away from such a vertex is an _outgoing
//! half-edge_. Every vertex is associated with exactly one _leading
//! half-edge_, which is always an outgoing half-edge. The vertex toward which
//! a half-edge is directed is the half-edge's _destination vertex_ and the
//! other is its _source vertex_.
//!
//! Every half-edge is paired with an _opposite half-edge_ with the opposite
//! direction. Given a half-edge from a vertex **A** to a vertex **B**, that
//! half-edge will have an opposite half-edge from **B** to **A**. Such edges
//! are typically labeled **AB** and **BA**. Together, these half-edges form a
//! _composite edge_. When the term "edge" is used alone, it generally refers
//! to a half-edge.
//!
//! Half-edges are connected to their neighbors, known as _next_ and _previous
//! half-edges_. When a face is present in the contiguous region formed by a
//! perimeter of vertices and their half-edges, the half-edges will refer to
//! that face and the face will refer to exactly one of the half-edges in the
//! interior. A half-edge with no associated face is known as a _boundary
//! half-edge_.
//!
//! Together with vertices and faces, the connectivity of half-edges allows for
//! effecient traversals of topology. For example, it becomes trivial to find
//! neighboring topologies, such as the faces that share a given vertex or the
//! neighboring faces of a given face.
//!
//! `MeshGraph`s store topological data using associative collections and mesh
//! data is accessed using keys into this storage. Keys are exposed as strongly
//! typed and opaque values, which can be used to refer to a topological
//! structure, such as `VertexKey`. Topology is typically manipulated using a
//! _view_, such as `VertexView` (see below).
//!
//! # Topological Views
//!
//! `MeshGraph`s expose _views_ over their topological structures (vertices,
//! edges, and faces). Views are accessed via keys or iteration and behave
//! similarly to references. They provide the primary API for interacting with
//! a `MeshGraph`'s topology and geometry. There are three types summarized
//! below:
//!
//! | Type      | Traversal | Exclusive | Geometry  | Topology  |
//! |-----------|-----------|-----------|-----------|-----------|
//! | Immutable | Yes       | No        | Immutable | Immutable |
//! | Mutable   | Yes       | Yes       | Mutable   | Mutable   |
//! | Orphan    | No        | No        | Mutable   | N/A       |
//!
//! _Immutable_ and _mutable views_ behave similarly to references. Immutable
//! views cannot mutate a mesh in any way and it is possible to obtain multiple
//! such views at the same time. Mutable views are exclusive, but allow for
//! mutations.
//!
//! _Orphan views_ are similar to mutable views, but they only have access to the
//! geometry of a single topological structure in a mesh. Because they do not
//! know about other vertices, edges, or faces, an orphan view cannot traverse
//! the topology of a mesh in any way. These views are most useful for
//! modifying the geometry of a mesh and, unlike mutable views, multiple orphan
//! views can be obtained at the same time. Orphan views are mostly used by
//! _circulators_ (iterators).
//!
//! Immutable and mutable views are both represented by view types, such as
//! `FaceView`. Orphan views are represented by an oprhan view type, such as
//! `OrphanFace`.
//!
//! # Circulators
//!
//! Topological views allow for traversals of a mesh's topology. One useful
//! type of traversal uses a _circulator_, which is a type of iterator that
//! examines the neighbors of a topological structure. For example, the face
//! circulator of a vertex yields all faces that share that vertex in order.
//!
//! Mutable circulators emit orphan views, not mutable views. This is because
//! it is not possible to instantiate more than one mutable view at a time. If
//! multiple mutable views are needed, it is possible to use an immutable
//! circulator to collect the keys of the target topology and then lookup each
//! mutable view using those keys.
//!
//! # Examples
//!
//! Generating a mesh from a UV-sphere:
//!
//! ```rust
//! # extern crate nalgebra;
//! # extern crate plexus;
//! use nalgebra::Point3;
//! use plexus::graph::MeshGraph;
//! use plexus::prelude::*;
//! use plexus::primitive::sphere::UvSphere;
//!
//! # fn main() {
//! let mut graph = UvSphere::new(16, 16)
//!     .polygons_with_position()
//!     .collect::<MeshGraph<Point3<f32>>>();
//! # }
//! ```
//!
//! Extruding a face in a mesh:
//!
//! ```rust
//! # extern crate nalgebra;
//! # extern crate plexus;
//! use nalgebra::Point3;
//! use plexus::graph::MeshGraph;
//! use plexus::prelude::*;
//! use plexus::primitive::sphere::UvSphere;
//!
//! # fn main() {
//! let mut graph = UvSphere::new(16, 16)
//!     .polygons_with_position()
//!     .collect::<MeshGraph<Point3<f32>>>();
//! let key = graph.faces().nth(0).unwrap().key(); // Get the key of the first face.
//! graph.face_mut(key).unwrap().extrude(1.0).unwrap(); // Extrude the face.
//! # }
//! ```
//!
//! Traversing and circulating over a mesh:
//!
//! ```rust
//! # extern crate nalgebra;
//! # extern crate plexus;
//! use nalgebra::Point2;
//! use plexus::graph::MeshGraph;
//! use plexus::prelude::*;
//!
//! # fn main() {
//! let mut graph = MeshGraph::<Point2<f32>>::from_raw_buffers_with_arity(
//!     vec![0u32, 1, 2, 3],
//!     vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)],
//!     4,
//! )
//! .unwrap();
//! graph.triangulate().unwrap();
//!
//! // Traverse an edge and use a circulator to get the faces of a nearby vertex.
//! let key = graph.edges().nth(0).unwrap().key();
//! let mut vertex = graph
//!     .edge_mut(key)
//!     .unwrap()
//!     .into_opposite_edge()
//!     .into_next_edge()
//!     .into_destination_vertex();
//! for mut face in vertex.neighboring_orphan_faces() {
//!     // `face.geometry` is mutable here.
//! }
//! # }
//! ```

mod container;
mod geometry;
mod mesh;
mod mutation;
mod storage;
mod topology;
mod view;

use failure::Error;

use crate::buffer::BufferError;

pub use self::mesh::MeshGraph;
pub use self::storage::{EdgeKey, FaceKey, VertexKey};
// TODO: It's unclear how view types should be exposed to users. Type aliases
//       for mutable, immutable, and orphan views over a `MeshGraph` would be
//       simpler and help insulate users from the complexity of views, but it
//       is currently not possible to document such aliases. See:
//       https://github.com/rust-lang/rust/issues/39437
//
//       Moreover, in the future it may be tenable to expose the internal
//       mutation APIs, and exposing the underlying view types would then be
//       necessary. For now, use them directly.
pub use self::view::{
    EdgeKeyTopology, EdgeView, FaceKeyTopology, FaceView, OrphanEdgeView, OrphanFaceView,
    OrphanVertexView, VertexView,
};

#[derive(Debug, Fail)]
pub enum GraphError {
    #[fail(display = "required topology not found")]
    TopologyNotFound,
    #[fail(display = "conflicting topology found")]
    TopologyConflict,
    #[fail(display = "topology malformed")]
    TopologyMalformed,
    #[fail(
        display = "conflicting arity; expected {}, but got {}",
        expected, actual
    )]
    ArityConflict { expected: usize, actual: usize },
    #[fail(display = "face arity is non-constant")]
    ArityNonConstant,
}

impl From<BufferError> for GraphError {
    fn from(_: BufferError) -> Self {
        // TODO: How should buffer errors be handled? Is this sufficient?
        GraphError::TopologyMalformed
    }
}

trait ResultExt<T>: Sized {
    /// If the `Result` is an error with the value
    /// `GraphError::TopologyConflict`, then the given function is executed and
    /// its `Result` is returned. Otherwise, the original `Result` is returned.
    ///
    /// Because this operates on the result of an operation, it does not cancel
    /// or negate any mutations that may have occurred.
    fn or_if_conflict<F>(self, f: F) -> Result<T, GraphError>
    where
        F: FnOnce() -> Result<T, GraphError>;
}

impl<T> ResultExt<T> for Result<T, Error> {
    fn or_if_conflict<F>(self, f: F) -> Result<T, GraphError>
    where
        F: FnOnce() -> Result<T, GraphError>,
    {
        self.map_err(|error| error.downcast::<GraphError>().unwrap())
            .or_if_conflict(f)
    }
}

impl<T> ResultExt<T> for Result<T, GraphError> {
    fn or_if_conflict<F>(self, f: F) -> Result<T, GraphError>
    where
        F: FnOnce() -> Result<T, GraphError>,
    {
        self.or_else(|error| match error {
            GraphError::TopologyConflict => f(),
            error => Err(error),
        })
    }
}

trait IteratorExt: Iterator + Sized {
    /// Provides an iterator over a window of duplets that includes the first
    /// value in the sequence at the beginning and end of the iteration.
    ///
    /// Given a collection with ordered elements `a`, `b`, and `c`, this
    /// iterator yeilds the ordered items `(a, b)`, `(b, c)`, `(c, a)`.
    fn perimeter(self) -> Perimeter<Self>
    where
        Self::Item: Copy;
}

impl<I> IteratorExt for I
where
    I: Iterator,
{
    fn perimeter(self) -> Perimeter<I>
    where
        I::Item: Copy,
    {
        Perimeter::new(self)
    }
}

struct Perimeter<I>
where
    I: Iterator,
    I::Item: Copy,
{
    input: I,
    first: Option<I::Item>,
    previous: Option<I::Item>,
}

impl<I> Perimeter<I>
where
    I: Iterator,
    I::Item: Copy,
{
    fn new(mut input: I) -> Self {
        let first = input.next();
        let previous = first;
        Perimeter {
            input,
            first,
            previous,
        }
    }
}

impl<I> Iterator for Perimeter<I>
where
    I: Iterator,
    I::Item: Copy,
{
    type Item = (I::Item, I::Item);

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.input.next();
        match (self.previous, next.or_else(|| self.first.take())) {
            (Some(a), Some(b)) => {
                self.previous = Some(b);
                Some((a, b))
            }
            _ => None,
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.input.size_hint()
    }
}
<commit_msg>Remove `ResultExt`.<commit_after>//! Half-edge graph representation of meshes.
//!
//! This module provides a flexible representation of meshes as a [half-edge
//! graph](https://en.wikipedia.org/wiki/doubly_connected_edge_list). Meshes
//! can store arbitrary geometric data associated with any topological
//! structure (vertices, half-edges, and faces).
//!
//! Geometry is vertex-based, meaning that geometric operations depend on
//! vertices exposing some notion of positional data. See the `geometry` module
//! and `AsPosition` trait. If geometry does not have this property, then most
//! useful spatial operations will not be available.
//!
//! # Representation
//!
//! A `MeshGraph` is conceptually composed of _vertices_, _half-edges_, and
//! _faces_. The figure below summarizes the connectivity in a `MeshGraph`.
//!
//! ![Half-Edge Graph Figure](https://raw.githubusercontent.com/olson-sean-k/plexus/master/doc/heg.svg?sanitize=true)
//!
//! Half-edges are directed and connect vertices. A half-edge that is directed
//! toward a vertex **A** is an _incoming half-edge_ with respect to **A**.
//! Similarly, a half-edge directed away from such a vertex is an _outgoing
//! half-edge_. Every vertex is associated with exactly one _leading
//! half-edge_, which is always an outgoing half-edge. The vertex toward which
//! a half-edge is directed is the half-edge's _destination vertex_ and the
//! other is its _source vertex_.
//!
//! Every half-edge is paired with an _opposite half-edge_ with the opposite
//! direction. Given a half-edge from a vertex **A** to a vertex **B**, that
//! half-edge will have an opposite half-edge from **B** to **A**. Such edges
//! are typically labeled **AB** and **BA**. Together, these half-edges form a
//! _composite edge_. When the term "edge" is used alone, it generally refers
//! to a half-edge.
//!
//! Half-edges are connected to their neighbors, known as _next_ and _previous
//! half-edges_. When a face is present in the contiguous region formed by a
//! perimeter of vertices and their half-edges, the half-edges will refer to
//! that face and the face will refer to exactly one of the half-edges in the
//! interior. A half-edge with no associated face is known as a _boundary
//! half-edge_.
//!
//! Together with vertices and faces, the connectivity of half-edges allows for
//! effecient traversals of topology. For example, it becomes trivial to find
//! neighboring topologies, such as the faces that share a given vertex or the
//! neighboring faces of a given face.
//!
//! `MeshGraph`s store topological data using associative collections and mesh
//! data is accessed using keys into this storage. Keys are exposed as strongly
//! typed and opaque values, which can be used to refer to a topological
//! structure, such as `VertexKey`. Topology is typically manipulated using a
//! _view_, such as `VertexView` (see below).
//!
//! # Topological Views
//!
//! `MeshGraph`s expose _views_ over their topological structures (vertices,
//! edges, and faces). Views are accessed via keys or iteration and behave
//! similarly to references. They provide the primary API for interacting with
//! a `MeshGraph`'s topology and geometry. There are three types summarized
//! below:
//!
//! | Type      | Traversal | Exclusive | Geometry  | Topology  |
//! |-----------|-----------|-----------|-----------|-----------|
//! | Immutable | Yes       | No        | Immutable | Immutable |
//! | Mutable   | Yes       | Yes       | Mutable   | Mutable   |
//! | Orphan    | No        | No        | Mutable   | N/A       |
//!
//! _Immutable_ and _mutable views_ behave similarly to references. Immutable
//! views cannot mutate a mesh in any way and it is possible to obtain multiple
//! such views at the same time. Mutable views are exclusive, but allow for
//! mutations.
//!
//! _Orphan views_ are similar to mutable views, but they only have access to the
//! geometry of a single topological structure in a mesh. Because they do not
//! know about other vertices, edges, or faces, an orphan view cannot traverse
//! the topology of a mesh in any way. These views are most useful for
//! modifying the geometry of a mesh and, unlike mutable views, multiple orphan
//! views can be obtained at the same time. Orphan views are mostly used by
//! _circulators_ (iterators).
//!
//! Immutable and mutable views are both represented by view types, such as
//! `FaceView`. Orphan views are represented by an oprhan view type, such as
//! `OrphanFace`.
//!
//! # Circulators
//!
//! Topological views allow for traversals of a mesh's topology. One useful
//! type of traversal uses a _circulator_, which is a type of iterator that
//! examines the neighbors of a topological structure. For example, the face
//! circulator of a vertex yields all faces that share that vertex in order.
//!
//! Mutable circulators emit orphan views, not mutable views. This is because
//! it is not possible to instantiate more than one mutable view at a time. If
//! multiple mutable views are needed, it is possible to use an immutable
//! circulator to collect the keys of the target topology and then lookup each
//! mutable view using those keys.
//!
//! # Examples
//!
//! Generating a mesh from a UV-sphere:
//!
//! ```rust
//! # extern crate nalgebra;
//! # extern crate plexus;
//! use nalgebra::Point3;
//! use plexus::graph::MeshGraph;
//! use plexus::prelude::*;
//! use plexus::primitive::sphere::UvSphere;
//!
//! # fn main() {
//! let mut graph = UvSphere::new(16, 16)
//!     .polygons_with_position()
//!     .collect::<MeshGraph<Point3<f32>>>();
//! # }
//! ```
//!
//! Extruding a face in a mesh:
//!
//! ```rust
//! # extern crate nalgebra;
//! # extern crate plexus;
//! use nalgebra::Point3;
//! use plexus::graph::MeshGraph;
//! use plexus::prelude::*;
//! use plexus::primitive::sphere::UvSphere;
//!
//! # fn main() {
//! let mut graph = UvSphere::new(16, 16)
//!     .polygons_with_position()
//!     .collect::<MeshGraph<Point3<f32>>>();
//! let key = graph.faces().nth(0).unwrap().key(); // Get the key of the first face.
//! graph.face_mut(key).unwrap().extrude(1.0).unwrap(); // Extrude the face.
//! # }
//! ```
//!
//! Traversing and circulating over a mesh:
//!
//! ```rust
//! # extern crate nalgebra;
//! # extern crate plexus;
//! use nalgebra::Point2;
//! use plexus::graph::MeshGraph;
//! use plexus::prelude::*;
//!
//! # fn main() {
//! let mut graph = MeshGraph::<Point2<f32>>::from_raw_buffers_with_arity(
//!     vec![0u32, 1, 2, 3],
//!     vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)],
//!     4,
//! )
//! .unwrap();
//! graph.triangulate().unwrap();
//!
//! // Traverse an edge and use a circulator to get the faces of a nearby vertex.
//! let key = graph.edges().nth(0).unwrap().key();
//! let mut vertex = graph
//!     .edge_mut(key)
//!     .unwrap()
//!     .into_opposite_edge()
//!     .into_next_edge()
//!     .into_destination_vertex();
//! for mut face in vertex.neighboring_orphan_faces() {
//!     // `face.geometry` is mutable here.
//! }
//! # }
//! ```

mod container;
mod geometry;
mod mesh;
mod mutation;
mod storage;
mod topology;
mod view;

use crate::buffer::BufferError;

pub use self::mesh::MeshGraph;
pub use self::storage::{EdgeKey, FaceKey, VertexKey};
// TODO: It's unclear how view types should be exposed to users. Type aliases
//       for mutable, immutable, and orphan views over a `MeshGraph` would be
//       simpler and help insulate users from the complexity of views, but it
//       is currently not possible to document such aliases. See:
//       https://github.com/rust-lang/rust/issues/39437
//
//       Moreover, in the future it may be tenable to expose the internal
//       mutation APIs, and exposing the underlying view types would then be
//       necessary. For now, use them directly.
pub use self::view::{
    EdgeKeyTopology, EdgeView, FaceKeyTopology, FaceView, OrphanEdgeView, OrphanFaceView,
    OrphanVertexView, VertexView,
};

#[derive(Debug, Fail)]
pub enum GraphError {
    #[fail(display = "required topology not found")]
    TopologyNotFound,
    #[fail(display = "conflicting topology found")]
    TopologyConflict,
    #[fail(display = "topology malformed")]
    TopologyMalformed,
    #[fail(
        display = "conflicting arity; expected {}, but got {}",
        expected, actual
    )]
    ArityConflict { expected: usize, actual: usize },
    #[fail(display = "face arity is non-constant")]
    ArityNonConstant,
}

impl From<BufferError> for GraphError {
    fn from(_: BufferError) -> Self {
        // TODO: How should buffer errors be handled? Is this sufficient?
        GraphError::TopologyMalformed
    }
}

trait IteratorExt: Iterator + Sized {
    /// Provides an iterator over a window of duplets that includes the first
    /// value in the sequence at the beginning and end of the iteration.
    ///
    /// Given a collection with ordered elements `a`, `b`, and `c`, this
    /// iterator yeilds the ordered items `(a, b)`, `(b, c)`, `(c, a)`.
    fn perimeter(self) -> Perimeter<Self>
    where
        Self::Item: Copy;
}

impl<I> IteratorExt for I
where
    I: Iterator,
{
    fn perimeter(self) -> Perimeter<I>
    where
        I::Item: Copy,
    {
        Perimeter::new(self)
    }
}

struct Perimeter<I>
where
    I: Iterator,
    I::Item: Copy,
{
    input: I,
    first: Option<I::Item>,
    previous: Option<I::Item>,
}

impl<I> Perimeter<I>
where
    I: Iterator,
    I::Item: Copy,
{
    fn new(mut input: I) -> Self {
        let first = input.next();
        let previous = first;
        Perimeter {
            input,
            first,
            previous,
        }
    }
}

impl<I> Iterator for Perimeter<I>
where
    I: Iterator,
    I::Item: Copy,
{
    type Item = (I::Item, I::Item);

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.input.next();
        match (self.previous, next.or_else(|| self.first.take())) {
            (Some(a), Some(b)) => {
                self.previous = Some(b);
                Some((a, b))
            }
            _ => None,
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.input.size_hint()
    }
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/calculate-amount-paid-in-taxes/
pub fn calculate_tax(brackets: Vec<Vec<i32>>, income: i32) -> f64 {
    todo!()
}

fn main() {
    println!(
        "{}",
        calculate_tax(vec![vec![3, 50], vec![7, 10], vec![12, 25]], 10)
    ); // 2.65000
    println!(
        "{}",
        calculate_tax(vec![vec![1, 0], vec![4, 25], vec![5, 50]], 2)
    ); // 0.25000
    println!("{}", calculate_tax(vec![vec![2, 50]], 0)); // 0.00000
}
<commit_msg>Solve problem 2303<commit_after>// https://leetcode.com/problems/calculate-amount-paid-in-taxes/
pub fn calculate_tax(brackets: Vec<Vec<i32>>, income: i32) -> f64 {
    let mut answer = 0.0;
    for (i, e) in brackets.iter().enumerate() {
        let upper = if income < e[0] { income } else { e[0] };
        let percent = &e[1];
        let mut prev = 0;
        if i > 0 {
            let p = &brackets[i - 1];
            prev = p[0];
        }
        let tax = (upper - prev) as f64 * (*percent as f64 / 100.0) as f64;
        answer += tax;
        if income < e[0] {
            break;
        }
    }
    answer
}

fn main() {
    println!(
        "{}",
        calculate_tax(vec![vec![3, 50], vec![7, 10], vec![12, 25]], 10)
    ); // 2.65000
    println!(
        "{}",
        calculate_tax(vec![vec![1, 0], vec![4, 25], vec![5, 50]], 2)
    ); // 0.25000
    println!("{}", calculate_tax(vec![vec![2, 50]], 0)); // 0.00000
}
<|endoftext|>


<commit_before>// Issue #53114: NLL's borrow check had some deviations from the old borrow
// checker, and both had some deviations from our ideal state. This test
// captures the behavior of how `_` bindings are handled wiith respect to how we
// flag expressions that are meant to request unsafe blocks.

#![feature(untagged_unions)]

struct I(i64);
struct F(f64);

union U { a: I, b: F }

#[repr(packed)]
struct P {
    a: &'static i8,
    b: &'static u32,
}

fn let_wild_gets_unsafe_field() {
    let u1 = U { a: I(0) };
    let u2 = U { a: I(1) };
    let p = P { a: &2, b: &3 };
    let _ = &p.b;  //~ WARN    E0133
    //~^  WARN will become a hard error
    let _ = u1.a;  // #53114: should eventually signal error as well
    let _ = &u2.a; //~ ERROR  [E0133]

    // variation on above with `_` in substructure
    let (_,) = (&p.b,);  //~ WARN     E0133
    //~^  WARN will become a hard error
    let (_,) = (u1.a,);  //~ ERROR   [E0133]
    let (_,) = (&u2.a,); //~ ERROR   [E0133]
}

fn match_unsafe_field_to_wild() {
    let u1 = U { a: I(0) };
    let u2 = U { a: I(1) };
    let p = P { a: &2, b: &3 };
    match &p.b  { _ => { } } //~ WARN     E0133
    //~^  WARN will become a hard error
    match u1.a  { _ => { } } //~ ERROR   [E0133]
    match &u2.a { _ => { } } //~ ERROR   [E0133]

    // variation on above with `_` in substructure
    match (&p.b,)  { (_,) => { } } //~ WARN     E0133
    //~^  WARN will become a hard error
    match (u1.a,)  { (_,) => { } } //~ ERROR   [E0133]
    match (&u2.a,) { (_,) => { } } //~ ERROR   [E0133]
}

fn main() { }
<commit_msg>Update src/test/ui/binding/issue-53114-safety-checks.rs<commit_after>// Issue #53114: NLL's borrow check had some deviations from the old borrow
// checker, and both had some deviations from our ideal state. This test
// captures the behavior of how `_` bindings are handled with respect to how we
// flag expressions that are meant to request unsafe blocks.

#![feature(untagged_unions)]

struct I(i64);
struct F(f64);

union U { a: I, b: F }

#[repr(packed)]
struct P {
    a: &'static i8,
    b: &'static u32,
}

fn let_wild_gets_unsafe_field() {
    let u1 = U { a: I(0) };
    let u2 = U { a: I(1) };
    let p = P { a: &2, b: &3 };
    let _ = &p.b;  //~ WARN    E0133
    //~^  WARN will become a hard error
    let _ = u1.a;  // #53114: should eventually signal error as well
    let _ = &u2.a; //~ ERROR  [E0133]

    // variation on above with `_` in substructure
    let (_,) = (&p.b,);  //~ WARN     E0133
    //~^  WARN will become a hard error
    let (_,) = (u1.a,);  //~ ERROR   [E0133]
    let (_,) = (&u2.a,); //~ ERROR   [E0133]
}

fn match_unsafe_field_to_wild() {
    let u1 = U { a: I(0) };
    let u2 = U { a: I(1) };
    let p = P { a: &2, b: &3 };
    match &p.b  { _ => { } } //~ WARN     E0133
    //~^  WARN will become a hard error
    match u1.a  { _ => { } } //~ ERROR   [E0133]
    match &u2.a { _ => { } } //~ ERROR   [E0133]

    // variation on above with `_` in substructure
    match (&p.b,)  { (_,) => { } } //~ WARN     E0133
    //~^  WARN will become a hard error
    match (u1.a,)  { (_,) => { } } //~ ERROR   [E0133]
    match (&u2.a,) { (_,) => { } } //~ ERROR   [E0133]
}

fn main() { }
<|endoftext|>


<commit_before>
use std::io;
use std::slice::Iter;

use parser::ast::*;
use processing::structs::*;
use output::scope::*;
use output::client_ops_writer::*;

#[inline]
pub fn write_js_var_reference(w: &mut io::Write,
                                    var_name: Option<&str>,
                                    doc: &DocumentState,
                                    scope_prefixes: &ScopePrefixes)
                                    -> Result {
    let default_var_scope = scope_prefixes.default_var_scope();
    if let Some(ref var_name) = var_name {
        let var_key = scope_prefixes.var_prefix(var_name);
        write!(w, "{}", var_key)?;
    } else {
        let default_var_scope = scope_prefixes.default_var_scope();
        let default_var = scope_prefixes.default_var();
        let var_key = default_var_scope
            .or_else(|| default_var)
            .unwrap_or("default".to_owned());
        write!(w, "{}", var_key)?;
    };

    // let state_key = "".to_owned();
    // let state_key = scope.state_lookup_key(var_name);
    // let is_scope_key = state_key.map_or(false, |s| doc.default_state_map.contains_key(s.as_str()));
    // let var_reference = scope.var_reference(is_scope_key, var_name);
    // write!(w, "{}", var_reference)?;
    // write!(w, "{}", var_key)?;
    Ok(())
}

#[inline]
pub fn write_js_expr_value(w: &mut io::Write,
                                node: &ExprValue,
                                doc: &DocumentState,
                                scope_prefixes: &ScopePrefixes)
                                -> Result {
    match node {
        // TODO: Handle the case where quotes appear in the string
        &ExprValue::LiteralString(ref s) => {
            write!(w, "\"{}\"", s)?;
        }
        &ExprValue::LiteralNumber(ref n) => {
            write!(w, "{}", n)?;
        }

        &ExprValue::LiteralArray(ref items) => {
            if let &Some(ref items) = items {
                write!(w, "[")?;
                for ref item in items {
                    write_js_expr_value(w, item, doc, scope_prefixes)?;
                }
                write!(w, "]")?;
            };
        }

        &ExprValue::DefaultVariableReference => {
            write_js_var_reference(w, None, doc, scope_prefixes)?;
        }

        &ExprValue::VariableReference(ref var_name) => {
            write_js_var_reference(w, Some(var_name.as_str()), doc, scope_prefixes)?;
        }

        &ExprValue::SymbolReference(ref sym) => {
            match sym {
                &(Some(ref sym), _) => {
                    match sym {
                        &SymbolReferenceType::LocalVarReference(ref var_name) => {
                            write_js_var_reference(w, Some(var_name.as_str()), doc, scope_prefixes)?;
                        }

                        &SymbolReferenceType::ParameterReference(ref param_key) => {
                            write_js_var_reference(w, Some(param_key.as_str()), doc, scope_prefixes)?;
                        }

                        &SymbolReferenceType::ReducerKeyReference(ref as_reducer_key) => {
                            write_js_var_reference(w, Some(as_reducer_key.as_str()), doc, scope_prefixes)?;
                        }

                        _ => {}
                    };
                }
                _ => {}
            };
        }

        // &ExprValue::Expr(ExprOp::Add, box ExprValue::DefaultVariableReference, ref r) => {
        //     // let state_ty = scope().unwrap().state_lookup_key(None);
        //     // let state_ty = state_ty.map_or(None, |s| doc.default_state_map.get(s.as_str()));

        //     // write!(w, "(")?;
        //     // write_js_var_reference(w, None, doc, scope)?;
        //     // if let Some(&(Some(VarType::ArrayVar(..)), _)) = state_ty {
        //     //     write!(w, ").concat(")?;
        //     // } else {
        //     //     write!(w, "+ (")?;
        //     // }
        //     // write_js_expr_value(w, r, doc, scope)?;
        //     // write!(w, ")")?;

        //     // let state_ty = scope().unwrap().state_lookup_key(None);
        //     // let state_ty = state_ty.map_or(None, |s| doc.default_state_map.get(s.as_str()));
        //     write!(w, "(")?;
        //     let
        //     write_js_expr_value(w, ExprValue::DefaultVariableReference, doc, scope_prefixes)?;
        //     // write_js_var_reference(w, None, doc, scope_prefixes)?;
        //     // if let Some(&(Some(VarType::ArrayVar(..)), _)) = state_ty {
        //         write!(w, ").concat(")?;
        //     // } else {
        //         // write!(w, "+ (")?;
        //     // }
        //     write_js_expr_value(w, r, doc, scope_prefixes)?;
        //     write!(w, ")")?;
        // }

        // &ExprValue::Expr(ExprOp::Add, box ExprValue::VariableReference(ref var_name), ref r) => {
        //     // let state_ty = scope.state_lookup_key(Some(var_name.as_str())).as_ref()
        //     //     .map_or(None, |s| doc.default_state_map.get(s.as_str()));

        //     // write!(w, "(")?;
        //     // write_js_var_reference(w, None, doc, scope)?;
        //     // if let Some(&(Some(VarType::ArrayVar(..)), _)) = state_ty {
        //     //     write!(w, ").concat(")?;
        //     // } else {
        //     //     write!(w, "+ (")?;
        //     // }
        //     // write_js_expr_value(w, r, doc, scope)?;
        //     // write!(w, ")")?;
        // }

        &ExprValue::Expr(ref op, box ExprValue::SymbolReference(ref l_sym), ref r) => {
            let is_array = match l_sym {
                &(Some(_), Some(VarType::ArrayVar(_))) => true,
                _ => false
            };

            match op {
                &ExprOp::Add if is_array => write!(w, ").concat("),
                &ExprOp::Add => write!(w, " + "),
                &ExprOp::Sub => write!(w, " - "),
                &ExprOp::Mul => write!(w, " * "),
                &ExprOp::Div => write!(w, " / ")
            }?;

            write_js_expr_value(w, r, doc, scope_prefixes)?;
            if is_array {
                write!(w, ")")?;
            };
        }

        &ExprValue::Expr(ref sym, ref l, ref r) => {
            write!(w, "(")?;
            write_js_expr_value(w, l, doc, scope_prefixes)?;
            match sym {
                &ExprOp::Add => {
                    write!(w, ").concat(")?;
                    // write!(w, " + ")?;
                }
                &ExprOp::Sub => {
                    write!(w, " - ")?;
                }
                &ExprOp::Mul => {
                    write!(w, " * ")?;
                }
                &ExprOp::Div => {
                    write!(w, " / ")?;
                }
            }
            write_js_expr_value(w, r, doc, scope_prefixes)?;
            write!(w, ")")?;
        }

        &ExprValue::ContentNode(..) => {}
        &ExprValue::DefaultAction(..) => {}
        &ExprValue::Action(..) => {}
    }
    Ok(())
}

#[inline]
#[allow(unused_variables)]
pub fn write_js_props_object<'input>(w: &mut io::Write,
                                props: Option<Iter<'input, Prop>>,
                                doc: &DocumentState,
                                scope_prefixes: &ScopePrefixes)
                        -> Result {
    write!(w, "{{")?;
    let mut wrote_first = false;
    if let Some(props) = props {
        for &(ref key, ref expr) in props {
            if wrote_first {
                write!(w, ", ")?
            } else {
                wrote_first = true;
            }

            // Write the property name
            write!(w, "\"{}\": ", key)?;

            // Write the property value or undefined for None
            if let &Some(ref expr) = expr {

                if let &ExprValue::DefaultAction(ref params, ref act_ops) = expr {
                    write!(w, "\"{}\", ", key)?;
                    write!(w, "function(event) {{")?;
                    if let &Some(ref act_ops) = act_ops {
                        for ref act_op in act_ops {
                            match *act_op {
                                &ActionOpNode::DispatchAction(ref action, ref params) => {
                                    write!(w, " store.dispatch({{\"type\": \"{}\"}}); ", action)?;
                                }
                            }
                        }
                    }
                    write!(w, "}}")?;
                    continue;
                };

                write_js_expr_value(w,
                                    &expr,
                                    doc,
                                    scope_prefixes)?;

            } else {
                write!(w, "undefined")?;
            }
        }
    };
    write!(w, "}}")?;
    Ok(())
}

#[inline]
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn write_js_incdom_attr_array<'input>(w: &mut io::Write,
                                    attrs: Option<Iter<'input, Prop>>,
                                    doc: &DocumentState,
                                    scope_prefixes: &ScopePrefixes,
                                    base_key: Option<&str>)
                                    -> Result {
    let mut wrote_first = false;
    if let Some(base_key) = base_key {
        write!(w, "\"data-id\", \"{}\", ", base_key)?;
    };

    if let Some(attrs) = attrs {
        for &(ref key, ref expr) in attrs {
            if let &Some(ref expr) = expr {
                if wrote_first {
                    write!(w, ", ")?
                } else {
                    wrote_first = true;
                }

                if let &ExprValue::DefaultAction(ref params, ref act_ops) = expr {
                    write!(w, "\"{}\", ", key)?;
                    write!(w, "function(event) {{")?;
                    if let &Some(ref act_ops) = act_ops {
                        for ref act_op in act_ops {
                            match *act_op {
                                &ActionOpNode::DispatchAction(ref action, ref params) => {
                                    write!(w, " store.dispatch({{\"type\": \"{}\"}}); ", action)?;
                                }
                            }
                        }
                    }
                    write!(w, "}}")?;
                    continue;
                };

                write!(w, "\"{}\", ", key)?;
                write_js_expr_value(w, expr, doc, scope_prefixes)?;
            } else {
                write!(w, "\"{}\", ", key)?;
                write!(w, "undefined")?;
            }
        }
    };
    Ok(())
}<commit_msg>Spoke a little too soon.<commit_after>
use std::io;
use std::slice::Iter;

use parser::ast::*;
use processing::structs::*;
use output::scope::*;
use output::client_ops_writer::*;

#[inline]
pub fn write_js_var_reference(w: &mut io::Write,
                                    var_name: Option<&str>,
                                    doc: &DocumentState,
                                    scope_prefixes: &ScopePrefixes)
                                    -> Result {
    let default_var_scope = scope_prefixes.default_var_scope();
    if let Some(ref var_name) = var_name {
        let var_key = scope_prefixes.var_prefix(var_name);
        write!(w, "{}", var_key)?;
    } else {
        let default_var_scope = scope_prefixes.default_var_scope();
        let default_var = scope_prefixes.default_var();
        let var_key = default_var_scope
            .or_else(|| default_var)
            .unwrap_or("default".to_owned());
        write!(w, "{}", var_key)?;
    };

    // let state_key = "".to_owned();
    // let state_key = scope.state_lookup_key(var_name);
    // let is_scope_key = state_key.map_or(false, |s| doc.default_state_map.contains_key(s.as_str()));
    // let var_reference = scope.var_reference(is_scope_key, var_name);
    // write!(w, "{}", var_reference)?;
    // write!(w, "{}", var_key)?;
    Ok(())
}

#[inline]
pub fn write_js_expr_value(w: &mut io::Write,
                                node: &ExprValue,
                                doc: &DocumentState,
                                scope_prefixes: &ScopePrefixes)
                                -> Result {
    match node {
        // TODO: Handle the case where quotes appear in the string
        &ExprValue::LiteralString(ref s) => {
            write!(w, "\"{}\"", s)?;
        }
        &ExprValue::LiteralNumber(ref n) => {
            write!(w, "{}", n)?;
        }

        &ExprValue::LiteralArray(ref items) => {
            if let &Some(ref items) = items {
                write!(w, "[")?;
                for ref item in items {
                    write_js_expr_value(w, item, doc, scope_prefixes)?;
                }
                write!(w, "]")?;
            };
        }

        &ExprValue::DefaultVariableReference => {
            write_js_var_reference(w, None, doc, scope_prefixes)?;
        }

        &ExprValue::VariableReference(ref var_name) => {
            write_js_var_reference(w, Some(var_name.as_str()), doc, scope_prefixes)?;
        }

        &ExprValue::SymbolReference(ref sym) => {
            match sym {
                &(Some(ref sym), _) => {
                    match sym {
                        &SymbolReferenceType::LocalVarReference(ref var_name) => {
                            write_js_var_reference(w, Some(var_name.as_str()), doc, scope_prefixes)?;
                        }

                        &SymbolReferenceType::ParameterReference(ref param_key) => {
                            write_js_var_reference(w, Some(param_key.as_str()), doc, scope_prefixes)?;
                        }

                        &SymbolReferenceType::ReducerKeyReference(ref as_reducer_key) => {
                            write_js_var_reference(w, Some(as_reducer_key.as_str()), doc, scope_prefixes)?;
                        }

                        _ => {}
                    };
                }
                _ => {}
            };
        }

        // &ExprValue::Expr(ExprOp::Add, box ExprValue::DefaultVariableReference, ref r) => {
        //     // let state_ty = scope().unwrap().state_lookup_key(None);
        //     // let state_ty = state_ty.map_or(None, |s| doc.default_state_map.get(s.as_str()));

        //     // write!(w, "(")?;
        //     // write_js_var_reference(w, None, doc, scope)?;
        //     // if let Some(&(Some(VarType::ArrayVar(..)), _)) = state_ty {
        //     //     write!(w, ").concat(")?;
        //     // } else {
        //     //     write!(w, "+ (")?;
        //     // }
        //     // write_js_expr_value(w, r, doc, scope)?;
        //     // write!(w, ")")?;

        //     // let state_ty = scope().unwrap().state_lookup_key(None);
        //     // let state_ty = state_ty.map_or(None, |s| doc.default_state_map.get(s.as_str()));
        //     write!(w, "(")?;
        //     let
        //     write_js_expr_value(w, ExprValue::DefaultVariableReference, doc, scope_prefixes)?;
        //     // write_js_var_reference(w, None, doc, scope_prefixes)?;
        //     // if let Some(&(Some(VarType::ArrayVar(..)), _)) = state_ty {
        //         write!(w, ").concat(")?;
        //     // } else {
        //         // write!(w, "+ (")?;
        //     // }
        //     write_js_expr_value(w, r, doc, scope_prefixes)?;
        //     write!(w, ")")?;
        // }

        // &ExprValue::Expr(ExprOp::Add, box ExprValue::VariableReference(ref var_name), ref r) => {
        //     // let state_ty = scope.state_lookup_key(Some(var_name.as_str())).as_ref()
        //     //     .map_or(None, |s| doc.default_state_map.get(s.as_str()));

        //     // write!(w, "(")?;
        //     // write_js_var_reference(w, None, doc, scope)?;
        //     // if let Some(&(Some(VarType::ArrayVar(..)), _)) = state_ty {
        //     //     write!(w, ").concat(")?;
        //     // } else {
        //     //     write!(w, "+ (")?;
        //     // }
        //     // write_js_expr_value(w, r, doc, scope)?;
        //     // write!(w, ")")?;
        // }

        &ExprValue::Expr(ref op, box ExprValue::SymbolReference(ref l_sym), ref r) => {
            let is_array = match l_sym {
                &(Some(_), Some(VarType::ArrayVar(_))) => true,
                _ => false
            };

            match op {
                &ExprOp::Add if is_array => write!(w, ".concat("),
                &ExprOp::Add => write!(w, " + "),
                &ExprOp::Sub => write!(w, " - "),
                &ExprOp::Mul => write!(w, " * "),
                &ExprOp::Div => write!(w, " / ")
            }?;

            write_js_expr_value(w, r, doc, scope_prefixes)?;
            if is_array {
                write!(w, ")")?;
            };
        }

        &ExprValue::Expr(ref sym, ref l, ref r) => {
            write_js_expr_value(w, l, doc, scope_prefixes)?;
            match sym {
                &ExprOp::Add => {
                    write!(w, " + ")?;
                }
                &ExprOp::Sub => {
                    write!(w, " - ")?;
                }
                &ExprOp::Mul => {
                    write!(w, " * ")?;
                }
                &ExprOp::Div => {
                    write!(w, " / ")?;
                }
            }
            write_js_expr_value(w, r, doc, scope_prefixes)?;
        }

        &ExprValue::ContentNode(..) => {}
        &ExprValue::DefaultAction(..) => {}
        &ExprValue::Action(..) => {}
    }
    Ok(())
}

#[inline]
#[allow(unused_variables)]
pub fn write_js_props_object<'input>(w: &mut io::Write,
                                props: Option<Iter<'input, Prop>>,
                                doc: &DocumentState,
                                scope_prefixes: &ScopePrefixes)
                        -> Result {
    write!(w, "{{")?;
    let mut wrote_first = false;
    if let Some(props) = props {
        for &(ref key, ref expr) in props {
            if wrote_first {
                write!(w, ", ")?
            } else {
                wrote_first = true;
            }

            // Write the property name
            write!(w, "\"{}\": ", key)?;

            // Write the property value or undefined for None
            if let &Some(ref expr) = expr {

                if let &ExprValue::DefaultAction(ref params, ref act_ops) = expr {
                    write!(w, "\"{}\", ", key)?;
                    write!(w, "function(event) {{")?;
                    if let &Some(ref act_ops) = act_ops {
                        for ref act_op in act_ops {
                            match *act_op {
                                &ActionOpNode::DispatchAction(ref action, ref params) => {
                                    write!(w, " store.dispatch({{\"type\": \"{}\"}}); ", action)?;
                                }
                            }
                        }
                    }
                    write!(w, "}}")?;
                    continue;
                };

                write_js_expr_value(w,
                                    &expr,
                                    doc,
                                    scope_prefixes)?;

            } else {
                write!(w, "undefined")?;
            }
        }
    };
    write!(w, "}}")?;
    Ok(())
}

#[inline]
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn write_js_incdom_attr_array<'input>(w: &mut io::Write,
                                    attrs: Option<Iter<'input, Prop>>,
                                    doc: &DocumentState,
                                    scope_prefixes: &ScopePrefixes,
                                    base_key: Option<&str>)
                                    -> Result {
    let mut wrote_first = false;
    if let Some(base_key) = base_key {
        write!(w, "\"data-id\", \"{}\", ", base_key)?;
    };

    if let Some(attrs) = attrs {
        for &(ref key, ref expr) in attrs {
            if let &Some(ref expr) = expr {
                if wrote_first {
                    write!(w, ", ")?
                } else {
                    wrote_first = true;
                }

                if let &ExprValue::DefaultAction(ref params, ref act_ops) = expr {
                    write!(w, "\"{}\", ", key)?;
                    write!(w, "function(event) {{")?;
                    if let &Some(ref act_ops) = act_ops {
                        for ref act_op in act_ops {
                            match *act_op {
                                &ActionOpNode::DispatchAction(ref action, ref params) => {
                                    write!(w, " store.dispatch({{\"type\": \"{}\"}}); ", action)?;
                                }
                            }
                        }
                    }
                    write!(w, "}}")?;
                    continue;
                };

                write!(w, "\"{}\", ", key)?;
                write_js_expr_value(w, expr, doc, scope_prefixes)?;
            } else {
                write!(w, "\"{}\", ", key)?;
                write!(w, "undefined")?;
            }
        }
    };
    Ok(())
}<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![deny(warnings)]
use std::thread; //~ ERROR: unused import
fn main() {}
<commit_msg>Improve previous compile fail test<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

#![deny(warnings)] //~ NOTE: lint level defined here
use std::thread; //~ ERROR: unused import
fn main() {}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// compile-flags: -Z parse-only

// Test that we generate obsolete syntax errors around usages of `proc`.

fn foo(p: proc()) { } //~ ERROR expected type, found reserved keyword `proc`

fn bar() { proc() 1; } //~ ERROR expected expression, found reserved keyword `proc`

fn main() { }
<commit_msg>Removed proc test<commit_after><|endoftext|>


<commit_before>// In this case, the code should compile and should
// succeed at runtime
use std;
import std::uint;

import std::vec::*;

fn main() {
    let a = 'a' as u8, j = 'j' as u8, k = 1u, l = 10u;
    // Silly, but necessary
    check le_u8(a, j);
    check uint::le(k, l);
    let chars = enum_chars(a, j);
    let ints  = enum_uints(k, l);

/*
    check same_length(chars, ints);
    let ps = zip(chars, ints);

    assert (head(ps) == ('a', 1u));
    assert (last(ps) == ('j' as u8, 10u));
*/
}<commit_msg>XFAIL zip-same-length -- that's ok, since it's a new test<commit_after>// xfail-stage1
// xfail-stage2
// xfail-stage3
// In this case, the code should compile and should
// succeed at runtime
use std;
import std::uint;
import std::u8;

import std::vec::*;

fn main() {
    let a = 'a' as u8, j = 'j' as u8, k = 1u, l = 10u;
    // Silly, but necessary
    check u8::le(a, j);
    check uint::le(k, l);
    let chars = enum_chars(a, j);
    let ints  = enum_uints(k, l);

    check same_length(chars, ints);
    let ps = zip(chars, ints);

    assert (head(ps) == ('a', 1u));
    assert (last(ps) == ('j' as u8, 10u));
}<|endoftext|>