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

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

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

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_ = *const c_void;
type In6Addr = [u8, ..16];

#[repr(C)]
struct GeoIPLookup_ {
    netmask: c_int
}

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

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

enum Charset {
    UTF8 = 1
}

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_
}

#[repr(C)]
pub struct GeoIPRecord_ {
    country_code: *const c_char,
    country_code3: *const c_char,
    country_name: *const c_char,
    region: *const c_char,
    city: *const c_char,
    postal_code: *const c_char,
    latitude: c_float,
    longitude: c_float,
    dma_code: c_int,
    area_code: c_int,
    charset: c_int,
    continent_code: *const 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 {
            CString::new(res.country_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let country_code3 = unsafe { if res.country_code3.is_null() {
            None
        } else {
            CString::new(res.country_code3, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let country_name = unsafe { if res.country_name.is_null() {
            None
        } else {
            CString::new(res.country_name, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let region = unsafe { if res.region.is_null() {
            None
        } else {
            CString::new(res.region, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let city = unsafe { if res.city.is_null() {
            None
        } else {
            CString::new(res.city, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let postal_code = unsafe { if res.postal_code.is_null() {
            None
        } else {
            CString::new(res.postal_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let continent_code = unsafe { if res.continent_code.is_null() {
            None
        } else {
            CString::new(res.continent_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        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)
        };
        if db.is_null() {
            return Err(format!("Can't open {}", file));
        }
        if unsafe { GeoIP_set_charset(db, 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 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) => panic!(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) => panic!(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>Update warn attributes<commit_after>// (C)opyleft 2013,2014 Frank Denis

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

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

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_ = *const c_void;
type In6Addr = [u8, ..16];

#[repr(C)]
struct GeoIPLookup_ {
    netmask: c_int
}

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

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

enum Charset {
    UTF8 = 1
}

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_
}

#[repr(C)]
pub struct GeoIPRecord_ {
    country_code: *const c_char,
    country_code3: *const c_char,
    country_name: *const c_char,
    region: *const c_char,
    city: *const c_char,
    postal_code: *const c_char,
    latitude: c_float,
    longitude: c_float,
    dma_code: c_int,
    area_code: c_int,
    charset: c_int,
    continent_code: *const 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 {
            CString::new(res.country_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let country_code3 = unsafe { if res.country_code3.is_null() {
            None
        } else {
            CString::new(res.country_code3, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let country_name = unsafe { if res.country_name.is_null() {
            None
        } else {
            CString::new(res.country_name, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let region = unsafe { if res.region.is_null() {
            None
        } else {
            CString::new(res.region, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let city = unsafe { if res.city.is_null() {
            None
        } else {
            CString::new(res.city, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let postal_code = unsafe { if res.postal_code.is_null() {
            None
        } else {
            CString::new(res.postal_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let continent_code = unsafe { if res.continent_code.is_null() {
            None
        } else {
            CString::new(res.continent_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        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)
        };
        if db.is_null() {
            return Err(format!("Can't open {}", file));
        }
        if unsafe { GeoIP_set_charset(db, 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 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) => panic!(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) => panic!(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>// (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)]

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

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;
}

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 ASInfo {
    asn: uint,
    name: ~str,
    netmask: uint
}

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

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, ~str> {
        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 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 asinfo = ASInfo {
            asn: asn,
            name: name.to_owned(),
            netmask: gl.netmask as uint
        };
        Some(asinfo)
    }
}

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.contains("Telefun"));
    assert!(res.netmask == 22);
}
<commit_msg>ASInfo fields can be 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)]

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

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;
}

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 ASInfo {
    pub asn: uint,
    pub name: ~str,
    pub netmask: uint
}

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

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, ~str> {
        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 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 asinfo = ASInfo {
            asn: asn,
            name: name.to_owned(),
            netmask: gl.netmask as uint
        };
        Some(asinfo)
    }
}

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.contains("Telefun"));
    assert!(res.netmask == 22);
}
<|endoftext|>


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

/*!
 * Bindings for the GeoIP library
 */
#[desc = "Bindings for the GeoIP library."];
#[license = "BSD"];
#[link(package_id = "geoip", name = "geoip", vers = "0.1")];
#[crate_type = "rlib"];

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

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

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: CString, 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;
}

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 {
    priv db: GeoIP_
}

pub struct ASInfo {
    asn: uint,
    name: ~str,
    netmask: uint
}

impl ToStr for ASInfo {
    fn to_str(&self) -> ~str {
        format!("{}\t{}", self.asn, self.name)
    }
}

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, ~str> {
        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(), options as c_int)
        };
        match db.is_null() {
            true => Err(format!("Can't open {}", file)),
            false => Ok(GeoIP {
                    db: db
                })
        }
    }

    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 asinfo = ASInfo {
            asn: asn,
            name: name.to_owned(),
            netmask: gl.netmask as uint
        };
        Some(asinfo)
    }
}

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.contains("Telefun"));
    assert!(res.netmask == 22);
}
<commit_msg>link -> crate_id<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)];

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

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: CString, 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;
}

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 {
    priv db: GeoIP_
}

pub struct ASInfo {
    asn: uint,
    name: ~str,
    netmask: uint
}

impl ToStr for ASInfo {
    fn to_str(&self) -> ~str {
        format!("{}\t{}", self.asn, self.name)
    }
}

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, ~str> {
        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(), options as c_int)
        };
        match db.is_null() {
            true => Err(format!("Can't open {}", file)),
            false => Ok(GeoIP {
                    db: db
                })
        }
    }

    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 asinfo = ASInfo {
            asn: asn,
            name: name.to_owned(),
            netmask: gl.netmask as uint
        };
        Some(asinfo)
    }
}

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.contains("Telefun"));
    assert!(res.netmask == 22);
}
<|endoftext|>


<commit_before>use clap::{App, Arg};
use std::process;

// This Struct is later given to our main program,
// it contains all the needed information to make suggestions of films
#[derive(Debug, Clone)]
pub struct SearchParams {
    genres: Vec<String>,
    movies: Vec<String>,
    actors: Vec<String>,
    rating: Vec<f32>,
}

impl SearchParams {
    // initialize a SearchParams type with empty fields
    fn init() -> Self {
        SearchParams {
            genres: Vec::new(),
            movies: Vec::new(),
            actors: Vec::new(),
            rating: Vec::new(),
        }
    }
}

// Creates struct SearchParams in which all given parameters are included.
pub fn get_search_params() -> SearchParams {
    // status of program
    println!("Getting Commandline Input ...");

    // later given to main program, contains all arguments given in
    // command line
    let mut search_params = SearchParams::init();

    // our matches, we can later use those to handle our commandline input
    let matches = App::new("Film-O-Mat")
        .arg(Arg::with_name("genre")
            .short("g")
            .help("Takes one or more genres")
            .takes_value(true)
            .multiple(true))
        .arg(Arg::with_name("actor")
            .short("a")
            .help("Takes an actor")
            .takes_value(true))
        .arg(Arg::with_name("movie")
            .short("m")
            .help("Takes one or more movies. e.g. \u{0022}Schindler's List\u{0022}")
            .takes_value(true)
            .multiple(true))
        .arg(Arg::with_name("rating")
            .short("r")
            .help("Takes a rating")
            .takes_value(true))
        .get_matches();

    // If a genre was given, save it in our SearchParams Type
    if matches.is_present("genre") {
        let genres: Vec<String> = match matches.values_of("genre") {
            Some(vals) => {
                vals.map(|x| x.to_string())
                    .collect()
            }
            None => {
                println!("Invalid Genre");
                process::exit(0);
            }
        };
        search_params.genres = genres;
        // Debug
        // println!("Genre: {}", genre);
    }

    // If an actor was given, save it in our SearchParams Type
    if matches.is_present("actor") {
        let actor = match matches.value_of("actor") {
            Some(actor) => actor,
            None => {
                println!("Invalid Actor");
                process::exit(0);
            }
        };
        search_params.actors.push(actor.into());
        // Debug
        // println!("Actor: {}", actor);
    }

    // If a genre was given, save it in our SearchParams Type
    if matches.is_present("movie") {
        let movies: Vec<String> = match matches.values_of("movie") {
            Some(vals) => {
                vals.map(|x| x.to_string())
                    .collect()
            }
            None => {
                println!("Invalid Movie");
                process::exit(0);
            }
        };
        search_params.movies = movies;
        // Debug
        // println!("Movies: {:?}", search_params.genre);
    }

    if matches.is_present("rating") {
        let val = match matches.value_of("rating") {
            Some(vals) => vals,
            None => {
                println!("Invalid Rating");
                process::exit(0);
            }
        };
        search_params.rating.push(
            match val.parse() {
                Ok(val) => val,
                Err(err) => {
                    println!("{:?}", err);
                    process::exit(0);
                }
            }
        );
        // Debug
        // println!("Rating: {:?}", search_params.rating);
    }

    // Debug
    // println!("{:?}", search_params);
    search_params
}
<commit_msg>added get_genres to SearchParams<commit_after>use clap::{App, Arg};
use std::process;

// This Struct is later given to our main program,
// it contains all the needed information to make suggestions of films
#[derive(Debug, Clone)]
pub struct SearchParams {
    genres: Vec<String>,
    movies: Vec<String>,
    actors: Vec<String>,
    rating: Vec<f32>,
}

impl SearchParams {
    // initialize a SearchParams type with empty fields
    fn init() -> Self {
        SearchParams {
            genres: Vec::new(),
            movies: Vec::new(),
            actors: Vec::new(),
            rating: Vec::new(),
        }
    }

    pub fn get_genres(&self) -> Vec<String> {
        self.genres.clone()
    }
}

// Creates struct SearchParams in which all given parameters are included.
pub fn get_search_params() -> SearchParams {
    // status of program
    println!("Getting Commandline Input ...");

    // later given to main program, contains all arguments given in
    // command line
    let mut search_params = SearchParams::init();

    // our matches, we can later use those to handle our commandline input
    let matches = App::new("Film-O-Mat")
        .arg(Arg::with_name("genre")
            .short("g")
            .help("Takes one or more genres")
            .takes_value(true)
            .multiple(true))
        .arg(Arg::with_name("actor")
            .short("a")
            .help("Takes an actor")
            .takes_value(true))
        .arg(Arg::with_name("movie")
            .short("m")
            .help("Takes one or more movies. e.g. \u{0022}Schindler's List\u{0022}")
            .takes_value(true)
            .multiple(true))
        .arg(Arg::with_name("rating")
            .short("r")
            .help("Takes a rating")
            .takes_value(true))
        .get_matches();

    // If a genre was given, save it in our SearchParams Type
    if matches.is_present("genre") {
        let genres: Vec<String> = match matches.values_of("genre") {
            Some(vals) => {
                vals.map(|x| x.to_string())
                    .collect()
            }
            None => {
                println!("Invalid Genre");
                process::exit(0);
            }
        };
        search_params.genres = genres;
        // Debug
        // println!("Genre: {}", genre);
    }

    // If an actor was given, save it in our SearchParams Type
    if matches.is_present("actor") {
        let actor = match matches.value_of("actor") {
            Some(actor) => actor,
            None => {
                println!("Invalid Actor");
                process::exit(0);
            }
        };
        search_params.actors.push(actor.into());
        // Debug
        // println!("Actor: {}", actor);
    }

    // If a genre was given, save it in our SearchParams Type
    if matches.is_present("movie") {
        let movies: Vec<String> = match matches.values_of("movie") {
            Some(vals) => {
                vals.map(|x| x.to_string())
                    .collect()
            }
            None => {
                println!("Invalid Movie");
                process::exit(0);
            }
        };
        search_params.movies = movies;
        // Debug
        // println!("Movies: {:?}", search_params.genre);
    }

    if matches.is_present("rating") {
        let val = match matches.value_of("rating") {
            Some(vals) => vals,
            None => {
                println!("Invalid Rating");
                process::exit(0);
            }
        };
        search_params.rating.push(match val.parse() {
            Ok(val) => val,
            Err(err) => {
                println!("{:?}", err);
                process::exit(0);
            }
        });
        // Debug
        // println!("Rating: {:?}", search_params.rating);
    }

    // Debug
    // println!("{:?}", search_params);
    search_params
}
<|endoftext|>


<commit_before>use memory::Memory;
use std::io;

#[allow(dead_assignment)]
pub fn interpret(str: String, mem: &mut Memory) {
	let test_arr = str.into_bytes();
	let mut test_ptr = 0u;

	while test_ptr < test_arr.len() {
		let mut ainc = true;
		match test_arr[test_ptr] as char {
			'>' => mem.fwd(),
			'+' => mem.inc(),
			'-' => mem.dcr(),
			'<' => mem.bck(),
			'!' => print!("{}", mem.get() as u8 as char),
			'*' => mem.lft(10),
			'/' => mem.dwn(10),
			')' => mem.adv(10),
			'(' => mem.rwd(10),
			'[' => {
				if mem.get() == 0 {
					while test_ptr < test_arr.len() && test_arr[test_ptr] as char != ']' {
						test_ptr += 1;
					}
					ainc = false;
				}
			},
			']' => {
				if mem.get() != 0 {
					while test_ptr > 0 && test_arr[test_ptr] as char != '[' {
						test_ptr -= 1;
					}
					ainc = false;
				}
			},
			'?' => print!("{}", mem.getptr()),
			'&' => print!("{}", mem.getptr() as u8 as char),
			'.' => print!("{}", mem.get()),
			'`' => {
				let inchr = match io::stdin().read_byte() {
					Ok(val) => val,
					Err(err) => {
						if err.kind != io::EndOfFile {
							fail!(err)
						}
						else {
							0 // EOF
						}
					}
				};

				mem.set(inchr as int);
			},
			'^' => mem.setptr(0),
			'#' => mem.set(0),
			_ => { /* We're a pretty ignorant parser... */ }
		}
		if ainc {
			test_ptr += 1;
		}
		ainc = true;
		//println!("{}", test_arr[test_ptr] as char);
	}

	// Prints the last accessed cell's value
	// println!("{}", mem.get());
}

/*
#[allow(dead_assignment)]
pub fn dummy_interpret(str: String, mem: &mut Memory) {
	let test_arr = str.into_bytes();
	let mut test_ptr = 0u;
	let mut input = io::stdin();

	while test_ptr < test_arr.len() {
		let mut ainc = true;
		match test_arr[test_ptr] as char {
			'>' => {println!("FWD"); mem.fwd()},
			'+' => {println!("INC"); mem.inc()},
			'-' => {println!("DCR"); mem.dcr()},
			'<' => {println!("BCK"); mem.bck()},
			'!' => println!("PCC*"),
			'*' => {println!("LFT"); mem.lft(10)},
			'/' => {println!("DWN"); mem.dwn(10)},
			')' => {println!("ADV"); mem.adv(10)},
			'(' => {println!("RWD"); mem.rwd(10)},
			'[' => {
				println!("LBL");
				if mem.get() == 0 {
					while test_ptr < test_arr.len() && test_arr[test_ptr] as char != ']' {
						test_ptr += 1;
					}
					ainc = false;
				}
			},
			']' => {
				println!("RBL");
				if mem.get() != 0 {
					while test_ptr > 0 && test_arr[test_ptr] as char != '[' {
						test_ptr -= 1;
					}
					ainc = false;
				}
			},
			'?' => println!("PPL*"),
			'&' => println!("PPC*"),
			'.' => println!("PCL*"),
			'`' => {
				println!("INP");
				let inchr = match input.read_byte() {
					Ok(val) => val,
					Err(err) => {
						if err.kind != io::EndOfFile {
							fail!(err)
						}
						else {
							0 // EOF
						}
					}
				};

				mem.set(inchr as int);
			},
			'^' => {println!("RPT"); mem.setptr(0)},
			'#' => {println!("RCV"); mem.set(0)},
			_ => { }
		}
		if ainc {
			test_ptr += 1;
		}
		ainc = true;
		//println!("{}", test_arr[test_ptr] as char);
	}
}
*/<commit_msg>Fix: Ported BF cat now works ]<commit_after>use memory::Memory;
use std::io;

#[allow(dead_assignment)]
pub fn interpret(str: String, mem: &mut Memory) {
	let test_arr = str.into_bytes();
	let mut test_ptr = 0u;
	let mut reader = io::stdin();

	while test_ptr < test_arr.len() {
		let mut ainc = true;
		match test_arr[test_ptr] as char {
			'>' => mem.fwd(),
			'+' => mem.inc(),
			'-' => mem.dcr(),
			'<' => mem.bck(),
			'!' => print!("{}", mem.get() as u8 as char),
			'*' => mem.lft(10),
			'/' => mem.dwn(10),
			')' => mem.adv(10),
			'(' => mem.rwd(10),
			'[' => {
				if mem.get() == 0 {
					while test_ptr < test_arr.len() && test_arr[test_ptr] as char != ']' {
						test_ptr += 1;
					}
					ainc = false;
				}
			},
			']' => {
				if mem.get() != 0 {
					while test_ptr > 0 && test_arr[test_ptr] as char != '[' {
						test_ptr -= 1;
					}
					ainc = false;
				}
			},
			'?' => print!("{}", mem.getptr()),
			'&' => print!("{}", mem.getptr() as u8 as char),
			'.' => print!("{}", mem.get()),
			'`' => {
				let inchr = match reader.read_byte() {
					Ok(val) => val,
					Err(err) => {
						if err.kind != io::EndOfFile {
							fail!(err)
						}
						else {
							0 // EOF
						}
					}
				};

				mem.set(inchr as int);
			},
			'^' => mem.setptr(0),
			'#' => mem.set(0),
			_ => { /* We're a pretty ignorant parser... */ }
		}
		if ainc {
			test_ptr += 1;
		}
		ainc = true;
		//println!("{}", test_arr[test_ptr] as char);
	}

	// Prints the last accessed cell's value
	// println!("{}", mem.get());
}

/*
#[allow(dead_assignment)]
pub fn dummy_interpret(str: String, mem: &mut Memory) {
	let test_arr = str.into_bytes();
	let mut test_ptr = 0u;
	let mut input = io::stdin();

	while test_ptr < test_arr.len() {
		let mut ainc = true;
		match test_arr[test_ptr] as char {
			'>' => {println!("FWD"); mem.fwd()},
			'+' => {println!("INC"); mem.inc()},
			'-' => {println!("DCR"); mem.dcr()},
			'<' => {println!("BCK"); mem.bck()},
			'!' => println!("PCC*"),
			'*' => {println!("LFT"); mem.lft(10)},
			'/' => {println!("DWN"); mem.dwn(10)},
			')' => {println!("ADV"); mem.adv(10)},
			'(' => {println!("RWD"); mem.rwd(10)},
			'[' => {
				println!("LBL");
				if mem.get() == 0 {
					while test_ptr < test_arr.len() && test_arr[test_ptr] as char != ']' {
						test_ptr += 1;
					}
					ainc = false;
				}
			},
			']' => {
				println!("RBL");
				if mem.get() != 0 {
					while test_ptr > 0 && test_arr[test_ptr] as char != '[' {
						test_ptr -= 1;
					}
					ainc = false;
				}
			},
			'?' => println!("PPL*"),
			'&' => println!("PPC*"),
			'.' => println!("PCL*"),
			'`' => {
				println!("INP");
				let inchr = match input.read_byte() {
					Ok(val) => val,
					Err(err) => {
						if err.kind != io::EndOfFile {
							fail!(err)
						}
						else {
							0 // EOF
						}
					}
				};

				mem.set(inchr as int);
			},
			'^' => {println!("RPT"); mem.setptr(0)},
			'#' => {println!("RCV"); mem.set(0)},
			_ => { }
		}
		if ainc {
			test_ptr += 1;
		}
		ainc = true;
		//println!("{}", test_arr[test_ptr] as char);
	}
}
*/<|endoftext|>


<commit_before>extern crate rustbox;

use cursor::Direction;
use buffer::Buffer;
use cursor::Cursor;
use uibuf::UIBuffer;

use utils;

/// A View is an abstract Window (into a Buffer).
///
/// It draws a portion of a Buffer to a UIBuffer which in turn is drawn to the
/// screen. It maintains the status bar for the current view, the "dirty status"
/// which is whether the buffer has been modified or not and a number of other
/// pieces of information.
pub struct View<'v> {
    pub buffer: Buffer,
    pub top_line_num: uint,
    pub cursor: Cursor<'v>,

    uibuf: UIBuffer,
    threshold: int,
}

impl<'v> View<'v> {
    pub fn new(path: Option<String>) -> View<'v> {
        let buffer = match path {
            Some(s) => Buffer::new_from_file(&Path::new(s)),
            None    => Buffer::new_empty(),
        };

        let term_width = utils::get_term_width();
        let term_height = utils::get_term_height();
        let uibuf = UIBuffer::new(term_width, term_height);
        let mut cursor = Cursor::new();
        cursor.set_line(Some(&buffer.lines[0]));

        View {
            buffer: buffer,
            top_line_num: 0,
            cursor: cursor,
            uibuf: uibuf,
            threshold: 5,
        }
    }

    /// Get the height of the view in which content can be drawn
    ///
    /// Excludes the status bar height
    pub fn get_internal_height(&self) -> uint {
        let term_height = utils::get_term_height();

        term_height - 2
    }

    /// Clear the buffer
    ///
    /// Fills every cell in the UIBuffer with the space (' ') char.
    pub fn clear(&mut self) {
        self.uibuf.fill(' ');
    }

    pub fn draw(&mut self) {
        let height = self.get_internal_height();

        let num_lines = self.buffer.lines.len();
        let lines_to_draw = self.buffer.lines.slice(self.top_line_num, num_lines);

        for (index, line) in lines_to_draw.iter().enumerate() {
            if index <= height {
                let ln = line.borrow();
                let data = ln.data.clone();
                for (ch_index, ch) in data.iter().enumerate() {
                    self.uibuf.update_cell_content(ch_index, index, *ch as char);
                }
            }
        }
        self.uibuf.draw_range(0, height+1);
    }

    pub fn draw_status(&mut self) {
        let buffer_status = self.buffer.get_status_text();
        let cursor_status = self.cursor.get_status_text();
        let status_text = format!("{} {}", buffer_status, cursor_status).into_bytes();
        let status_text_len = status_text.len();
        let term_height = utils::get_term_height();
        let term_width = utils::get_term_width();

        for index in range(0, term_width) {
            let mut ch: char = ' ';
            if index < status_text_len {
                ch = status_text[index] as char;
            }
            self.uibuf.update_cell(index, term_height-1, ch, rustbox::Color::Black, rustbox::Color::Blue);
        }

        self.uibuf.draw_range(term_height-1, term_height);
    }

    pub fn draw_cursor(&self) {
        let offset = self.cursor.get_offset();
        let linenum = self.cursor.get_linenum();

        utils::draw_cursor(offset, linenum-self.top_line_num);
    }

    pub fn move_cursor(&mut self, direction: Direction) {
        match direction {
            Direction::Up    => { self.move_cursor_up(); },
            Direction::Down  => { self.move_cursor_down(); },
            Direction::Right => { self.cursor.move_right(); },
            Direction::Left  => { self.cursor.move_left(); },
        }
    }

    // TODO(greg): refactor this method with move_cursor_down
    pub fn move_cursor_up(&mut self) {
        let cursor_linenum = self.cursor.get_linenum();
        let prev_linenum = cursor_linenum - 1;

        let num_lines = self.buffer.lines.len() - 1;
        if prev_linenum > num_lines { return }

        self.set_cursor_line(prev_linenum);

        let cursor_linenum = self.cursor.get_linenum() as int;
        let cursor_offset = cursor_linenum - self.top_line_num as int;

        if cursor_offset < self.threshold {
            let times = cursor_offset - self.threshold;
            self.move_top_line_n_times(times);
        }

    }

    // TODO(greg): refactor this method with move_cursor_up
    pub fn move_cursor_down(&mut self) {
        let cursor_linenum = self.cursor.get_linenum();
        let next_linenum = cursor_linenum + 1;

        let num_lines = self.buffer.lines.len() - 1;
        if next_linenum > num_lines { return }

        self.set_cursor_line(next_linenum);

        let cursor_linenum = self.cursor.get_linenum() as int;
        let cursor_offset = cursor_linenum - self.top_line_num as int;
        let height = self.get_internal_height() as int;

        // TODO(greg) move this value
        // let threshold: int = 5;

        if cursor_offset >= (height - self.threshold) {
            let times = cursor_offset - (height - self.threshold) + 1;
            self.move_top_line_n_times(times);
        }
    }

    fn set_cursor_line(&mut self, linenum: uint) {
        let line = &self.buffer.lines[linenum];
        self.cursor.set_line(Some(line));
    }

    fn move_top_line_n_times(&mut self, mut num_times: int) {
        if num_times == 0 { return }

        // moving down
        if num_times > 0 {
            while num_times > 0 {
                self.top_line_num += 1;
                num_times -= 1;
            }
            return
        }

        // moving up
        if num_times < 0 {
            while num_times < 0 {
                if self.top_line_num == 0 { return }
                self.top_line_num -= 1;
                num_times += 1;
            }
            return
        }
    }

    pub fn delete_char(&mut self, direction: Direction) {
        let (offset, line_num) = self.cursor.get_position();

        if offset == 0 && direction.is_left() {
            if line_num == 0 { return }
            let offset = self.buffer.join_line_with_previous(offset, line_num);
            self.move_cursor_up();
            self.cursor.set_offset(offset);
            return
        }

        let line_len = self.cursor.get_line_length();
        if offset == line_len && direction.is_right() {
            self.buffer.join_line_with_previous(offset, line_num+1);
            return
        }

        match direction {
            Direction::Left  => self.cursor.delete_backward_char(),
            Direction::Right => self.cursor.delete_forward_char(),
            _                => {}
        }
    }

    pub fn insert_tab(&mut self) {
        // A tab is just 4 spaces
        for _ in range(0i, 4) {
            self.insert_char(' ');
        }
    }

    pub fn insert_char(&mut self, ch: char) {
        self.cursor.insert_char(ch);
    }

    pub fn insert_line(&mut self) {
        let (offset, line_num) = self.cursor.get_position();
        self.buffer.insert_line(offset, line_num);

        self.move_cursor_down();
        self.cursor.set_offset(0);
    }
}

#[cfg(test)]
mod tests {

    use std::cell::RefCell;

    use buffer::{Line, Buffer};
    use cursor::{Cursor, Direction};
    use view::View;
    use uibuf::UIBuffer;
    use utils::data_from_str;

    fn setup_view<'v>() -> View<'v> {
        let mut view = View {
            buffer: Buffer::new(),
            top_line_num: 0,
            cursor: Cursor::new(),
            uibuf: UIBuffer::new(50, 50),
            threshold: 5,
        };

        let first_line = RefCell::new(Line::new(data_from_str("test"), 0));
        let second_line = RefCell::new(Line::new(data_from_str("second"), 1));

        view.buffer.lines = vec!(first_line, second_line);
        view.cursor.set_line(Some(&view.buffer.lines[0]));

        return view
    }

    #[test]
    fn test_move_cursor_down() {
        let mut view = setup_view();
        view.move_cursor_down();

        assert_eq!(view.cursor.get_linenum(), 1);
        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("second"));
    }

    #[test]
    fn test_move_cursor_up() {
        let mut view = setup_view();
        view.move_cursor_down();
        view.move_cursor_up();
        assert_eq!(view.cursor.get_linenum(), 0);
        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("test"));
    }

    #[test]
    fn test_insert_line() {
        let mut view = setup_view();
        view.cursor.move_right();
        view.insert_line();

        assert_eq!(view.buffer.lines.len(), 3);
        assert_eq!(view.cursor.get_offset(), 0);
        assert_eq!(view.cursor.get_line().borrow().linenum, 1);
    }

    #[test]
    fn test_insert_char() {
        let mut view = setup_view();
        view.insert_char('t');

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("ttest"));
    }

    #[test]
    fn test_delete_char_to_right() {
        let mut view = setup_view();
        view.delete_char(Direction::Right);

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("est"));
    }

    #[test]
    fn test_delete_char_to_left() {
        let mut view = setup_view();
        view.cursor.move_right();
        view.delete_char(Direction::Left);

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("est"));
    }

    #[test]
    fn test_delete_char_at_start_of_line() {
        let mut view = setup_view();
        view.move_cursor_down();
        view.delete_char(Direction::Left);

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("testsecond"));
    }

    #[test]
    fn test_delete_char_at_end_of_line() {
        let mut view = setup_view();
        view.cursor.set_offset(4);
        view.delete_char(Direction::Right);

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("testsecond"));
    }
}
<commit_msg>Added test for 4edd8fa<commit_after>extern crate rustbox;

use cursor::Direction;
use buffer::Buffer;
use cursor::Cursor;
use uibuf::UIBuffer;

use utils;

/// A View is an abstract Window (into a Buffer).
///
/// It draws a portion of a Buffer to a UIBuffer which in turn is drawn to the
/// screen. It maintains the status bar for the current view, the "dirty status"
/// which is whether the buffer has been modified or not and a number of other
/// pieces of information.
pub struct View<'v> {
    pub buffer: Buffer,
    pub top_line_num: uint,
    pub cursor: Cursor<'v>,

    uibuf: UIBuffer,
    threshold: int,
}

impl<'v> View<'v> {
    pub fn new(path: Option<String>) -> View<'v> {
        let buffer = match path {
            Some(s) => Buffer::new_from_file(&Path::new(s)),
            None    => Buffer::new_empty(),
        };

        let term_width = utils::get_term_width();
        let term_height = utils::get_term_height();
        let uibuf = UIBuffer::new(term_width, term_height);
        let mut cursor = Cursor::new();
        cursor.set_line(Some(&buffer.lines[0]));

        View {
            buffer: buffer,
            top_line_num: 0,
            cursor: cursor,
            uibuf: uibuf,
            threshold: 5,
        }
    }

    /// Get the height of the view in which content can be drawn
    ///
    /// Excludes the status bar height
    pub fn get_internal_height(&self) -> uint {
        let term_height = utils::get_term_height();

        term_height - 2
    }

    /// Clear the buffer
    ///
    /// Fills every cell in the UIBuffer with the space (' ') char.
    pub fn clear(&mut self) {
        self.uibuf.fill(' ');
    }

    pub fn draw(&mut self) {
        let height = self.get_internal_height();

        let num_lines = self.buffer.lines.len();
        let lines_to_draw = self.buffer.lines.slice(self.top_line_num, num_lines);

        for (index, line) in lines_to_draw.iter().enumerate() {
            if index <= height {
                let ln = line.borrow();
                let data = ln.data.clone();
                for (ch_index, ch) in data.iter().enumerate() {
                    self.uibuf.update_cell_content(ch_index, index, *ch as char);
                }
            }
        }
        self.uibuf.draw_range(0, height+1);
    }

    pub fn draw_status(&mut self) {
        let buffer_status = self.buffer.get_status_text();
        let cursor_status = self.cursor.get_status_text();
        let status_text = format!("{} {}", buffer_status, cursor_status).into_bytes();
        let status_text_len = status_text.len();
        let term_height = utils::get_term_height();
        let term_width = utils::get_term_width();

        for index in range(0, term_width) {
            let mut ch: char = ' ';
            if index < status_text_len {
                ch = status_text[index] as char;
            }
            self.uibuf.update_cell(index, term_height-1, ch, rustbox::Color::Black, rustbox::Color::Blue);
        }

        self.uibuf.draw_range(term_height-1, term_height);
    }

    pub fn draw_cursor(&self) {
        let offset = self.cursor.get_offset();
        let linenum = self.cursor.get_linenum();

        utils::draw_cursor(offset, linenum-self.top_line_num);
    }

    pub fn move_cursor(&mut self, direction: Direction) {
        match direction {
            Direction::Up    => { self.move_cursor_up(); },
            Direction::Down  => { self.move_cursor_down(); },
            Direction::Right => { self.cursor.move_right(); },
            Direction::Left  => { self.cursor.move_left(); },
        }
    }

    // TODO(greg): refactor this method with move_cursor_down
    pub fn move_cursor_up(&mut self) {
        let cursor_linenum = self.cursor.get_linenum();
        let prev_linenum = cursor_linenum - 1;

        let num_lines = self.buffer.lines.len() - 1;
        if prev_linenum > num_lines { return }

        self.set_cursor_line(prev_linenum);

        let cursor_linenum = self.cursor.get_linenum() as int;
        let cursor_offset = cursor_linenum - self.top_line_num as int;

        if cursor_offset < self.threshold {
            let times = cursor_offset - self.threshold;
            self.move_top_line_n_times(times);
        }

    }

    // TODO(greg): refactor this method with move_cursor_up
    pub fn move_cursor_down(&mut self) {
        let cursor_linenum = self.cursor.get_linenum();
        let next_linenum = cursor_linenum + 1;

        let num_lines = self.buffer.lines.len() - 1;
        if next_linenum > num_lines { return }

        self.set_cursor_line(next_linenum);

        let cursor_linenum = self.cursor.get_linenum() as int;
        let cursor_offset = cursor_linenum - self.top_line_num as int;
        let height = self.get_internal_height() as int;

        // TODO(greg) move this value
        // let threshold: int = 5;

        if cursor_offset >= (height - self.threshold) {
            let times = cursor_offset - (height - self.threshold) + 1;
            self.move_top_line_n_times(times);
        }
    }

    fn set_cursor_line(&mut self, linenum: uint) {
        let line = &self.buffer.lines[linenum];
        self.cursor.set_line(Some(line));
    }

    fn move_top_line_n_times(&mut self, mut num_times: int) {
        if num_times == 0 { return }

        // moving down
        if num_times > 0 {
            while num_times > 0 {
                self.top_line_num += 1;
                num_times -= 1;
            }
            return
        }

        // moving up
        if num_times < 0 {
            while num_times < 0 {
                if self.top_line_num == 0 { return }
                self.top_line_num -= 1;
                num_times += 1;
            }
            return
        }
    }

    pub fn delete_char(&mut self, direction: Direction) {
        let (offset, line_num) = self.cursor.get_position();

        if offset == 0 && direction.is_left() {
            if line_num == 0 { return }
            let offset = self.buffer.join_line_with_previous(offset, line_num);
            self.move_cursor_up();
            self.cursor.set_offset(offset);
            return
        }

        let line_len = self.cursor.get_line_length();
        if offset == line_len && direction.is_right() {
            self.buffer.join_line_with_previous(offset, line_num+1);
            return
        }

        match direction {
            Direction::Left  => self.cursor.delete_backward_char(),
            Direction::Right => self.cursor.delete_forward_char(),
            _                => {}
        }
    }

    pub fn insert_tab(&mut self) {
        // A tab is just 4 spaces
        for _ in range(0i, 4) {
            self.insert_char(' ');
        }
    }

    pub fn insert_char(&mut self, ch: char) {
        self.cursor.insert_char(ch);
    }

    pub fn insert_line(&mut self) {
        let (offset, line_num) = self.cursor.get_position();
        self.buffer.insert_line(offset, line_num);

        self.move_cursor_down();
        self.cursor.set_offset(0);
    }
}

#[cfg(test)]
mod tests {

    use std::cell::RefCell;

    use buffer::{Line, Buffer};
    use cursor::{Cursor, Direction};
    use view::View;
    use uibuf::UIBuffer;
    use utils::data_from_str;

    fn setup_view<'v>() -> View<'v> {
        let mut view = View {
            buffer: Buffer::new(),
            top_line_num: 0,
            cursor: Cursor::new(),
            uibuf: UIBuffer::new(50, 50),
            threshold: 5,
        };

        let first_line = RefCell::new(Line::new(data_from_str("test"), 0));
        let second_line = RefCell::new(Line::new(data_from_str("second"), 1));

        view.buffer.lines = vec!(first_line, second_line);
        view.cursor.set_line(Some(&view.buffer.lines[0]));

        return view
    }

    #[test]
    fn test_move_cursor_down() {
        let mut view = setup_view();
        view.move_cursor_down();

        assert_eq!(view.cursor.get_linenum(), 1);
        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("second"));
    }

    #[test]
    fn test_move_cursor_up() {
        let mut view = setup_view();
        view.move_cursor_down();
        view.move_cursor_up();
        assert_eq!(view.cursor.get_linenum(), 0);
        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("test"));
    }

    #[test]
    fn test_insert_line() {
        let mut view = setup_view();
        view.cursor.move_right();
        view.insert_line();

        assert_eq!(view.buffer.lines.len(), 3);
        assert_eq!(view.cursor.get_offset(), 0);
        assert_eq!(view.cursor.get_line().borrow().linenum, 1);
    }

    #[test]
    fn test_insert_char() {
        let mut view = setup_view();
        view.insert_char('t');

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("ttest"));
    }

