<commit_before>use std::io::File;
use std::io::BufferedReader;
use std::{str,vec,fmt,path};

pub mod scopes;
pub mod ast;
pub mod typeinf;
pub mod nameres;
pub mod codeiter;
pub mod codecleaner;
pub mod testutils;
pub mod util;
pub mod matchers;

#[cfg(test)] pub mod test;

#[deriving(Show,Clone,PartialEq)]
pub enum MatchType {
    Struct,
    Module,
    Function,
    Crate,
    Let,
    StructField,
    Impl,
    Enum,
    EnumVariant,
    Type,
    FnArg,
    Trait,
    Const,
    Static
}

#[deriving(Show)]
pub enum SearchType {
    ExactMatch,
    StartsWith
}

#[deriving(Show)]
pub enum Namespace {
    TypeNamespace,
    ValueNamespace,
    BothNamespaces
}

#[deriving(Show)]
pub enum CompletionType {
    CompleteField,
    CompletePath
}

#[deriving(Clone)]
pub struct Match {
    pub matchstr: String,
    pub filepath: path::Path,
    pub point: uint,
    pub local: bool,
    pub mtype: MatchType,
    pub contextstr: String,
    pub generic_args: Vec<String>,
    pub generic_types: Vec<PathSearch>  // generic types are evaluated lazily
}

impl Match {
    fn with_generic_types(&self, generic_types: Vec<PathSearch>) -> Match {
        Match {
            matchstr: self.matchstr.clone(),
            filepath: self.filepath.clone(),
            point: self.point,
            local: self.local,
            mtype: self.mtype,
            contextstr: self.contextstr.clone(),
            generic_args: self.generic_args.clone(),
            generic_types: generic_types
        }
    }
}

impl fmt::Show for Match {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Match [{}, {}, {}, {}, {}, {}, {} |{}|]",
               self.matchstr,
               self.filepath.as_str(),
               self.point,
               self.local,
               self.mtype,
               self.generic_args,
               self.generic_types,
               self.contextstr)
    }
}

#[deriving(Clone)]
pub struct Scope {
    pub filepath: path::Path,
    pub point: uint
}

impl Scope {
    pub fn from_match(m: &Match) -> Scope {
        Scope{filepath: m.filepath.clone(), point: m.point}
    }
}

impl fmt::Show for Scope {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Scope [{}, {}]",
               self.filepath.as_str(),
               self.point)
    }
}

// Represents a type. Equivilent to rustc's ast::Ty but can be passed across threads
#[deriving(Show,Clone)]
pub enum Ty {
    TyMatch(Match),
    TyPathSearch(Path, Scope),   // A path + the scope to be able to resolve it
    TyTuple(Vec<Ty>),
    TyUnsupported
}

// The racer implementation of an ast::Path. Difference is that it is Send-able
#[deriving(Show,Clone)]
pub struct Path {
    global: bool,
    segments: Vec<PathSegment>
}

impl Path {
    pub fn generic_types(&self) -> ::std::slice::Items<Path> {
        return self.segments[self.segments.len()-1].types.iter();
    }
}

#[deriving(Show,Clone)]
pub struct PathSegment {
    pub name: String,
    pub types: Vec<Path>
}

#[deriving(Clone)]
pub struct PathSearch {
    path: Path,
    filepath: path::Path,
    point: uint
}

impl fmt::Show for PathSearch {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Search [{}, {}, {}]",
               self.path,
               self.filepath.as_str(),
               self.point)
    }
}

pub fn load_file_and_mask_comments(filepath: &path::Path) -> String {
    let filetxt = BufferedReader::new(File::open(filepath)).read_to_end().unwrap();
    let src = str::from_utf8(filetxt.as_slice()).unwrap();
    let msrc = scopes::mask_comments(src);
    return msrc;
}

pub fn complete_from_file(src: &str, filepath: &path::Path, pos: uint) -> vec::MoveItems<Match> {

    let start = scopes::get_start_of_search_expr(src, pos);
    let expr = src.slice(start,pos);

    let (contextstr, searchstr, completetype) = scopes::split_into_context_and_completion(expr);

    debug!("{}: contextstr is |{}|, searchstr is |{}|",
           completetype, contextstr, searchstr);

    let mut out = Vec::new();

    match completetype {
        CompletionType::CompletePath => {
            let mut v : Vec<&str> = expr.split_str("::").collect();
            let mut global = false;
            if v[0] == "" {      // i.e. starts with '::' e.g. ::std::io::blah
                v.remove(0);
                global = true;
            }

            let mut segs = v.iter().map(|x| PathSegment{name:x.to_string(), types: Vec::new()});
            let segs : Vec<PathSegment> = segs.collect();
            let path = Path{ global: global, segments: segs };

            for m in nameres::resolve_path(&path, filepath, pos,
                                         SearchType::StartsWith, Namespace::BothNamespaces) {
                out.push(m);
            }
        },
        CompletionType::CompleteField => {
            let context = ast::get_type_of(contextstr.to_string(), filepath, pos);
            debug!("complete_from_file context is {}", context);
            context.map(|ty| {
                match ty {
                    Ty::TyMatch(m) => {
                        for m in nameres::search_for_field_or_method(m, searchstr, SearchType::StartsWith) {
                            out.push(m)
                        }
                    }
                    _ => {}
                }
            });
        }
    }
    return out.into_iter();
}

pub fn find_definition(src: &str, filepath: &path::Path, pos: uint) -> Option<Match> {
    return find_definition_(src, filepath, pos);
}

pub fn find_definition_(src: &str, filepath: &path::Path, pos: uint) -> Option<Match> {
    let (start, end) = scopes::expand_search_expr(src, pos);
    let expr = src.slice(start,end);

    let (contextstr, searchstr, completetype) = scopes::split_into_context_and_completion(expr);

    debug!("find_definition_ for |{}| |{}| {}",contextstr, searchstr, completetype);

    return match completetype {
        CompletionType::CompletePath => {
            let mut v : Vec<&str> = expr.split_str("::").collect();
            let mut global = false;
            if v[0] == "" {      // i.e. starts with '::' e.g. ::std::io::blah
                v.remove(0);
                global = true;
            }

            let mut segs = v.iter().map(|x|
                                 PathSegment{name:x.to_string(), types: Vec::new()});
            let segs : Vec<PathSegment> = segs.collect();
            let path = Path{ global: global, segments: segs };

            return nameres::resolve_path(&path, filepath, pos,
                                         SearchType::ExactMatch, Namespace::BothNamespaces).nth(0);
        },
        CompletionType::CompleteField => {
            let context = ast::get_type_of(contextstr.to_string(), filepath, pos);
            debug!("context is {}",context);

            return context.and_then(|ty| {
                // for now, just handle matches
                match ty {
                    Ty::TyMatch(m) => {
                        return nameres::search_for_field_or_method(m, searchstr, SearchType::ExactMatch).nth(0);
                    }
                    _ => None
                }
            });
        }
    }
}
<commit_msg>Better 'Show' for racer::Path for debugging<commit_after>use std::io::File;
use std::io::BufferedReader;
use std::{str,vec,fmt,path};

pub mod scopes;
pub mod ast;
pub mod typeinf;
pub mod nameres;
pub mod codeiter;
pub mod codecleaner;
pub mod testutils;
pub mod util;
pub mod matchers;

#[cfg(test)] pub mod test;

#[deriving(Show,Clone,PartialEq)]
pub enum MatchType {
    Struct,
    Module,
    Function,
    Crate,
    Let,
    StructField,
    Impl,
    Enum,
    EnumVariant,
    Type,
    FnArg,
    Trait,
    Const,
    Static
}

#[deriving(Show)]
pub enum SearchType {
    ExactMatch,
    StartsWith
}

#[deriving(Show)]
pub enum Namespace {
    TypeNamespace,
    ValueNamespace,
    BothNamespaces
}

#[deriving(Show)]
pub enum CompletionType {
    CompleteField,
    CompletePath
}

#[deriving(Clone)]
pub struct Match {
    pub matchstr: String,
    pub filepath: path::Path,
    pub point: uint,
    pub local: bool,
    pub mtype: MatchType,
    pub contextstr: String,
    pub generic_args: Vec<String>,
    pub generic_types: Vec<PathSearch>  // generic types are evaluated lazily
}

impl Match {
    fn with_generic_types(&self, generic_types: Vec<PathSearch>) -> Match {
        Match {
            matchstr: self.matchstr.clone(),
            filepath: self.filepath.clone(),
            point: self.point,
            local: self.local,
            mtype: self.mtype,
            contextstr: self.contextstr.clone(),
            generic_args: self.generic_args.clone(),
            generic_types: generic_types
        }
    }
}

impl fmt::Show for Match {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Match [{}, {}, {}, {}, {}, {}, {} |{}|]",
               self.matchstr,
               self.filepath.as_str(),
               self.point,
               self.local,
               self.mtype,
               self.generic_args,
               self.generic_types,
               self.contextstr)
    }
}

#[deriving(Clone)]
pub struct Scope {
    pub filepath: path::Path,
    pub point: uint
}

impl Scope {
    pub fn from_match(m: &Match) -> Scope {
        Scope{filepath: m.filepath.clone(), point: m.point}
    }
}

impl fmt::Show for Scope {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Scope [{}, {}]",
               self.filepath.as_str(),
               self.point)
    }
}