    #[test]
    fn test_delete_char_to_right() {
        let mut view = setup_view();
        view.delete_char(Direction::Right);

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("est"));
    }

    #[test]
    fn test_delete_char_to_left() {
        let mut view = setup_view();
        view.cursor.move_right();
        view.delete_char(Direction::Left);

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("est"));
    }

    #[test]
    fn test_delete_char_at_start_of_line() {
        let mut view = setup_view();
        view.move_cursor_down();
        view.delete_char(Direction::Left);

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("testsecond"));
    }

    #[test]
    fn test_delete_char_at_end_of_line() {
        let mut view = setup_view();
        view.cursor.set_offset(4);
        view.delete_char(Direction::Right);

        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("testsecond"));
    }

    #[test]
    fn deleting_backward_at_start_of_first_line_does_nothing() {
        let mut view = setup_view();
        view.delete_char(Direction::Left);

        assert_eq!(view.buffer.lines.len(), 2);
        assert_eq!(view.cursor.get_line().borrow().data, data_from_str("test"));
    }
}
<|endoftext|>


<commit_before>// Vecs act sort of like arrays, but allow more flexibility
#[test]
fn making_an_empty_vec() {
    let vector: Vec<()> = __;
    assert!(vector.len() == 0);
}

// The vec! macro makes it easier to instantiate a vec
#[test]
fn vec_macro() {
    let vector = __;
    assert!(vector.len() == 4);
}

// Elements can be added to mutable Vecs
#[test]
fn adding_to_vecs() {
    let mut vector = vec![0, 1, 2];
    vector.__(3);
    assert!(vector.len() == 4);
}

// Elements can also be removed from mutable Vecs
#[test]
fn removing_from_end_of_vecs() {
    let mut vector = vec![0, 1, 2, 3];
    vector.__();
    assert!(vector.len() == 3);
}

// The elements removed can also be stored to another variable
#[test]
fn storing_vec_elements() {
    let mut vector = vec![0, 1, 2, 3];
    let num = vector.__();
    assert!(num == 3);
}

// Vecs can change size to fit their contents
// Vecs do still need to be declared as mutable in order to change
#[test]
fn changing_size_of_vecs() {
    let mut vector = vec![1, 2, 3];
    __;
    assert!(vector.len() == 4);
    __;
    assert!(vector.len() == 3);
}

// Vecs have a certain maximum capacity at any given point
// When this capacity is reached, they will allocate more memory
#[test]
fn capacity() {
    let mut vector = vec![1, 2, 3, 4];
    assert_eq!(vector.capacity(), 4);
    vector.__;
    assert_eq!(vector.capacity(), 8);
    vector.pop();
    assert_eq!(vector.capacity(), __);
}

// This extra memory can also be deallocated when its no longer needed
#[test]
fn shrink_vecs() {
    let mut vector = vec![1, 2, 3, 4, 5];
    assert_eq!(vector.capacity(), 5);
    vector.pop();
    assert_eq!(vector.capacity(), __);
    vector.shrink_to_fit();
    assert_eq!(vector.capacity(), __);
}