// Represents a type. Equivilent to rustc's ast::Ty but can be passed across threads
#[deriving(Show,Clone)]
pub enum Ty {
    TyMatch(Match),
    TyPathSearch(Path, Scope),   // A path + the scope to be able to resolve it
    TyTuple(Vec<Ty>),
    TyUnsupported
}

// The racer implementation of an ast::Path. Difference is that it is Send-able
#[deriving(Clone)]
pub struct Path {
    global: bool,
    segments: Vec<PathSegment>
}

impl Path {
    pub fn generic_types(&self) -> ::std::slice::Items<Path> {
        return self.segments[self.segments.len()-1].types.iter();
    }
}

impl fmt::Show for Path {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "P["));
        let mut first = true;
        for seg in self.segments.iter() {
            if first {
                try!(write!(f, "{}", seg.name));
                first = false;
            } else {
                try!(write!(f, "::{}", seg.name));
            }

            if !seg.types.is_empty() {
                try!(write!(f, "<"));
                let mut tfirst = true;
                for typath in seg.types.iter() {
                    if tfirst {
                        try!(write!(f, "{}", typath));
                        tfirst = false;
                    } else {
                        try!(write!(f, ",{}", typath))
                    }
                }
                try!(write!(f, ">"));
            }
        }
        return write!(f, "]");
    }
}

#[deriving(Show,Clone)]
pub struct PathSegment {
    pub name: String,
    pub types: Vec<Path>
}

#[deriving(Clone)]
pub struct PathSearch {
    path: Path,
    filepath: path::Path,
    point: uint
}

impl fmt::Show for PathSearch {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Search [{}, {}, {}]",
               self.path,
               self.filepath.as_str(),
               self.point)
    }
}

pub fn load_file_and_mask_comments(filepath: &path::Path) -> String {
    let filetxt = BufferedReader::new(File::open(filepath)).read_to_end().unwrap();
    let src = str::from_utf8(filetxt.as_slice()).unwrap();
    let msrc = scopes::mask_comments(src);
    return msrc;
}

pub fn complete_from_file(src: &str, filepath: &path::Path, pos: uint) -> vec::MoveItems<Match> {

    let start = scopes::get_start_of_search_expr(src, pos);
    let expr = src.slice(start,pos);

    let (contextstr, searchstr, completetype) = scopes::split_into_context_and_completion(expr);

    debug!("{}: contextstr is |{}|, searchstr is |{}|",
           completetype, contextstr, searchstr);

    let mut out = Vec::new();

    match completetype {
        CompletionType::CompletePath => {
            let mut v : Vec<&str> = expr.split_str("::").collect();
            let mut global = false;
            if v[0] == "" {      // i.e. starts with '::' e.g. ::std::io::blah
                v.remove(0);
                global = true;
            }

            let mut segs = v.iter().map(|x| PathSegment{name:x.to_string(), types: Vec::new()});
            let segs : Vec<PathSegment> = segs.collect();
            let path = Path{ global: global, segments: segs };

            for m in nameres::resolve_path(&path, filepath, pos,
                                         SearchType::StartsWith, Namespace::BothNamespaces) {
                out.push(m);
            }
        },
        CompletionType::CompleteField => {
            let context = ast::get_type_of(contextstr.to_string(), filepath, pos);
            debug!("complete_from_file context is {}", context);
            context.map(|ty| {
                match ty {
                    Ty::TyMatch(m) => {
                        for m in nameres::search_for_field_or_method(m, searchstr, SearchType::StartsWith) {
                            out.push(m)
                        }
                    }
                    _ => {}
                }
            });
        }
    }
    return out.into_iter();
}

pub fn find_definition(src: &str, filepath: &path::Path, pos: uint) -> Option<Match> {
    return find_definition_(src, filepath, pos);
}

pub fn find_definition_(src: &str, filepath: &path::Path, pos: uint) -> Option<Match> {
    let (start, end) = scopes::expand_search_expr(src, pos);
    let expr = src.slice(start,end);

    let (contextstr, searchstr, completetype) = scopes::split_into_context_and_completion(expr);

    debug!("find_definition_ for |{}| |{}| {}",contextstr, searchstr, completetype);

    return match completetype {
        CompletionType::CompletePath => {
            let mut v : Vec<&str> = expr.split_str("::").collect();
            let mut global = false;
            if v[0] == "" {      // i.e. starts with '::' e.g. ::std::io::blah
                v.remove(0);
                global = true;
            }

            let mut segs = v.iter().map(|x|
                                 PathSegment{name:x.to_string(), types: Vec::new()});
            let segs : Vec<PathSegment> = segs.collect();
            let path = Path{ global: global, segments: segs };

            return nameres::resolve_path(&path, filepath, pos,
                                         SearchType::ExactMatch, Namespace::BothNamespaces).nth(0);
        },
        CompletionType::CompleteField => {
            let context = ast::get_type_of(contextstr.to_string(), filepath, pos);
            debug!("context is {}",context);

            return context.and_then(|ty| {
                // for now, just handle matches
                match ty {
                    Ty::TyMatch(m) => {
                        return nameres::search_for_field_or_method(m, searchstr, SearchType::ExactMatch).nth(0);
                    }
                    _ => None
                }
            });
        }
    }
}
<|endoftext|>


<commit_before>//! Reexports of crates, that are part of the public api, for convenience

pub use calloop;
#[cfg(feature = "dbus")]
pub use dbus;
#[cfg(feature = "backend_drm")]
pub use drm;
#[cfg(feature = "backend_gbm")]
pub use gbm;
#[cfg(feature = "backend_libinput")]
pub use input;
#[cfg(any(feature = "backend_udev", feature = "backend_drm"))]
pub use nix;
#[cfg(feature = "backend_udev")]
pub use udev;
// #[cfg(feature = "wayland_frontend")]
// pub use wayland_commons;
// #[cfg(feature = "wayland_frontend")]
// pub use wayland_protocols;
#[cfg(feature = "wayland_frontend")]
pub use wayland_server;
#[cfg(feature = "backend_winit")]
pub use winit;
#[cfg(feature = "x11rb_event_source")]
pub use x11rb;
<commit_msg>fix reexports<commit_after>//! Reexports of crates, that are part of the public api, for convenience

pub use calloop;
#[cfg(feature = "dbus")]
pub use dbus;
#[cfg(feature = "backend_drm")]
pub use drm;
#[cfg(feature = "backend_gbm")]
pub use gbm;
#[cfg(feature = "backend_libinput")]
pub use input;
#[cfg(any(feature = "backend_udev", feature = "backend_drm"))]
pub use nix;
#[cfg(feature = "backend_udev")]
pub use udev;
#[cfg(feature = "wayland_frontend")]
pub use wayland_protocols;
#[cfg(feature = "wayland_frontend")]
pub use wayland_server;
#[cfg(feature = "backend_winit")]
pub use winit;
#[cfg(feature = "x11rb_event_source")]
pub use x11rb;
<|endoftext|>


<commit_before>use sync::{Arc, Mutex};
use super::super::error::{MyDriverError, InvalidPoolConstraints};
use super::{MyConn, MyOpts, Stmt, QueryResult};
use super::super::error::{MyResult};

struct MyInnerPool {
    opts: MyOpts,
    pool: Vec<MyConn>,
    min: uint,
    max: uint,
    count: uint
}

impl MyInnerPool {
    fn new(min: uint, max: uint, opts: MyOpts) -> MyResult<MyInnerPool> {
        if min > max || max == 0 {
            return Err(MyDriverError(InvalidPoolConstraints));
        }
        let mut pool = MyInnerPool {
            opts: opts,
            pool: Vec::with_capacity(max),
            max: max,
            min: min,
            count: 0
        };
        for _ in range(0, min) {
            try!(pool.new_conn());
        }
        Ok(pool)
    }
    fn new_conn(&mut self) -> MyResult<()> {
        match MyConn::new(self.opts.clone()) {
            Ok(conn) => {
                self.pool.push(conn);
                Ok(())
            },
            Err(err) => Err(err)
        }
    }
}

/// Pool which is holding mysql connections.
///
/// It will hold at least ```min``` connections and will create as many as
/// ```max``` connections.
///
/// ```
/// use mysql::conn::{MyOpts};
/// use std::default::{Default};
/// use mysql::conn::pool::{MyPool};
/// use mysql::value::{ToValue};
///
/// fn main() {
///     let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
///                                   ..Default::default()});
///     assert!(pool.is_ok());
///     let pool = pool.unwrap();
///     for _ in range(0u, 100) {
///         let pool = pool.clone();
///         spawn(proc() {
///             let conn = pool.get_conn();
///             assert!(conn.is_ok());
///             let mut conn = conn.unwrap();
///             let result = conn.query("SELECT 1");
///             assert!(result.is_ok());
///             let mut result = result.unwrap();
///             assert_eq!(result.next(), Some(Ok(vec!["1".to_value()])));
///         });
///     }
/// }
/// ```
#[deriving(Clone)]
pub struct MyPool {
    pool: Arc<Mutex<MyInnerPool>>
}

impl MyPool {
    /// Creates new pool with ```min = 10``` and ```max = 100```
    pub fn new(opts: MyOpts) -> MyResult<MyPool> {
        MyPool::new_manual(10, 100, opts)
    }

    /// Same as ```new``` but you can set ```min``` and ```max```
    pub fn new_manual(min: uint, max: uint, opts: MyOpts) -> MyResult<MyPool> {
        let pool = try!(MyInnerPool::new(min, max, opts));
        Ok(MyPool{ pool: Arc::new(Mutex::new(pool)) })
    }

    pub fn get_conn(&self) -> MyResult<MyPooledConn> {
        let mut pool = self.pool.lock();

        while pool.pool.is_empty() {
            if pool.count < pool.max {
                match pool.new_conn() {
                    Ok(()) => {
                        pool.count += 1;
                        break;
                    },
                    Err(err) => return Err(err)
                }
            } else {
                pool.cond.wait();
            }
        }

        let mut conn = pool.pool.pop().unwrap();

        if !conn.ping() {
            try!(conn.reset());
        }

        Ok(MyPooledConn {pool: self.clone(), conn: Some(conn)})
    }

    /// You can call ```query``` and ```prepare``` directly on a pool but be
    /// aware of the fact that you can't guarantee that query will be called
    /// at concrete connection.
    ///
    /// For example:
    ///
    /// ```ignore
    /// let opts = MyOpts{user: Some("root".to_string()), ..Default::default()};
    /// let pool = MyPool::new(opts).unwrap();
    ///
    /// pool.query("USE some_database");
    /// let result = pool.query("INSERT INTO users (name) VALUES ('Steven')");
    /// let result = pool.query("SELECT * FROM users"); // Error! `no database selected`
    ///                                                 // because PooledConn on which
    ///                                                 // you have executed USE was
    ///                                                 // borrowed by result shadowed
    ///                                                 // on previous line and will not
    ///                                                 // be available until the end of
    ///                                                 // its scope.
    /// ```
    pub fn query<'a>(&'a self, query: &'a str) -> MyResult<QueryResult<'a>> {
        let conn = try!(self.get_conn());
        conn.pooled_query(query)
    }

    /// See docs on ```Pool#query```
    pub fn prepare<'a>(&'a self, query: &'a str) -> MyResult<Stmt<'a>> {
        let conn = try!(self.get_conn());
        conn.pooled_prepare(query)
    }
}

pub struct MyPooledConn {
    pool: MyPool,
    conn: Option<MyConn>
}

impl Drop for MyPooledConn {
    fn drop(&mut self) {
        let mut pool = self.pool.pool.lock();
        if pool.count > pool.min || self.conn.is_none() {
            pool.count -= 1;
        } else {
            pool.pool.push(self.conn.take_unwrap());
        }
        pool.cond.signal();
    }
}

impl MyPooledConn {
    pub fn query<'a>(&'a mut self, query: &str) -> MyResult<QueryResult<'a>> {
        self.conn.get_mut_ref().query(query)
    }
    pub fn prepare<'a>(&'a mut self, query: &str) -> MyResult<Stmt<'a>> {
        self.conn.get_mut_ref().prepare(query)
    }
    pub fn get_mut_ref<'a>(&'a mut self) -> &'a mut MyConn {
        self.conn.get_mut_ref()
    }
    pub fn get_ref<'a>(&'a self) -> &'a MyConn {
        self.conn.get_ref()
    }
    pub fn unwrap(mut self) -> MyConn {
        self.conn.take_unwrap()
    }
    fn pooled_query(mut self, query: &str) -> MyResult<QueryResult> {
        match self.get_mut_ref()._query(query) {
            Ok((columns, ok_packet)) => Ok(QueryResult::new_pooled(self,
                                                                   columns,
                                                                   ok_packet,
                                                                   false)),
            Err(err) => Err(err)
        }
    }
    fn pooled_prepare(mut self, query: &str) -> MyResult<Stmt> {
        match self.get_mut_ref()._prepare(query) {
            Ok(stmt) => Ok(Stmt::new_pooled(stmt, self)),
            Err(err) => Err(err)
        }
    }
}

#[cfg(test)]
mod test {
    use conn::{MyOpts};
    use std::default::{Default};
    use super::{MyPool};
    use super::super::super::value::{Bytes, Int};

    #[test]
    fn test_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                assert!(conn.query("SELECT 1").is_ok());
            });
        }
    }

    #[test]
    fn test_pooled_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let result = pool.query("SELECT 1");
                assert!(result.is_ok());
                let mut result = result.unwrap();
                assert_eq!(result.next(), Some(Ok(vec![Bytes(vec![0x31u8])])));
            });
        }
    }

    #[test]
    fn test_prepared_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                let stmt = conn.prepare("SELECT 1");
                assert!(stmt.is_ok());
                let mut stmt = stmt.unwrap();
                assert!(stmt.execute([]).is_ok());
            });
        }
    }

    #[test]
    fn test_pooled_prepared_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let stmt = pool.prepare("SELECT 1");
                assert!(stmt.is_ok());
                let mut stmt = stmt.unwrap();
                for _ in range(0u, 5u) {
                    let result = stmt.execute([]);
                    assert!(result.is_ok());
                    let mut result = result.unwrap();
                    assert_eq!(result.next(), Some(Ok(vec![Int(1)])));
                    assert_eq!(result.next(), None);
                }
            });
        }
    }
}
<commit_msg>Add docs to MyPooledConn<commit_after>use sync::{Arc, Mutex};
use super::super::error::{MyDriverError, InvalidPoolConstraints};
use super::{MyConn, MyOpts, Stmt, QueryResult};
use super::super::error::{MyResult};

struct MyInnerPool {
    opts: MyOpts,
    pool: Vec<MyConn>,
    min: uint,
    max: uint,
    count: uint
}

impl MyInnerPool {
    fn new(min: uint, max: uint, opts: MyOpts) -> MyResult<MyInnerPool> {
        if min > max || max == 0 {
            return Err(MyDriverError(InvalidPoolConstraints));
        }
        let mut pool = MyInnerPool {
            opts: opts,
            pool: Vec::with_capacity(max),
            max: max,
            min: min,
            count: 0
        };
        for _ in range(0, min) {
            try!(pool.new_conn());
        }
        Ok(pool)
    }
    fn new_conn(&mut self) -> MyResult<()> {
        match MyConn::new(self.opts.clone()) {
            Ok(conn) => {
                self.pool.push(conn);
                Ok(())
            },
            Err(err) => Err(err)
        }
    }
}

/// Pool which is holding mysql connections.
///
/// It will hold at least ```min``` connections and will create as many as
/// ```max``` connections.
///
/// ```
/// use mysql::conn::{MyOpts};
/// use std::default::{Default};
/// use mysql::conn::pool::{MyPool};
/// use mysql::value::{ToValue};
///
/// fn main() {
///     let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
///                                   ..Default::default()});
///     assert!(pool.is_ok());
///     let pool = pool.unwrap();
///     for _ in range(0u, 100) {
///         let pool = pool.clone();
///         spawn(proc() {
///             let conn = pool.get_conn();
///             assert!(conn.is_ok());
///             let mut conn = conn.unwrap();
///             let result = conn.query("SELECT 1");
///             assert!(result.is_ok());
///             let mut result = result.unwrap();
///             assert_eq!(result.next(), Some(Ok(vec!["1".to_value()])));
///         });
///     }
/// }
/// ```
#[deriving(Clone)]
pub struct MyPool {
    pool: Arc<Mutex<MyInnerPool>>
}

impl MyPool {
    /// Creates new pool with ```min = 10``` and ```max = 100```
    pub fn new(opts: MyOpts) -> MyResult<MyPool> {
        MyPool::new_manual(10, 100, opts)
    }

    /// Same as ```new``` but you can set ```min``` and ```max```
    pub fn new_manual(min: uint, max: uint, opts: MyOpts) -> MyResult<MyPool> {
        let pool = try!(MyInnerPool::new(min, max, opts));
        Ok(MyPool{ pool: Arc::new(Mutex::new(pool)) })
    }

    pub fn get_conn(&self) -> MyResult<MyPooledConn> {
        let mut pool = self.pool.lock();

        while pool.pool.is_empty() {
            if pool.count < pool.max {
                match pool.new_conn() {
                    Ok(()) => {
                        pool.count += 1;
                        break;
                    },
                    Err(err) => return Err(err)
                }
            } else {
                pool.cond.wait();
            }
        }

        let mut conn = pool.pool.pop().unwrap();

        if !conn.ping() {
            try!(conn.reset());
        }

        Ok(MyPooledConn {pool: self.clone(), conn: Some(conn)})
    }

    /// You can call ```query``` and ```prepare``` directly on a pool but be
    /// aware of the fact that you can't guarantee that query will be called
    /// at concrete connection.
    ///
    /// For example:
    ///
    /// ```ignore
    /// let opts = MyOpts{user: Some("root".to_string()), ..Default::default()};
    /// let pool = MyPool::new(opts).unwrap();
    ///
    /// pool.query("USE some_database");
    /// let result = pool.query("INSERT INTO users (name) VALUES ('Steven')");
    /// let result = pool.query("SELECT * FROM users"); // Error! `no database selected`
    ///                                                 // because PooledConn on which
    ///                                                 // you have executed USE was
    ///                                                 // borrowed by result shadowed
    ///                                                 // on previous line and will not
    ///                                                 // be available until the end of
    ///                                                 // its scope.
    /// ```
    pub fn query<'a>(&'a self, query: &'a str) -> MyResult<QueryResult<'a>> {
        let conn = try!(self.get_conn());
        conn.pooled_query(query)
    }

    /// See docs on ```Pool#query```
    pub fn prepare<'a>(&'a self, query: &'a str) -> MyResult<Stmt<'a>> {
        let conn = try!(self.get_conn());
        conn.pooled_prepare(query)
    }
}