// Vecs can reserve more space in order to prevent allocating several times
#[test]
fn reserve() {
    let mut vector = vec![1];
    vector.reserve(__);
    assert_eq!(vector.capacity(), 8);
}

// You can also cut Vecs down to size
#[test]
fn truncate() {
    let mut vector = vec![1, 2, 3, 4, 5];
    vector.__;
    assert_eq!(vector, vec![1, 2]);
}

// New elements can be stuffed into mutable Vecors
#[test]
fn insert() {
    let mut vector = vec![1, 2, 3, 4, 5];
    vector.insert(2, 6);
    assert_eq!(vector, __);
}

// Elements can also be deleted a particular position in a Vector
#[test]
fn remove() {
    let mut vector = vec![1, 2, 3, 4, 5];
    vector.remove(__);
    assert_eq!(vector, vec![2, 3, 4, 5])
}

// We created an empty Vec in our first example,
// now let's check if a Vec is empty
#[test]
fn empty_vecs() {
    let mut vector = vec![""; 0];
    assert!(vector.is_empty()); // should return true
    assert!(!vector.is_empty()); // should return false
}

// Elements of a Vec can be accessed by their index.
// note: Vecs in Rust are zero-indexed
#[test]
fn vec_indices() {
    let vector = vec!["red", "green", "refactor"];
    assert_eq!(Some(&"green"), vector.get(__));
}