/// Pooled mysql connection which will return to the pool at the end of its
/// scope.
pub struct MyPooledConn {
    pool: MyPool,
    conn: Option<MyConn>
}

impl Drop for MyPooledConn {
    fn drop(&mut self) {
        let mut pool = self.pool.pool.lock();
        if pool.count > pool.min || self.conn.is_none() {
            pool.count -= 1;
        } else {
            pool.pool.push(self.conn.take_unwrap());
        }
        pool.cond.signal();
    }
}

impl MyPooledConn {
    /// Redirects to ```MyConn#query```.
    pub fn query<'a>(&'a mut self, query: &str) -> MyResult<QueryResult<'a>> {
        self.conn.get_mut_ref().query(query)
    }

    /// Redirects to ```MyConn#prepare```.
    pub fn prepare<'a>(&'a mut self, query: &str) -> MyResult<Stmt<'a>> {
        self.conn.get_mut_ref().prepare(query)
    }

    /// Gives mutable reference to the wrapped ```MyConn```.
    pub fn get_mut_ref<'a>(&'a mut self) -> &'a mut MyConn {
        self.conn.get_mut_ref()
    }

    /// Gives reference to the wrapped ```MyConn```.
    pub fn get_ref<'a>(&'a self) -> &'a MyConn {
        self.conn.get_ref()
    }

    /// Unwraps wrapped ```MyConn```.
    pub fn unwrap(mut self) -> MyConn {
        self.conn.take_unwrap()
    }

    fn pooled_query(mut self, query: &str) -> MyResult<QueryResult> {
        match self.get_mut_ref()._query(query) {
            Ok((columns, ok_packet)) => Ok(QueryResult::new_pooled(self,
                                                                   columns,
                                                                   ok_packet,
                                                                   false)),
            Err(err) => Err(err)
        }
    }

    fn pooled_prepare(mut self, query: &str) -> MyResult<Stmt> {
        match self.get_mut_ref()._prepare(query) {
            Ok(stmt) => Ok(Stmt::new_pooled(stmt, self)),
            Err(err) => Err(err)
        }
    }
}

#[cfg(test)]
mod test {
    use conn::{MyOpts};
    use std::default::{Default};
    use super::{MyPool};
    use super::super::super::value::{Bytes, Int};

    #[test]
    fn test_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                assert!(conn.query("SELECT 1").is_ok());
            });
        }
    }

    #[test]
    fn test_pooled_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let result = pool.query("SELECT 1");
                assert!(result.is_ok());
                let mut result = result.unwrap();
                assert_eq!(result.next(), Some(Ok(vec![Bytes(vec![0x31u8])])));
            });
        }
    }

    #[test]
    fn test_prepared_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let conn = pool.get_conn();
                assert!(conn.is_ok());
                let mut conn = conn.unwrap();
                let stmt = conn.prepare("SELECT 1");
                assert!(stmt.is_ok());
                let mut stmt = stmt.unwrap();
                assert!(stmt.execute([]).is_ok());
            });
        }
    }

    #[test]
    fn test_pooled_prepared_query() {
        let pool = MyPool::new(MyOpts{user: Some("root".to_string()),
                                      ..Default::default()});
        assert!(pool.is_ok());
        let pool = pool.unwrap();
        for _ in range(0u, 10u) {
            let pool = pool.clone();
            spawn(proc() {
                let stmt = pool.prepare("SELECT 1");
                assert!(stmt.is_ok());
                let mut stmt = stmt.unwrap();
                for _ in range(0u, 5u) {
                    let result = stmt.execute([]);
                    assert!(result.is_ok());
                    let mut result = result.unwrap();
                    assert_eq!(result.next(), Some(Ok(vec![Int(1)])));
                    assert_eq!(result.next(), None);
                }
            });
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>also use BigInt::from<commit_after><|endoftext|>


<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_upper_case_globals,
        unused_qualifications)]

extern crate libc;
extern crate serialize;

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 RawGeoIp = *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) -> RawGeoIp;
    fn GeoIP_delete(db: RawGeoIp);
    fn GeoIP_name_by_ipnum_gl(db: RawGeoIp, ipnum: c_ulong, gl: &GeoIPLookup_) -> *const c_char;
    fn GeoIP_name_by_ipnum_v6_gl(db: RawGeoIp, ipnum: In6Addr, gl: &GeoIPLookup_) -> *const c_char;
    fn GeoIP_record_by_ipnum(db: RawGeoIp, ipnum: c_ulong) -> *const GeoIPRecord_;
    fn GeoIP_record_by_ipnum_v6(db: RawGeoIp, ipnum: In6Addr) -> *const GeoIPRecord_;
    fn GeoIPRecord_delete(gir: *const GeoIPRecord_);
    fn GeoIP_set_charset(db: RawGeoIp, 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: RawGeoIp
}

#[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
}

#[deriving(Decodable, Encodable)]
pub struct ASInfo {
    pub asn: uint,
    pub name: String,
    pub netmask: uint
}

#[deriving(Decodable, Encodable)]
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
}

unsafe fn maybe_string(c_str: *const c_char) -> Option<String> {
    c_str.as_ref().and_then(|opt| {
        CString::new(opt, false).as_str().map(|s| s.to_string())
    })
}