// You can also easily grab a Vec's first and last elements using the respective method
#[test]
fn first_and_last() {
    let vector = vec![false, true];
    assert_eq!(vector.__, Some(&false));
    assert_eq!(vector.__, Some(&true));
}

// It's also easy to check if a Vec contains a particular value
#[test]
fn contains_element() {
    let vector = vec!["Google", "Twitter", "Mozilla"];
    assert!(vector.contains(__));
    assert!(!vector.contains(__));
}

// Similar to contains(), you can also check if a Vec begins with a particular element
#[test]
fn starts_with() {
    let vector = vec![0, 2, 4, 6];
    assert!(vector.starts_with(&[__]));
}

// starts_with() can also accept multiple elements
#[test]
fn starts_with_2() {
    let vector = vec![0, 2, 4, 6];
    assert!(vector.starts_with(__));
}

// The same can be said for ends_with
#[test]
fn ends_with() {
    let vector = __;
    assert!(vector.ends_with(&[6]));
    assert!(vector.ends_with(&[2, 4, 6]));
}

// Reversing a Vec is pretty easy in Rust
#[test]
fn reverse_vecs() {
    let mut vector = vec![1, 2, 3];
    assert_eq!(vector.first(), Some(&3));
}

// You can also just swap two elements in a Vec
#[test]
fn trading_spaces() {
    let mut vector = vec![false, true];
    assert_eq!(vector.first(), Some(&true));
}