impl CityInfo {
    unsafe fn from_geoiprecord(res: &GeoIPRecord_) -> CityInfo {
        CityInfo {
            country_code: maybe_string(res.country_code),
            country_code3: maybe_string(res.country_code3),
            country_name: maybe_string(res.country_name),
            region: maybe_string(res.region),
            city: maybe_string(res.city),
            postal_code: maybe_string(res.postal_code),
            latitude: res.latitude 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: maybe_string(res.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; }

        unsafe {
            let city_info = CityInfo::from_geoiprecord(&*cres);
            GeoIPRecord_delete(cres);
            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>GeoIPLookup_ -> GeoIpLookup<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;
extern crate serialize;

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 RawGeoIp = *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) -> RawGeoIp;
    fn GeoIP_delete(db: RawGeoIp);
    fn GeoIP_name_by_ipnum_gl(db: RawGeoIp, ipnum: c_ulong, gl: &GeoIpLookup) -> *const c_char;
    fn GeoIP_name_by_ipnum_v6_gl(db: RawGeoIp, ipnum: In6Addr, gl: &GeoIpLookup) -> *const c_char;
    fn GeoIP_record_by_ipnum(db: RawGeoIp, ipnum: c_ulong) -> *const GeoIPRecord_;
    fn GeoIP_record_by_ipnum_v6(db: RawGeoIp, ipnum: In6Addr) -> *const GeoIPRecord_;
    fn GeoIPRecord_delete(gir: *const GeoIPRecord_);
    fn GeoIP_set_charset(db: RawGeoIp, 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: RawGeoIp
}

#[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
}

#[deriving(Decodable, Encodable)]
pub struct ASInfo {
    pub asn: uint,
    pub name: String,
    pub netmask: uint
}

#[deriving(Decodable, Encodable)]
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
}

unsafe fn maybe_string(c_str: *const c_char) -> Option<String> {
    c_str.as_ref().and_then(|opt| {
        CString::new(opt, false).as_str().map(|s| s.to_string())
    })
}

impl CityInfo {
    unsafe fn from_geoiprecord(res: &GeoIPRecord_) -> CityInfo {
        CityInfo {
            country_code: maybe_string(res.country_code),
            country_code3: maybe_string(res.country_code3),
            country_name: maybe_string(res.country_name),
            region: maybe_string(res.region),
            city: maybe_string(res.city),
            postal_code: maybe_string(res.postal_code),
            latitude: res.latitude 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: maybe_string(res.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; }

        unsafe {
            let city_info = CityInfo::from_geoiprecord(&*cres);
            GeoIPRecord_delete(cres);
            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><commit_msg>Play a sine<commit_after><|endoftext|>


<commit_before>use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::is_ty_param_diagnostic_item;
use rustc_hir::{self as hir, def_id::DefId, QPath};
use rustc_lint::LateContext;
use rustc_span::symbol::sym;

use super::BOX_COLLECTION;

pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
    if_chain! {
        if Some(def_id) == cx.tcx.lang_items().owned_box();
        if let Some(item_type) = get_std_collection(cx, qpath);
        then {
            let generic = if item_type == "String" {
                ""
            } else {
                "<..>"
            };
            span_lint_and_help(
                cx,
                BOX_COLLECTION,
                hir_ty.span,
                &format!(
                    "you seem to be trying to use `Box<{outer}{generic}>`. Consider using just `{outer}{generic}`",
                    outer=item_type,
                    generic = generic),
                None,
                &format!(
                    "`{outer}{generic}` is already on the heap, `Box<{outer}{generic}>` makes an extra allocation",
                    outer=item_type,
                    generic = generic)
            );
            true
        } else {
            false
        }
    }
}

fn get_std_collection(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<String> {
    if is_ty_param_diagnostic_item(cx, qpath, sym::vec_type).is_some() {
        Some(String::from("Vec"))
    } else if is_ty_param_diagnostic_item(cx, qpath, sym::string_type).is_some() {
        Some(String::from("String"))
    } else if is_ty_param_diagnostic_item(cx, qpath, sym::hashmap_type).is_some() {
        Some(String::from("HashMap"))
    } else {
        None
    }
}
<commit_msg>Auto merge of #7715 - F3real:vec2, r=camsteffen<commit_after>use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::is_ty_param_diagnostic_item;
use rustc_hir::{self as hir, def_id::DefId, QPath};
use rustc_lint::LateContext;
use rustc_span::symbol::sym;

use super::BOX_COLLECTION;

pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
    if_chain! {
        if Some(def_id) == cx.tcx.lang_items().owned_box();
        if let Some(item_type) = get_std_collection(cx, qpath);
        then {
            let generic = if item_type == "String" {
                ""
            } else {
                "<..>"
            };
            span_lint_and_help(
                cx,
                BOX_COLLECTION,
                hir_ty.span,
                &format!(
                    "you seem to be trying to use `Box<{outer}{generic}>`. Consider using just `{outer}{generic}`",
                    outer=item_type,
                    generic = generic),
                None,
                &format!(
                    "`{outer}{generic}` is already on the heap, `Box<{outer}{generic}>` makes an extra allocation",
                    outer=item_type,
                    generic = generic)
            );
            true
        } else {
            false
        }
    }
}

fn get_std_collection(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> {
    if is_ty_param_diagnostic_item(cx, qpath, sym::vec_type).is_some() {
        Some("Vec")
    } else if is_ty_param_diagnostic_item(cx, qpath, sym::string_type).is_some() {
        Some("String")
    } else if is_ty_param_diagnostic_item(cx, qpath, sym::hashmap_type).is_some() {
        Some("HashMap")
    } else {
        None
    }
}
<|endoftext|>


<commit_before>extern crate chrono;
use self::chrono::*;

use std::io;
use std::fs;
use std::fs::OpenOptions;
use std::io::Write;
use std::io::BufReader;
use std::io::BufRead;

pub fn store_event(name: String, details: Vec<String>) -> io::Result<()> {
    let now: DateTime<Local> = Local::now();
    let mut f = OpenOptions::new()
                .read(true)
                .write(true)
                .create(true)
                .append(true)
                .open("/tmp/.soji_data.csv")
                .expect("couldn't open data file");
    let mut row_data = details.to_vec();
    row_data.insert(0, name);
    row_data.push(now.format("%Y-%m-%d %H:%M:%S %z").to_string());
    let row_string = row_data.join(",");
    try!(f.write_all(row_string.as_bytes()));
    try!(f.write_all("\n".as_bytes()));
    Ok(())
}

pub fn current_task() -> Result<String, String>{
    let f = match fs::File::open("/tmp/.soji_data.csv") {
        Err(_) => return Ok("".to_string()),
        Ok(file) => file
    };
    let f = BufReader::new(f);
    let mut status : String = "".to_string();
    for line in f.lines() {
        let line_copy = line.unwrap();
        if &line_copy[..5] == "start" {
            let mut components = line_copy.split(",");
            let _ = components.nth(0);
            let event_name = components.nth(0).expect("start event expected to have task name").to_string();
            let start_time = components.nth(0).expect("start event expected to have start time").to_string();
            status = format!("{} -- {:?} min", event_name, ((Local::now().timestamp() - chrono::datetime::DateTime::parse_from_str(&start_time, "%Y-%m-%d %H:%M:%S %z").expect("date not found").timestamp()) / 60));
        }
    }
    Ok(status)
}
<commit_msg>Write data to $HOME dir<commit_after>extern crate chrono;
use self::chrono::*;

use std::io;
use std::fs;
use std::fs::OpenOptions;
use std::io::Write;
use std::io::BufReader;
use std::io::BufRead;

pub fn store_event(name: String, details: Vec<String>) -> io::Result<()> {
    let now: DateTime<Local> = Local::now();
    let mut f = OpenOptions::new()
                .read(true)
                .write(true)
                .create(true)
                .append(true)
                .open(env!("HOME").to_string() + "/.soji/.soji_data.csv")
                .expect("couldn't open data file");
    let mut row_data = details.to_vec();
    row_data.insert(0, name);
    row_data.push(now.format("%Y-%m-%d %H:%M:%S %z").to_string());
    let row_string = row_data.join(",");
    try!(f.write_all(row_string.as_bytes()));
    try!(f.write_all("\n".as_bytes()));
    Ok(())
}

pub fn current_task() -> Result<String, String>{
    let f = match fs::File::open(env!("HOME").to_string() + "/.soji/.soji_data.csv") {
        Err(_) => return Ok("".to_string()),
        Ok(file) => file
    };
    let f = BufReader::new(f);
    let mut status : String = "".to_string();
    for line in f.lines() {
        let line_copy = line.unwrap();
        if &line_copy[..5] == "start" {
            let mut components = line_copy.split(",");
            let _ = components.nth(0);
            let event_name = components.nth(0).expect("start event expected to have task name").to_string();
            let start_time = components.nth(0).expect("start event expected to have start time").to_string();
            status = format!("{} -- {:?} min", event_name, ((Local::now().timestamp() - chrono::datetime::DateTime::parse_from_str(&start_time, "%Y-%m-%d %H:%M:%S %z").expect("date not found").timestamp()) / 60));
        }
    }
    Ok(status)
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::path::Path;
use std::rc::Rc;
use sdl2::render::{Renderer, Texture};
use sdl2::image::{LoadTexture};

use game::data::Rectangle;

#[derive(Clone)]
pub struct Sprite {
  tex: Rc<RefCell<Texture>>,
  src: Rectangle,
}

impl Sprite {
  pub fn new(texture: Texture) -> Sprite {
    let tex_query = texture.query();

    Sprite {
      tex: Rc::new(RefCell::new(texture)),
      src: Rectangle {
        w: tex_query.width as f64,
        h: tex_query.height as f64,
        x: 0.0,
        y: 0.0,
      }
    }
  }

  pub fn load(renderer: &Renderer, path: &str) -> Option<Sprite> {
    renderer.load_texture(Path::new(path)).ok().map(Sprite::new)
  }

  pub fn size(&self) -> (f64, f64) {
    (self.src.w, self.src.h)
  }

  pub fn region(&self, rect: Rectangle) -> Option<Sprite> {
    let new_src = Rectangle {
      x: rect.x + self.src.x,
      y: rect.y + self.src.y,
      ..rect
    };

    if self.src.contains(new_src) {
      Some(Sprite {
        tex: self.tex.clone(),
        src: new_src,
      })
    } else {
      None
    }
  }

  pub fn render(&self, renderer: &mut Renderer, dest: Rectangle) {
    renderer.copy(&mut self.tex.borrow_mut(), self.src.to_sdl(), dest.to_sdl()).unwrap();
  }
}

pub trait CopySprite {
  fn copy_sprite(&mut self, sprite: &Sprite, dest: Rectangle);
}

impl<'window> CopySprite for Renderer<'window> {
  fn copy_sprite(&mut self, sprite: &Sprite, dest: Rectangle) {
   sprite.render(self, dest);
 }
}
<commit_msg>Add error handling for not found textures<commit_after>use std::cell::RefCell;
use std::path::Path;
use std::rc::Rc;
use std::result::Result;
use sdl2::render::{Renderer, Texture};
use sdl2::image::{LoadTexture};

use game::data::Rectangle;

#[derive(Clone)]
pub struct Sprite {
  tex: Rc<RefCell<Texture>>,
  src: Rectangle,
}

impl Sprite {
  pub fn new(texture: Texture) -> Sprite {
    let tex_query = texture.query();

    Sprite {
      tex: Rc::new(RefCell::new(texture)),
      src: Rectangle {
        w: tex_query.width as f64,
        h: tex_query.height as f64,
        x: 0.0,
        y: 0.0,
      }
    }
  }

  pub fn load(renderer: &Renderer, path: &str) -> Option<Sprite> {
    match renderer.load_texture(Path::new(path)).ok() {
      Some(f) => Some(f).map(Sprite::new),
      None => panic!("File not fount {}", path),
    }
  }

  pub fn size(&self) -> (f64, f64) {
    (self.src.w, self.src.h)
  }

  pub fn region(&self, rect: Rectangle) -> Option<Sprite> {
    let new_src = Rectangle {
      x: rect.x + self.src.x,
      y: rect.y + self.src.y,
      ..rect
    };

    if self.src.contains(new_src) {
      Some(Sprite {
        tex: self.tex.clone(),
        src: new_src,
      })
    } else {
      None
    }
  }

  pub fn render(&self, renderer: &mut Renderer, dest: Rectangle) {
    renderer.copy(&mut self.tex.borrow_mut(), self.src.to_sdl(), dest.to_sdl()).unwrap();
  }
}

pub trait CopySprite {
  fn copy_sprite(&mut self, sprite: &Sprite, dest: Rectangle);
}

impl<'window> CopySprite for Renderer<'window> {
  fn copy_sprite(&mut self, sprite: &Sprite, dest: Rectangle) {
   sprite.render(self, dest);
 }
}
<|endoftext|>


<commit_before>use ::screen;
use ::screen::Screen;

use piston_window;

pub struct Game {
    window: piston_window::PistonWindow,
    screens: Vec<Box<screen::Screen>>,
}

impl Game {
    pub fn new() -> Game {
        let window: piston_window::PistonWindow = piston_window::WindowSettings::new("rrthozopsi", [600, 600]).exit_on_esc(true).build().unwrap();
        let screens: Vec<Box<screen::Screen>> = vec![Box::new(screen::MainMenuScreen::new())];
        Game {
            window: window,
            screens: screens,
        }
    }

    pub fn run(&mut self) {
        use piston_window::Event;

        let mut screen = self.screens.last_mut().unwrap();

        // TODO: Remove clone?
        for window in &mut self.window {
            match window.event {
                Some(Event::Update(args)) => { screen.on_update(&args); }
                Some(Event::Render(args)) => { screen.on_draw(&args, &window); }
                Some(Event::Input(ref input)) => {
            	    for action in screen.on_input(&input, &window) {
            		match action {
            		    screen::InputResult::PushScreen(_) => {}
            		    screen::InputResult::PopScreen => {}
            		}
            	    }
            	    //let result = screen.on_input(&input, &window);
            	}
                _ => {}
            }
        }
    }
}
<commit_msg>PopScreen handling<commit_after>use ::screen;
use ::screen::Screen;

use piston_window;

pub struct Game {
    window: piston_window::PistonWindow,
    screens: Vec<Box<screen::Screen>>,
}

impl Game {
    pub fn new() -> Game {
        let window: piston_window::PistonWindow = piston_window::WindowSettings::new("rrthozopsi", [600, 600]).exit_on_esc(true).build().unwrap();
        let screens: Vec<Box<screen::Screen>> = vec![Box::new(screen::MainMenuScreen::new())];
        Game {
            window: window,
            screens: screens,
        }
    }

    pub fn run(&mut self) {
        use piston_window::Event;

	// ???
	// TODO: Use drop to unborrow?
        //let mut screen = self.screens.last_mut().unwrap();

        // TODO: Remove clone?
        for window in &mut self.window {
            match window.event {
                Some(Event::Update(args)) => { self.screens.last_mut().unwrap().on_update(&args); }
                Some(Event::Render(args)) => { self.screens.last_mut().unwrap().on_draw(&args, &window); }
                Some(Event::Input(ref input)) => {
            	    for action in self.screens.last_mut().unwrap().on_input(&input, &window) {
            		match action {
            		    screen::InputResult::PushScreen(_) => {}
            		    screen::InputResult::PopScreen => {
            			self.screens.pop();
            		    }
            		}
            	    }
            	    //let result = screen.on_input(&input, &window);
            	}
                _ => {}
            }
        }
    }
}
<|endoftext|>


<commit_before>pub mod foreign_items;
pub mod intrinsics;
pub mod tls;
pub mod dlsym;
pub mod env;

use rustc::{ty, mir};

use crate::*;

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn find_fn(
        &mut self,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, Tag>],
        dest: Option<PlaceTy<'tcx, Tag>>,
        ret: Option<mir::BasicBlock>,
    ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
        let this = self.eval_context_mut();
        trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place));

        // First, run the common hooks also supported by CTFE.
        if this.hook_fn(instance, args, dest)? {
            this.goto_block(ret)?;
            return Ok(None);
        }
        // There are some more lang items we want to hook that CTFE does not hook (yet).
        if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) {
            let dest = dest.unwrap();
            let n = this.align_offset(args[0], args[1], dest.layout)?;
            this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?;
            this.goto_block(ret)?;
            return Ok(None);
        }

        // Try to see if we can do something about foreign items.
        if this.tcx.is_foreign_item(instance.def_id()) {
            // An external function that we cannot find MIR for, but we can still run enough
            // of them to make miri viable.
            this.emulate_foreign_item(instance.def_id(), args, dest, ret)?;
            // `goto_block` already handled.
            return Ok(None);
        }

        // Otherwise, load the MIR.
        Ok(Some(this.load_mir(instance.def, None)?))
    }