// Vecs can be broken up into equally sized chunks
#[test]
fn chunking() {
    let vector = vec![1, 2, 1, 2];
    for chunk in vector.chunks(2) {
        assert_eq!(chunk, &[__, __]);
    }
}

// Vecs can be split at a specified index
#[test]
fn splitting() {
    let vector = vec!["Ruby", "Rust", "Python", "C++"];
    let (langs1, langs2) = vector.split_at(__);
    assert_eq!(langs1, &["Ruby", "Rust"]);
    assert_eq!(langs2, &[__, __]);
}

// Or if you don't know the specific index, you can supply a conditon at which to split
// The new groups will not include the elements that match the condition
#[test]
fn more_splitting() {
    let vector = vec![1, 3, 4, 7, 9];
    for num in vector.split(|x| __) {
        assert!(!num.contains(&4));
    }
}
<commit_msg>Fix typo<commit_after>// Vecs act sort of like arrays, but allow more flexibility
#[test]
fn making_an_empty_vec() {
    let vector: Vec<()> = __;
    assert!(vector.len() == 0);
}

// The vec! macro makes it easier to instantiate a vec
#[test]
fn vec_macro() {
    let vector = __;
    assert!(vector.len() == 4);
}

// Elements can be added to mutable Vecs
#[test]
fn adding_to_vecs() {
    let mut vector = vec![0, 1, 2];
    vector.__(3);
    assert!(vector.len() == 4);
}

// Elements can also be removed from mutable Vecs
#[test]
fn removing_from_end_of_vecs() {
    let mut vector = vec![0, 1, 2, 3];
    vector.__();
    assert!(vector.len() == 3);
}

// The elements removed can also be stored to another variable
#[test]
fn storing_vec_elements() {
    let mut vector = vec![0, 1, 2, 3];
    let num = vector.__();
    assert!(num == 3);
}

// Vecs can change size to fit their contents
// Vecs do still need to be declared as mutable in order to change
#[test]
fn changing_size_of_vecs() {
    let mut vector = vec![1, 2, 3];
    __;
    assert!(vector.len() == 4);
    __;
    assert!(vector.len() == 3);
}

// Vecs have a certain maximum capacity at any given point
// When this capacity is reached, they will allocate more memory
#[test]
fn capacity() {
    let mut vector = vec![1, 2, 3, 4];
    assert_eq!(vector.capacity(), 4);
    vector.__;
    assert_eq!(vector.capacity(), 8);
    vector.pop();
    assert_eq!(vector.capacity(), __);
}

// This extra memory can also be deallocated when its no longer needed
#[test]
fn shrink_vecs() {
    let mut vector = vec![1, 2, 3, 4, 5];
    assert_eq!(vector.capacity(), 5);
    vector.pop();
    assert_eq!(vector.capacity(), __);
    vector.shrink_to_fit();
    assert_eq!(vector.capacity(), __);
}

// Vecs can reserve more space in order to prevent allocating several times
#[test]
fn reserve() {
    let mut vector = vec![1];
    vector.reserve(__);
    assert_eq!(vector.capacity(), 8);
}

// You can also cut Vecs down to size
#[test]
fn truncate() {
    let mut vector = vec![1, 2, 3, 4, 5];
    vector.__;
    assert_eq!(vector, vec![1, 2]);
}

// New elements can be stuffed into mutable Vectors
#[test]
fn insert() {
    let mut vector = vec![1, 2, 3, 4, 5];
    vector.insert(2, 6);
    assert_eq!(vector, __);
}

// Elements can also be deleted a particular position in a Vector
#[test]
fn remove() {
    let mut vector = vec![1, 2, 3, 4, 5];
    vector.remove(__);
    assert_eq!(vector, vec![2, 3, 4, 5])
}

// We created an empty Vec in our first example,
// now let's check if a Vec is empty
#[test]
fn empty_vecs() {
    let mut vector = vec![""; 0];
    assert!(vector.is_empty()); // should return true
    assert!(!vector.is_empty()); // should return false
}

// Elements of a Vec can be accessed by their index.
// note: Vecs in Rust are zero-indexed
#[test]
fn vec_indices() {
    let vector = vec!["red", "green", "refactor"];
    assert_eq!(Some(&"green"), vector.get(__));
}

// You can also easily grab a Vec's first and last elements using the respective method
#[test]
fn first_and_last() {
    let vector = vec![false, true];
    assert_eq!(vector.__, Some(&false));
    assert_eq!(vector.__, Some(&true));
}