    fn align_offset(
        &mut self,
        ptr_op: OpTy<'tcx, Tag>,
        align_op: OpTy<'tcx, Tag>,
        layout: ty::layout::TyLayout<'tcx>,
    ) -> InterpResult<'tcx, u128> {
        let this = self.eval_context_mut();

        let req_align = this.force_bits(
            this.read_scalar(align_op)?.not_undef()?,
            this.pointer_size()
        )? as usize;

        let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?;

        if let Scalar::Ptr(ptr) = ptr_scalar {
            let cur_align = this.memory().get(ptr.alloc_id)?.align.bytes() as usize;
            if cur_align < req_align {
                return Ok(this.truncate(u128::max_value(), layout));
            }
        }

        // if the allocation alignment is at least the required alignment or if the pointer is an
        // integer, we use the libcore implementation
        Ok(
            (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8)
            .align_offset(req_align) as u128
        )
    }
}
<commit_msg>Throw unsupported error when alignment is not a power of two<commit_after>pub mod foreign_items;
pub mod intrinsics;
pub mod tls;
pub mod dlsym;
pub mod env;

use rustc::{ty, mir};

use crate::*;

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn find_fn(
        &mut self,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, Tag>],
        dest: Option<PlaceTy<'tcx, Tag>>,
        ret: Option<mir::BasicBlock>,
    ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
        let this = self.eval_context_mut();
        trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place));

        // First, run the common hooks also supported by CTFE.
        if this.hook_fn(instance, args, dest)? {
            this.goto_block(ret)?;
            return Ok(None);
        }
        // There are some more lang items we want to hook that CTFE does not hook (yet).
        if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) {
            let dest = dest.unwrap();
            let n = this.align_offset(args[0], args[1], dest.layout)?;
            this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?;
            this.goto_block(ret)?;
            return Ok(None);
        }

        // Try to see if we can do something about foreign items.
        if this.tcx.is_foreign_item(instance.def_id()) {
            // An external function that we cannot find MIR for, but we can still run enough
            // of them to make miri viable.
            this.emulate_foreign_item(instance.def_id(), args, dest, ret)?;
            // `goto_block` already handled.
            return Ok(None);
        }

        // Otherwise, load the MIR.
        Ok(Some(this.load_mir(instance.def, None)?))
    }

    fn align_offset(
        &mut self,
        ptr_op: OpTy<'tcx, Tag>,
        align_op: OpTy<'tcx, Tag>,
        layout: ty::layout::TyLayout<'tcx>,
    ) -> InterpResult<'tcx, u128> {
        let this = self.eval_context_mut();

        let req_align = this.force_bits(
            this.read_scalar(align_op)?.not_undef()?,
            this.pointer_size()
        )? as usize;

        // FIXME: This should actually panic in the interpreted program
        if !req_align.is_power_of_two() {
            throw_unsup_format!("Required alignment should always be a power of two")
        }

        let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?;

        if let Scalar::Ptr(ptr) = ptr_scalar {
            let cur_align = this.memory().get(ptr.alloc_id)?.align.bytes() as usize;
            if cur_align < req_align {
                return Ok(this.truncate(u128::max_value(), layout));
            }
        }

        // if the allocation alignment is at least the required alignment or if the pointer is an
        // integer, we use the libcore implementation
        Ok(
            (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8)
            .align_offset(req_align) as u128
        )
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Write};
use std::fs::{File, create_dir_all, set_permissions, metadata};
use std::os::unix::ffi::OsStrExt;
use std::os::unix::fs::{symlink, MetadataExt, PermissionsExt};
use std::path::Path;
use std::collections::{BTreeMap, BTreeSet};

use cronparse::Limited;
use cronparse::crontab::{CrontabEntry, SystemCrontabEntry, UserCrontabEntry};
use cronparse::schedule::{Schedule, Period, Calendar};
use cronparse::interval::Interval;

use users::{get_user_by_name, get_user_by_uid};

use super::{REBOOT_FILE, PACKAGE, LIB_DIR};

pub fn generate_systemd_units(entry: CrontabEntry, env: &BTreeMap<String, String>, path: &Path, dstdir: &Path) -> io::Result<()> {
    use cronparse::crontab::CrontabEntry::*;

    info!("generating units for {}: \"{}\", {:?}", path.display(), entry, env);

    let owner = try!(metadata(path)).uid();

    let mut persistent = env.get("PERSISTENT").and_then(|v| match &**v {
        "yes" | "true" | "1" => Some(true),
        "auto" | "" => None,
        _ => Some(false)
    }).unwrap_or_else(|| match entry {
        Anacron(_) | User(UserCrontabEntry { sched: Schedule::Period(_), .. }) | System(SystemCrontabEntry { sched: Schedule::Period(_), .. }) => true,
        _ => false
    });

    let batch = env.get("BATCH").map(|v| match &**v {
        "yes" | "true" | "1" => true,
        _ => false
    }).unwrap_or(false);

    let random_delay = env.get("RANDOM_DELAY").and_then(|v| v.parse::<u64>().ok()).unwrap_or(1);
    let mut delay = env.get("DELAY").and_then(|v| v.parse::<u64>().ok()).unwrap_or(0);
    let hour = env.get("START_HOURS_RANGE").and_then(|v| v.splitn(1, '-').next().and_then(|v| v.parse::<u64>().ok())).unwrap_or(0);
    let shell = env.get("SHELL").map(|v| &**v).unwrap_or("/bin/sh");
    let daemon_reload = metadata(REBOOT_FILE).map(|m| m.is_file()).unwrap_or(false);

    let schedule = entry.period().and_then(|period| match *period {
        Period::Reboot => {
            persistent = false;
            if delay == 0 {
                delay = 1;
            }
            None
        },
        Period::Minutely => {
            persistent = false;
            Some("@minutely".to_owned())
        },
        Period::Hourly => {
            if delay == 0 {
                Some("@hourly".to_owned())
            } else {
                Some(format!("*-*-* *:{}:0", delay))
            }
        },
        Period::Midnight => {
            if delay == 0 {
                Some("@daily".to_owned())
            } else {
                Some(format!("*-*-* 0:{}:0", delay))
            }
        },
        Period::Daily => {
            if delay == 0 && hour == 0 {
                Some("@daily".to_owned())
            } else {
                Some(format!("*-*-* {}:{}:0", hour, delay))
            }
        },
        Period::Weekly => {
            if delay == 0 && hour == 0 {
                Some("@weekly".to_owned())
            } else {
                Some(format!("Mon *-*-* {}:{}:0", hour, delay))
            }
        },
        Period::Monthly => {
            if delay == 0 && hour == 0 {
                Some("@monthly".to_owned())
            } else {
                Some(format!("*-*-1 {}:{}:0", hour, delay))
            }
        },
        Period::Quaterly => {
            if delay == 0 && hour == 0 {
                Some("@quaterly".to_owned())
            } else {
                Some(format!("*-1,4,7,10-1 {}:{}:0", hour, delay))
            }
        },
        Period::Biannually => {
            if delay == 0 && hour == 0 {
                Some("@semi-annually".to_owned())
            } else {
                Some(format!("*-1,7-1 {}:{}:0", hour, delay))
            }
        },
        Period::Yearly => {
            if delay == 0 && hour == 0 {
                Some("@yearly".to_owned())
            } else {
                Some(format!("*-1-1 {}:{}:0", hour, delay))
            }
        },
        Period::Days(days) => {
            // workaround for anacrontab
            if days > 31 {
                Some(format!("*-1/{}-1 {}:{}:0", days / 30, hour, delay))
            } else {
                Some(format!("*-*-1/{} {}:{}:0", days, hour, delay))
            }
        },
    }).or_else(|| entry.calendar().and_then(|cal| {
        let Calendar {
            ref dows,
            ref days,
            ref mons,
            ref hrs,
            ref mins
        } = *cal;

        Some(format!("{} *-{}-{} {}:{}:00",
                     linearize(&**dows, "", ToString::to_string),
                     linearize(&**mons, "*", |&mon| (mon as u8).to_string()),
                     linearize(&**days, "*", ToString::to_string),
                     linearize(&**hrs, "*", ToString::to_string),
                     linearize(&**mins, "*", ToString::to_string)))
    }));

    if daemon_reload && schedule.is_none() {
        warn!("skipping job from {}: \"{}\"", path.display(), entry);
        return Ok(());
    }

    if let Some(cmd) = entry.command() {

        // make sure we know the user
        let user = try!(entry.user().and_then(get_user_by_name).or_else(|| get_user_by_uid(owner))
            .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "unknown user")));

        // generate unique cron job id
        let mut md5ctx = ::md5::Context::new();
        md5ctx.consume(path.as_os_str().as_bytes());
        if let Some(ref schedule) = schedule {
            md5ctx.consume(schedule.as_bytes());
        }
        md5ctx.consume(cmd.as_bytes());
        let md5hex = tohex(&md5ctx.compute());

        // create service and timer unit names
        let service_unit_name = format!("cron-{}.service", md5hex);
        let timer_unit_name = format!("cron-{}.timer", md5hex);

        // unit paths
        let service_unit_path = dstdir.join(&service_unit_name);
        let timer_unit_path = dstdir.join(&timer_unit_name);

        // make sure cron.target.wants dir exists
        let cron_target_wants_path = dstdir.join("cron.target.wants");
        try!(create_dir_all(&cron_target_wants_path));

        // process command in case it should be put into script
        let command = if metadata(cmd).map(|m| m.is_file()).unwrap_or(false) {
            cmd.to_owned()
        } else {
            let script_command_path = dstdir.join(format!("cron-{}.sh", md5hex));

            debug!("generating script {:?} from {:?}", script_command_path, path);
            {
                let mut script_command_file = try!(File::create(&script_command_path));
                try!(writeln!(script_command_file, "#!{}", shell));
                try!(writeln!(script_command_file, "{}", cmd));
            }

            let mut perms = try!(metadata(&script_command_path)).permissions();
            perms.set_mode(0o755);
            try!(set_permissions(&script_command_path, perms));
            script_command_path.to_str().unwrap().to_owned()
        };

        debug!("generating service {:?} from {:?}", service_unit_path, path);
        {
            let mut service_unit_file = try!(File::create(service_unit_path));

            try!(writeln!(service_unit_file, r###"[Unit]
Description=[Cron] "{entry}"
Documentation=man:systemd-crontab-generator(8)
RefuseManualStart=true
RefuseManualStop=true
SourcePath={source_crontab_path}"###,
                entry = entry,
                source_crontab_path = path.display(),
                ));

            if env.contains_key("MAILTO") {
                try!(writeln!(service_unit_file, "OnFailure=cron-failure@%i.service"));
            }

            if user.uid != 0 {
                try!(writeln!(service_unit_file, "Requires=systemd-user-sessions.service"));
                if !user.home_dir.is_empty() {
                    try!(writeln!(service_unit_file, "RequiresMountsFor={}", user.home_dir));
                }
            }

            try!(writeln!(service_unit_file, r###"
[Service]
Type=oneshot
IgnoreSIGPIPE=false
ExecStart={command}"###,
                command = command,
                ));

            if schedule.is_some() && delay > 0 {
                try!(writeln!(service_unit_file, "ExecStartPre=-{}/{}/boot-delay {}", LIB_DIR, PACKAGE, delay));
            }

            if user.uid != 0 {
                try!(writeln!(service_unit_file, "User={}", user.name));
            }

            if let Some(group) = entry.group() {
                try!(writeln!(service_unit_file, "Group={}", group));
            }
            if batch {
                try!(writeln!(service_unit_file, "CPUSchedulingPolicy=idle"));
                try!(writeln!(service_unit_file, "IOSchedulingClass=idle"));
            }

            if !env.is_empty() {
                for (name, value) in env.iter() {
                    try!(writeln!(service_unit_file, r#"Environment="{}={}""#, name, value));
                }
            }
        }

        debug!("generating timer {:?} from {:?}", timer_unit_path, path);
        {
            let mut timer_unit_file = try!(File::create(&timer_unit_path));

            try!(writeln!(timer_unit_file, r###"[Unit]
Description=[Timer] "{entry}"
Documentation=man:systemd-crontab-generator(8)
PartOf=cron.target
RefuseManualStart=true
RefuseManualStop=true
SourcePath={source_crontab_path}

[Timer]
Unit={service_unit_name}"###,
                entry = entry,
                source_crontab_path = path.display(),
                service_unit_name = service_unit_name,
                ));

            if cfg![feature="persistent"] {
                try!(writeln!(timer_unit_file, "Persistent={}", persistent));
            }

            if let Some(schedule) = schedule {
                try!(writeln!(timer_unit_file, "OnCalendar={}", schedule));
            } else {
                try!(writeln!(timer_unit_file, "OnBootSec={}m", delay));
            }

            if random_delay != 1 {
                try!(writeln!(timer_unit_file, "AccuracySec={}m", random_delay));
            }
        }
        try!(symlink(timer_unit_path, cron_target_wants_path.join(timer_unit_name)));
    }

    Ok(())
}

fn linearize<T, C>(input: &[Interval<T>], star: &str, conv: C) -> String where T: Limited, C: Fn(&T) -> String {
    if input.len() == 1 && input[0] == Interval::Full(1) {
        star.to_owned()
    } else {
        let mut output = String::new();
        for part in input.iter().flat_map(|v| v.iter()).collect::<BTreeSet<_>>().iter() {
            output.push_str(&*conv(&part));
            output.push(',');
        }
        output.pop();
        output
    }
}

fn tohex(input: &[u8]) -> String {
    #[inline]
    fn hex(d: u8) -> char {
        match d {
            0...9 => (d + 0x30) as char,
            10...15 => (d + 0x57) as char,
            _ => unreachable!("unexpected value: {}", d)
        }
    }

    let mut buf = String::with_capacity(32);
    for b in input.into_iter() {
        buf.push(hex(b >> 4));
        buf.push(hex(b & 0xf));
    }
    buf
}

<commit_msg>fix #34: incorrect special schedule experssions<commit_after>use std::io::{self, Write};
use std::fs::{File, create_dir_all, set_permissions, metadata};
use std::os::unix::ffi::OsStrExt;
use std::os::unix::fs::{symlink, MetadataExt, PermissionsExt};
use std::path::Path;
use std::collections::{BTreeMap, BTreeSet};

use cronparse::Limited;
use cronparse::crontab::{CrontabEntry, SystemCrontabEntry, UserCrontabEntry};
use cronparse::schedule::{Schedule, Period, Calendar};
use cronparse::interval::Interval;

use users::{get_user_by_name, get_user_by_uid};

use super::{REBOOT_FILE, PACKAGE, LIB_DIR};