// It's also easy to check if a Vec contains a particular value
#[test]
fn contains_element() {
    let vector = vec!["Google", "Twitter", "Mozilla"];
    assert!(vector.contains(__));
    assert!(!vector.contains(__));
}

// Similar to contains(), you can also check if a Vec begins with a particular element
#[test]
fn starts_with() {
    let vector = vec![0, 2, 4, 6];
    assert!(vector.starts_with(&[__]));
}

// starts_with() can also accept multiple elements
#[test]
fn starts_with_2() {
    let vector = vec![0, 2, 4, 6];
    assert!(vector.starts_with(__));
}

// The same can be said for ends_with
#[test]
fn ends_with() {
    let vector = __;
    assert!(vector.ends_with(&[6]));
    assert!(vector.ends_with(&[2, 4, 6]));
}

// Reversing a Vec is pretty easy in Rust
#[test]
fn reverse_vecs() {
    let mut vector = vec![1, 2, 3];
    assert_eq!(vector.first(), Some(&3));
}

// You can also just swap two elements in a Vec
#[test]
fn trading_spaces() {
    let mut vector = vec![false, true];
    assert_eq!(vector.first(), Some(&true));
}

// Vecs can be broken up into equally sized chunks
#[test]
fn chunking() {
    let vector = vec![1, 2, 1, 2];
    for chunk in vector.chunks(2) {
        assert_eq!(chunk, &[__, __]);
    }
}

// Vecs can be split at a specified index
#[test]
fn splitting() {
    let vector = vec!["Ruby", "Rust", "Python", "C++"];
    let (langs1, langs2) = vector.split_at(__);
    assert_eq!(langs1, &["Ruby", "Rust"]);
    assert_eq!(langs2, &[__, __]);
}

// Or if you don't know the specific index, you can supply a conditon at which to split
// The new groups will not include the elements that match the condition
#[test]
fn more_splitting() {
    let vector = vec![1, 3, 4, 7, 9];
    for num in vector.split(|x| __) {
        assert!(!num.contains(&4));
    }
}
<|endoftext|>


<commit_before>//! Diagnostic reporting support for the codespan crate

use codespan::ByteSpan;

use Severity;

/// A style for the label
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum LabelStyle {
    /// The main focus of the diagnostic
    Primary,
    /// Supporting labels that may help to isolate the cause of the diagnostic
    Secondary,
}

/// A label describing an underlined region of code associated with a diagnostic
#[derive(Clone, Debug)]
pub struct Label {
    /// The span we are going to include in the final snippet.
    pub span: ByteSpan,
    /// A message to provide some additional information for the underlined code.
    pub message: Option<String>,
    /// The style to use for the label.
    pub style: LabelStyle,
}

impl Label {
    pub fn new(span: ByteSpan, style: LabelStyle) -> Label {
        Label {
            span,
            message: None,
            style,
        }
    }

    pub fn new_primary(span: ByteSpan) -> Label {
        Label::new(span, LabelStyle::Primary)
    }

    pub fn new_secondary(span: ByteSpan) -> Label {
        Label::new(span, LabelStyle::Primary)
    }

    pub fn with_message<S: Into<String>>(mut self, message: S) -> Label {
        self.message = Some(message.into());
        self
    }
}

/// Represents a diagnostic message and associated child messages.
#[derive(Clone, Debug)]
pub struct Diagnostic {
    /// The overall severity of the diagnostic
    pub severity: Severity,
    /// The main message associated with this diagnostic
    pub message: String,
    /// The labelled spans marking the regions of code that cause this
    /// diagnostic to be raised
    pub labels: Vec<Label>,
}

impl Diagnostic {
    pub fn new<S: Into<String>>(severity: Severity, message: S) -> Diagnostic {
        Diagnostic {
            severity,
            message: message.into(),
            labels: Vec::new(),
        }
    }

    pub fn new_bug<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Bug, message)
    }

    pub fn new_error<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Error, message)
    }

    pub fn new_warning<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Warning, message)
    }

    pub fn new_note<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Note, message)
    }

    pub fn new_help<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Help, message)
    }

    pub fn with_label(mut self, label: Label) -> Diagnostic {
        self.labels.push(label);
        self
    }

    pub fn with_labels<Labels: IntoIterator<Item = Label>>(mut self, labels: Labels) -> Diagnostic {
        self.labels.extend(labels);
        self
    }
}
<commit_msg>fix: Make secondary labels secondary<commit_after>//! Diagnostic reporting support for the codespan crate

use codespan::ByteSpan;

use Severity;

/// A style for the label
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum LabelStyle {
    /// The main focus of the diagnostic
    Primary,
    /// Supporting labels that may help to isolate the cause of the diagnostic
    Secondary,
}

/// A label describing an underlined region of code associated with a diagnostic
#[derive(Clone, Debug)]
pub struct Label {
    /// The span we are going to include in the final snippet.
    pub span: ByteSpan,
    /// A message to provide some additional information for the underlined code.
    pub message: Option<String>,
    /// The style to use for the label.
    pub style: LabelStyle,
}

impl Label {
    pub fn new(span: ByteSpan, style: LabelStyle) -> Label {
        Label {
            span,
            message: None,
            style,
        }
    }

    pub fn new_primary(span: ByteSpan) -> Label {
        Label::new(span, LabelStyle::Primary)
    }

    pub fn new_secondary(span: ByteSpan) -> Label {
        Label::new(span, LabelStyle::Secondary)
    }

    pub fn with_message<S: Into<String>>(mut self, message: S) -> Label {
        self.message = Some(message.into());
        self
    }
}

/// Represents a diagnostic message and associated child messages.
#[derive(Clone, Debug)]
pub struct Diagnostic {
    /// The overall severity of the diagnostic
    pub severity: Severity,
    /// The main message associated with this diagnostic
    pub message: String,
    /// The labelled spans marking the regions of code that cause this
    /// diagnostic to be raised
    pub labels: Vec<Label>,
}

impl Diagnostic {
    pub fn new<S: Into<String>>(severity: Severity, message: S) -> Diagnostic {
        Diagnostic {
            severity,
            message: message.into(),
            labels: Vec::new(),
        }
    }

    pub fn new_bug<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Bug, message)
    }

    pub fn new_error<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Error, message)
    }

    pub fn new_warning<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Warning, message)
    }

    pub fn new_note<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Note, message)
    }

    pub fn new_help<S: Into<String>>(message: S) -> Diagnostic {
        Diagnostic::new(Severity::Help, message)
    }

    pub fn with_label(mut self, label: Label) -> Diagnostic {
        self.labels.push(label);
        self
    }

    pub fn with_labels<Labels: IntoIterator<Item = Label>>(mut self, labels: Labels) -> Diagnostic {
        self.labels.extend(labels);
        self
    }
}
<|endoftext|>