pub fn generate_systemd_units(entry: CrontabEntry, env: &BTreeMap<String, String>, path: &Path, dstdir: &Path) -> io::Result<()> {
    use cronparse::crontab::CrontabEntry::*;

    info!("generating units for {}: \"{}\", {:?}", path.display(), entry, env);

    let owner = try!(metadata(path)).uid();

    let mut persistent = env.get("PERSISTENT").and_then(|v| match &**v {
        "yes" | "true" | "1" => Some(true),
        "auto" | "" => None,
        _ => Some(false)
    }).unwrap_or_else(|| match entry {
        Anacron(_) | User(UserCrontabEntry { sched: Schedule::Period(_), .. }) | System(SystemCrontabEntry { sched: Schedule::Period(_), .. }) => true,
        _ => false
    });

    let batch = env.get("BATCH").map(|v| match &**v {
        "yes" | "true" | "1" => true,
        _ => false
    }).unwrap_or(false);

    let random_delay = env.get("RANDOM_DELAY").and_then(|v| v.parse::<u64>().ok()).unwrap_or(1);
    let mut delay = env.get("DELAY").and_then(|v| v.parse::<u64>().ok()).unwrap_or(0);
    let hour = env.get("START_HOURS_RANGE").and_then(|v| v.splitn(1, '-').next().and_then(|v| v.parse::<u64>().ok())).unwrap_or(0);
    let shell = env.get("SHELL").map(|v| &**v).unwrap_or("/bin/sh");
    let daemon_reload = metadata(REBOOT_FILE).map(|m| m.is_file()).unwrap_or(false);

    let schedule = entry.period().and_then(|period| match *period {
        Period::Reboot => {
            persistent = false;
            if delay == 0 {
                delay = 1;
            }
            None
        },
        Period::Minutely => {
            persistent = false;
            Some("minutely".to_owned())
        },
        Period::Hourly => {
            if delay == 0 {
                Some("hourly".to_owned())
            } else {
                Some(format!("*-*-* *:{}:0", delay))
            }
        },
        Period::Midnight => {
            if delay == 0 {
                Some("daily".to_owned())
            } else {
                Some(format!("*-*-* 0:{}:0", delay))
            }
        },
        Period::Daily => {
            if delay == 0 && hour == 0 {
                Some("daily".to_owned())
            } else {
                Some(format!("*-*-* {}:{}:0", hour, delay))
            }
        },
        Period::Weekly => {
            if delay == 0 && hour == 0 {
                Some("weekly".to_owned())
            } else {
                Some(format!("Mon *-*-* {}:{}:0", hour, delay))
            }
        },
        Period::Monthly => {
            if delay == 0 && hour == 0 {
                Some("monthly".to_owned())
            } else {
                Some(format!("*-*-1 {}:{}:0", hour, delay))
            }
        },
        Period::Quaterly => {
            if delay == 0 && hour == 0 {
                Some("quaterly".to_owned())
            } else {
                Some(format!("*-1,4,7,10-1 {}:{}:0", hour, delay))
            }
        },
        Period::Biannually => {
            if delay == 0 && hour == 0 {
                Some("semiannually".to_owned())
            } else {
                Some(format!("*-1,7-1 {}:{}:0", hour, delay))
            }
        },
        Period::Yearly => {
            if delay == 0 && hour == 0 {
                Some("yearly".to_owned())
            } else {
                Some(format!("*-1-1 {}:{}:0", hour, delay))
            }
        },
        Period::Days(days) => {
            // workaround for anacrontab
            if days > 31 {
                Some(format!("*-1/{}-1 {}:{}:0", days / 30, hour, delay))
            } else {
                Some(format!("*-*-1/{} {}:{}:0", days, hour, delay))
            }
        },
    }).or_else(|| entry.calendar().and_then(|cal| {
        let Calendar {
            ref dows,
            ref days,
            ref mons,
            ref hrs,
            ref mins
        } = *cal;

        Some(format!("{} *-{}-{} {}:{}:00",
                     linearize(&**dows, "", ToString::to_string),
                     linearize(&**mons, "*", |&mon| (mon as u8).to_string()),
                     linearize(&**days, "*", ToString::to_string),
                     linearize(&**hrs, "*", ToString::to_string),
                     linearize(&**mins, "*", ToString::to_string)))
    }));

    if daemon_reload && schedule.is_none() {
        warn!("skipping job from {}: \"{}\"", path.display(), entry);
        return Ok(());
    }

    if let Some(cmd) = entry.command() {

        // make sure we know the user
        let user = try!(entry.user().and_then(get_user_by_name).or_else(|| get_user_by_uid(owner))
            .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "unknown user")));

        // generate unique cron job id
        let mut md5ctx = ::md5::Context::new();
        md5ctx.consume(path.as_os_str().as_bytes());
        if let Some(ref schedule) = schedule {
            md5ctx.consume(schedule.as_bytes());
        }
        md5ctx.consume(cmd.as_bytes());
        let md5hex = tohex(&md5ctx.compute());

        // create service and timer unit names
        let service_unit_name = format!("cron-{}.service", md5hex);
        let timer_unit_name = format!("cron-{}.timer", md5hex);

        // unit paths
        let service_unit_path = dstdir.join(&service_unit_name);
        let timer_unit_path = dstdir.join(&timer_unit_name);

        // make sure cron.target.wants dir exists
        let cron_target_wants_path = dstdir.join("cron.target.wants");
        try!(create_dir_all(&cron_target_wants_path));

        // process command in case it should be put into script
        let command = if metadata(cmd).map(|m| m.is_file()).unwrap_or(false) {
            cmd.to_owned()
        } else {
            let script_command_path = dstdir.join(format!("cron-{}.sh", md5hex));

            debug!("generating script {:?} from {:?}", script_command_path, path);
            {
                let mut script_command_file = try!(File::create(&script_command_path));
                try!(writeln!(script_command_file, "#!{}", shell));
                try!(writeln!(script_command_file, "{}", cmd));
            }

            let mut perms = try!(metadata(&script_command_path)).permissions();
            perms.set_mode(0o755);
            try!(set_permissions(&script_command_path, perms));
            script_command_path.to_str().unwrap().to_owned()
        };

        debug!("generating service {:?} from {:?}", service_unit_path, path);
        {
            let mut service_unit_file = try!(File::create(service_unit_path));

            try!(writeln!(service_unit_file, r###"[Unit]
Description=[Cron] "{entry}"
Documentation=man:systemd-crontab-generator(8)
RefuseManualStart=true
RefuseManualStop=true
SourcePath={source_crontab_path}"###,
                entry = entry,
                source_crontab_path = path.display(),
                ));

            if env.contains_key("MAILTO") {
                try!(writeln!(service_unit_file, "OnFailure=cron-failure@%i.service"));
            }

            if user.uid != 0 {
                try!(writeln!(service_unit_file, "Requires=systemd-user-sessions.service"));
                if !user.home_dir.is_empty() {
                    try!(writeln!(service_unit_file, "RequiresMountsFor={}", user.home_dir));
                }
            }

            try!(writeln!(service_unit_file, r###"
[Service]
Type=oneshot
IgnoreSIGPIPE=false
ExecStart={command}"###,
                command = command,
                ));

            if schedule.is_some() && delay > 0 {
                try!(writeln!(service_unit_file, "ExecStartPre=-{}/{}/boot-delay {}", LIB_DIR, PACKAGE, delay));
            }

            if user.uid != 0 {
                try!(writeln!(service_unit_file, "User={}", user.name));
            }

            if let Some(group) = entry.group() {
                try!(writeln!(service_unit_file, "Group={}", group));
            }
            if batch {
                try!(writeln!(service_unit_file, "CPUSchedulingPolicy=idle"));
                try!(writeln!(service_unit_file, "IOSchedulingClass=idle"));
            }

            if !env.is_empty() {
                for (name, value) in env.iter() {
                    try!(writeln!(service_unit_file, r#"Environment="{}={}""#, name, value));
                }
            }
        }

        debug!("generating timer {:?} from {:?}", timer_unit_path, path);
        {
            let mut timer_unit_file = try!(File::create(&timer_unit_path));

            try!(writeln!(timer_unit_file, r###"[Unit]
Description=[Timer] "{entry}"
Documentation=man:systemd-crontab-generator(8)
PartOf=cron.target
RefuseManualStart=true
RefuseManualStop=true
SourcePath={source_crontab_path}

[Timer]
Unit={service_unit_name}"###,
                entry = entry,
                source_crontab_path = path.display(),
                service_unit_name = service_unit_name,
                ));

            if cfg![feature="persistent"] {
                try!(writeln!(timer_unit_file, "Persistent={}", persistent));
            }

            if let Some(schedule) = schedule {
                try!(writeln!(timer_unit_file, "OnCalendar={}", schedule));
            } else {
                try!(writeln!(timer_unit_file, "OnBootSec={}m", delay));
            }

            if random_delay != 1 {
                try!(writeln!(timer_unit_file, "AccuracySec={}m", random_delay));
            }
        }
        try!(symlink(timer_unit_path, cron_target_wants_path.join(timer_unit_name)));
    }

    Ok(())
}

fn linearize<T, C>(input: &[Interval<T>], star: &str, conv: C) -> String where T: Limited, C: Fn(&T) -> String {
    if input.len() == 1 && input[0] == Interval::Full(1) {
        star.to_owned()
    } else {
        let mut output = String::new();
        for part in input.iter().flat_map(|v| v.iter()).collect::<BTreeSet<_>>().iter() {
            output.push_str(&*conv(&part));
            output.push(',');
        }
        output.pop();
        output
    }
}

fn tohex(input: &[u8]) -> String {
    #[inline]
    fn hex(d: u8) -> char {
        match d {
            0...9 => (d + 0x30) as char,
            10...15 => (d + 0x57) as char,
            _ => unreachable!("unexpected value: {}", d)
        }
    }

    let mut buf = String::with_capacity(32);
    for b in input.into_iter() {
        buf.push(hex(b >> 4));
        buf.push(hex(b & 0xf));
    }
    buf
}

<|endoftext|>