<commit_before>use disassembler::Reg;

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum ILOperand {
    Value(i32),
    Register(Reg),
    Argument(i32),
    Local(i32),
    Pointer(Reg, Reg, u8, u32),
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct BinaryInstruction<Op: Clone> {
    pub left: Op,
    pub right: Op,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct UnaryInstruction<Op> {
    pub operand: Op,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct CopyInstruction<Op> {
    pub dst: Op,
    pub src: Op,
    pub stride: Op,
    pub count: Op,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum BranchType {
    Equal,
    NotEqual,
    Less,
    LessOrEqual,
    GreaterOrEqual,
    Greater,
    Unconditional,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct BranchInstruction<Op: Clone> {
    pub type_: BranchType,
    pub condition: Option<BinaryInstruction<Op>>,
    pub target: u64,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum ILBinaryOperator {
    Add,
    And,
    Divide,
    Multiply,
    LoadAddress,
    Or,
    ShiftLeft,
    ShiftRight,
    Subtract,
    Xor,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum ILUnaryOperator {
    Negate,
    Not,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum ILInstruction<Op: Clone> {
    Binary(ILBinaryOperator, BinaryInstruction<Op>),
    Unary(ILUnaryOperator, UnaryInstruction<Op>),
    Assign(BinaryInstruction<Op>),
    Copy(CopyInstruction<Op>),
    Branch(BranchInstruction<Op>),
    Call(UnaryInstruction<Op>),
    Return(UnaryInstruction<Op>), // TODO: remove data
    Continue,
    Break,
}

pub fn unary<Op>(operand: Op) -> UnaryInstruction<Op> {
    UnaryInstruction { operand }
}

pub fn binary<Op: Clone>(left: Op, right: Op) -> BinaryInstruction<Op> {
    BinaryInstruction { left, right }
}

pub fn copy<Op: Clone>(dst: Op, src: Op, stride: Op, count: Op) -> CopyInstruction<Op> {
    CopyInstruction {
        dst,
        src,
        stride,
        count,
    }
}

pub fn branch<Op: Clone>(
    type_: BranchType,
    condition: Option<BinaryInstruction<Op>>,
    target: u64,
) -> BranchInstruction<Op> {
    BranchInstruction {
        type_,
        condition,
        target,
    }
}

impl ILInstruction<ILOperand> {
    pub fn print_syntax(&self) -> String {
        let mut res = String::new();
        match self {
            ILInstruction::Binary(op, binary) => {
                res += Self::print_binary_operator(op);
                res += " ";
                res += &Self::print_operand(&binary.left);
                res += ", ";
                res += &Self::print_operand(&binary.right);
            }
            ILInstruction::Unary(op, unary) => {
                res += Self::print_unary_operator(op);
                res += " ";
                res += &Self::print_operand(&unary.operand);
            }
            ILInstruction::Assign(binary) => {
                res += &Self::print_operand(&binary.left);
                res += " := ";
                res += &Self::print_operand(&binary.right);
            }
            ILInstruction::Copy(copy) => {
                res += "copy (";
                res += &Self::print_operand(&copy.stride);
                res += " * ";
                res += &Self::print_operand(&copy.count);
                res += ") bytes from ";
                res += &Self::print_operand(&copy.src);
                res += " to ";
                res += &Self::print_operand(&copy.dst);
            }
            ILInstruction::Branch(branch) => {
                res += &Self::print_branch(branch);
            }
            ILInstruction::Call(unary) => {
                res += "call ";
                res += &Self::print_operand(&unary.operand);
            }
            ILInstruction::Return(unary) => {
                res += "ret ";
                res += &Self::print_operand(&unary.operand);
            }
            ILInstruction::Continue => {
                res += "continue";
            }
            ILInstruction::Break => {
                res += "break";
            }
        }
        res
    }

    fn print_binary_operator(op: &ILBinaryOperator) -> &'static str {
        use self::ILBinaryOperator::*;
        match op {
            Add => "add",
            And => "and",
            Divide => "div",
            Multiply => "mul",
            LoadAddress => "lea",
            Or => "or",
            ShiftLeft => "shl",
            ShiftRight => "shr",
            Subtract => "sub",
            Xor => "xor",
        }
    }

    fn print_unary_operator(op: &ILUnaryOperator) -> &'static str {
        use self::ILUnaryOperator::*;
        match op {
            Negate => "neg",
            Not => "not",
        }
    }

    fn print_branch_type(type_: &BranchType) -> &'static str {
        use self::BranchType::*;
        match type_ {
            Equal => "==",
            NotEqual => "!=",
            Less => "<",
            LessOrEqual => "<=",
            GreaterOrEqual => ">=",
            Greater => ">",
            Unconditional => panic!("Can't print unconditional branch type"),
        }
    }

    fn print_branch(br: &BranchInstruction<ILOperand>) -> String {
        let mut res = String::new();
        if br.type_ == BranchType::Unconditional {
            res += "jmp ";
            res += &br.target.to_string();
        } else {
            res += "br ";
            res += &br.target.to_string();
            res += " if ";
            if let Some(condition) = &br.condition {
                res += &Self::print_operand(&condition.left);
                res += " ";
                res += Self::print_branch_type(&br.type_);
                res += " ";
                res += &Self::print_operand(&condition.right);
            } else {
                panic!("Invalid branch instruction")
            }
        }
        res
    }

    fn print_operand(op: &ILOperand) -> String {
        let mut res = String::new();
        use self::ILOperand::*;
        match op {
            Value(v) => return v.to_string(),
            Register(r) => return String::from(r.to_str()),
            Argument(v) => {
                res += "arg(";
                res += &v.to_string();
                res += ")";
            }
            Local(v) => {
                res += "loc(";
                res += &v.to_string();
                res += ")";
            }
            &Pointer(b, i, s, o) => {
                res += "ptr(";
                if b != Reg::NONE {
                    res += b.to_str();
                    res += " + ";
                }
                if i != Reg::NONE && s != 0 {
                    res += i.to_str();
                    res += " * ";
                    res += &s.to_string();
                    res += " + ";
                }
                res += &o.to_string();
                res += ")";
            }
        }
        res
    }
}
<commit_msg>Pring most IL numbers in hex<commit_after>use disassembler::Reg;

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum ILOperand {
    Value(i32),
    Register(Reg),
    Argument(i32),
    Local(i32),
    Pointer(Reg, Reg, u8, u32),
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct BinaryInstruction<Op: Clone> {
    pub left: Op,
    pub right: Op,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct UnaryInstruction<Op> {
    pub operand: Op,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct CopyInstruction<Op> {
    pub dst: Op,
    pub src: Op,
    pub stride: Op,
    pub count: Op,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum BranchType {
    Equal,
    NotEqual,
    Less,
    LessOrEqual,
    GreaterOrEqual,
    Greater,
    Unconditional,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct BranchInstruction<Op: Clone> {
    pub type_: BranchType,
    pub condition: Option<BinaryInstruction<Op>>,
    pub target: u64,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum ILBinaryOperator {
    Add,
    And,
    Divide,
    Multiply,
    LoadAddress,
    Or,
    ShiftLeft,
    ShiftRight,
    Subtract,
    Xor,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum ILUnaryOperator {
    Negate,
    Not,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum ILInstruction<Op: Clone> {
    Binary(ILBinaryOperator, BinaryInstruction<Op>),
    Unary(ILUnaryOperator, UnaryInstruction<Op>),
    Assign(BinaryInstruction<Op>),
    Copy(CopyInstruction<Op>),
    Branch(BranchInstruction<Op>),
    Call(UnaryInstruction<Op>),
    Return(UnaryInstruction<Op>), // TODO: remove data
    Continue,
    Break,
}

pub fn unary<Op>(operand: Op) -> UnaryInstruction<Op> {
    UnaryInstruction { operand }
}

pub fn binary<Op: Clone>(left: Op, right: Op) -> BinaryInstruction<Op> {
    BinaryInstruction { left, right }
}

pub fn copy<Op: Clone>(dst: Op, src: Op, stride: Op, count: Op) -> CopyInstruction<Op> {
    CopyInstruction {
        dst,
        src,
        stride,
        count,
    }
}

pub fn branch<Op: Clone>(
    type_: BranchType,
    condition: Option<BinaryInstruction<Op>>,
    target: u64,
) -> BranchInstruction<Op> {
    BranchInstruction {
        type_,
        condition,
        target,
    }
}

impl ILInstruction<ILOperand> {
    pub fn print_syntax(&self) -> String {
        let mut res = String::new();
        match self {
            ILInstruction::Binary(op, binary) => {
                res += Self::print_binary_operator(op);
                res += " ";
                res += &Self::print_operand(&binary.left);
                res += ", ";
                res += &Self::print_operand(&binary.right);
            }
            ILInstruction::Unary(op, unary) => {
                res += Self::print_unary_operator(op);
                res += " ";
                res += &Self::print_operand(&unary.operand);
            }
            ILInstruction::Assign(binary) => {
                res += &Self::print_operand(&binary.left);
                res += " := ";
                res += &Self::print_operand(&binary.right);
            }
            ILInstruction::Copy(copy) => {
                res += "copy (";
                res += &Self::print_operand(&copy.stride);
                res += " * ";
                res += &Self::print_operand(&copy.count);
                res += ") bytes from ";
                res += &Self::print_operand(&copy.src);
                res += " to ";
                res += &Self::print_operand(&copy.dst);
            }
            ILInstruction::Branch(branch) => {
                res += &Self::print_branch(branch);
            }
            ILInstruction::Call(unary) => {
                res += "call ";
                res += &Self::print_operand(&unary.operand);
            }
            ILInstruction::Return(unary) => {
                res += "ret ";
                res += &Self::print_operand(&unary.operand);
            }
            ILInstruction::Continue => {
                res += "continue";
            }
            ILInstruction::Break => {
                res += "break";
            }
        }
        res
    }

    fn print_binary_operator(op: &ILBinaryOperator) -> &'static str {
        use self::ILBinaryOperator::*;
        match op {
            Add => "add",
            And => "and",
            Divide => "div",
            Multiply => "mul",
            LoadAddress => "lea",
            Or => "or",
            ShiftLeft => "shl",
            ShiftRight => "shr",
            Subtract => "sub",
            Xor => "xor",
        }
    }

    fn print_unary_operator(op: &ILUnaryOperator) -> &'static str {
        use self::ILUnaryOperator::*;
        match op {
            Negate => "neg",
            Not => "not",
        }
    }

    fn print_branch_type(type_: &BranchType) -> &'static str {
        use self::BranchType::*;
        match type_ {
            Equal => "==",
            NotEqual => "!=",
            Less => "<",
            LessOrEqual => "<=",
            GreaterOrEqual => ">=",
            Greater => ">",
            Unconditional => panic!("Can't print unconditional branch type"),
        }
    }

    fn print_branch(br: &BranchInstruction<ILOperand>) -> String {
        let mut res = String::new();
        if br.type_ == BranchType::Unconditional {
            res += "jmp ";
            res += &format!("0x{:x}", br.target);
        } else {
            res += "br ";
            res += &format!("0x{:x}", br.target);
            res += " if ";
            if let Some(condition) = &br.condition {
                res += &Self::print_operand(&condition.left);
                res += " ";
                res += Self::print_branch_type(&br.type_);
                res += " ";
                res += &Self::print_operand(&condition.right);
            } else {
                panic!("Invalid branch instruction")
            }
        }
        res
    }

    fn print_operand(op: &ILOperand) -> String {
        let mut res = String::new();
        use self::ILOperand::*;
        match op {
            Value(v) => return format!("0x{:x}", v),
            Register(r) => return String::from(r.to_str()),
            Argument(v) => {
                res += "arg(";
                res += &format!("0x{:x}", v);
                res += ")";
            }
            Local(v) => {
                res += "loc(";
                res += &format!("0x{:x}", -v);
                res += ")";
            }
            &Pointer(b, i, s, o) => {
                res += "ptr(";
                if b != Reg::NONE {
                    res += b.to_str();
                    res += " + ";
                }
                if i != Reg::NONE && s != 0 {
                    res += i.to_str();
                    res += " * ";
                    res += &s.to_string();
                    res += " + ";
                }
                res += &format!("0x{:x}", o);
                res += ")";
            }
        }
        res
    }
}
<|endoftext|>


<commit_before>extern crate clap;

use std::env;
use std::fs;
use std::path::Path;

use clap::ArgMatches;
use tempdir::TempDir;
use hyper::Client;
use util;
use extractor;
use downloader;
use profile;
use config::Config;

pub fn init() {
    let config = Config::new();
    if config.install_dir.exists() || config.shim_dir.exists() {
        println!("Already initalized. Reinitializing....");
    }
    fs::create_dir_all(&config.install_dir).expect("Could not create installation directory.");
    fs::create_dir_all(&config.shim_dir).expect("Could not create shims directory.");
    if !env::home_dir()
        .unwrap()
        .join("Documents")
        .join("WindowsPowerShell")
        .join("profile.ps1")
        .exists() {
        println!(r#"Please create profile.ps1 the following place:

$Env:USERPROFILE\Documents\WindowsPowerShell\profile.ps1

And write the following thing:

. $Env:USERPROFILE\.groonga\shims\bin\source-groonga.ps1
"#)
    }
}

pub fn install(m: &ArgMatches) {
    const BASE_URL: &'static str = "http://packages.groonga.org/windows/groonga";
    let config = Config::from_matches(m);
    println!("Value for architecture: {}",
             config.arch.clone().expect("unsupported platform"));
    println!("Obtaining Groonga version: {}",
             config.version.clone().unwrap());
    let groonga_dir = format!("groonga-{}-{}",
                              config.version.unwrap(),
                              config.arch.unwrap());
    let groonga_binary = format!("{}.zip", groonga_dir.clone());
    if config.versions_dir.join(groonga_dir.clone()).exists() {
        println!("Already installed. Ready to use it.");
        return ();
    }

    let download_dir = TempDir::new("grnenv-rs")
        .expect("Could not create temp dir.")
        .into_path();

    let client = Client::new();
    let filename = downloader::file_download(&client,
                                             &*format!("{}/{}", BASE_URL, groonga_binary),
                                             download_dir)
        .expect("Failed to download");
    extractor::extract_zip(&filename, &config.versions_dir);
}

pub fn switch(m: &ArgMatches) {
    let config = Config::from_matches(m);
    println!("Value for architecture: {}",
             config.arch.clone().expect("unsupported platform"));
    println!("Using Groonga version: {}", config.version.clone().unwrap());
    let groonga_dir = format!("groonga-{}-{}",
                              config.version.unwrap(),
                              config.arch.unwrap());
    match config.version {
        Some("system") => {
            profile::remove_grnenv_profile(&config.shim_dir).unwrap();
            return ();
        }
        Some(_) => {
            profile::create_profile_source(&config.shim_dir, &groonga_dir, &config.versions_dir)
                .expect("Could not create source-groonga.ps1")
        }
        None => unreachable!(),
    }
}

pub fn versions() {
    let groonga_versioned_dir = util::obtain_groonga_versioned_path();
    let paths = fs::read_dir(&Path::new(&groonga_versioned_dir)).unwrap();

    let names = paths.filter_map(|entry| {
            entry.ok().and_then(|e| {
                e.path()
                    .file_name()
                    .and_then(|n| n.to_str().map(|s| String::from(s)))
            })
        })
        .collect::<Vec<String>>();

    println!("Installed Groonga:");
    println!("\tsystem");
    for entry in names {
        println!("\t{}", entry);
    }
}
<commit_msg>Remove needless extern crate directive<commit_after>use std::env;
use std::fs;
use std::path::Path;

use clap::ArgMatches;
use tempdir::TempDir;
use hyper::Client;
use util;
use extractor;
use downloader;
use profile;
use config::Config;

pub fn init() {
    let config = Config::new();
    if config.install_dir.exists() || config.shim_dir.exists() {
        println!("Already initalized. Reinitializing....");
    }
    fs::create_dir_all(&config.install_dir).expect("Could not create installation directory.");
    fs::create_dir_all(&config.shim_dir).expect("Could not create shims directory.");
    if !env::home_dir()
        .unwrap()
        .join("Documents")
        .join("WindowsPowerShell")
        .join("profile.ps1")
        .exists() {
        println!(r#"Please create profile.ps1 the following place:

$Env:USERPROFILE\Documents\WindowsPowerShell\profile.ps1

And write the following thing:

. $Env:USERPROFILE\.groonga\shims\bin\source-groonga.ps1
"#)
    }
}

pub fn install(m: &ArgMatches) {
    const BASE_URL: &'static str = "http://packages.groonga.org/windows/groonga";
    let config = Config::from_matches(m);
    println!("Value for architecture: {}",
             config.arch.clone().expect("unsupported platform"));
    println!("Obtaining Groonga version: {}",
             config.version.clone().unwrap());
    let groonga_dir = format!("groonga-{}-{}",
                              config.version.unwrap(),
                              config.arch.unwrap());
    let groonga_binary = format!("{}.zip", groonga_dir.clone());
    if config.versions_dir.join(groonga_dir.clone()).exists() {
        println!("Already installed. Ready to use it.");
        return ();
    }

    let download_dir = TempDir::new("grnenv-rs")
        .expect("Could not create temp dir.")
        .into_path();

    let client = Client::new();
    let filename = downloader::file_download(&client,
                                             &*format!("{}/{}", BASE_URL, groonga_binary),
                                             download_dir)
        .expect("Failed to download");
    extractor::extract_zip(&filename, &config.versions_dir);
}

pub fn switch(m: &ArgMatches) {
    let config = Config::from_matches(m);
    println!("Value for architecture: {}",
             config.arch.clone().expect("unsupported platform"));
    println!("Using Groonga version: {}", config.version.clone().unwrap());
    let groonga_dir = format!("groonga-{}-{}",
                              config.version.unwrap(),
                              config.arch.unwrap());
    match config.version {
        Some("system") => {
            profile::remove_grnenv_profile(&config.shim_dir).unwrap();
            return ();
        }
        Some(_) => {
            profile::create_profile_source(&config.shim_dir, &groonga_dir, &config.versions_dir)
                .expect("Could not create source-groonga.ps1")
        }
        None => unreachable!(),
    }
}

pub fn versions() {
    let groonga_versioned_dir = util::obtain_groonga_versioned_path();
    let paths = fs::read_dir(&Path::new(&groonga_versioned_dir)).unwrap();

    let names = paths.filter_map(|entry| {
            entry.ok().and_then(|e| {
                e.path()
                    .file_name()
                    .and_then(|n| n.to_str().map(|s| String::from(s)))
            })
        })
        .collect::<Vec<String>>();

    println!("Installed Groonga:");
    println!("\tsystem");
    for entry in names {
        println!("\t{}", entry);
    }
}
<|endoftext|>


<commit_before>use nom::multispace;
use nom::{Err, ErrorKind, IResult, Needed};
use std::str;

use select::{limit_clause, nested_selection, order_clause, LimitClause, OrderClause,
             SelectStatement};

#[derive(Clone, Debug, Hash, PartialEq, Deserialize, Serialize)]
pub enum CompoundOperation {
    Union,
    DistinctUnion,
    Intersect,
    Except,
}

#[derive(Clone, Debug, Hash, PartialEq, Deserialize, Serialize)]
pub struct CompoundSelectStatement {
    pub selects: Vec<(Option<CompoundOperation>, SelectStatement)>,
    pub order: Option<OrderClause>,
    pub limit: Option<LimitClause>,
}

/// Parse compound operator
named!(compound_op<&[u8], CompoundOperation>,
    alt_complete!(
          chain!(
              caseless_tag!("union") ~
              distinct: opt!(
                  preceded!(multispace,
                            alt_complete!(  map!(caseless_tag!("all"), |_| { false })
                                          | map!(caseless_tag!("distinct"), |_| { true }))
                            )),
              || {
                  match distinct {
                      // DISTINCT is the default in both MySQL and SQLite
                      None => CompoundOperation::DistinctUnion,
                      Some(d) => {
                          if d {
                              CompoundOperation::DistinctUnion
                          } else {
                              CompoundOperation::Union
                          }
                      },
                  }
              }
          )
        | map!(caseless_tag!("intersect"), |_| CompoundOperation::Intersect)
        | map!(caseless_tag!("except"), |_| CompoundOperation::Except)
    )
);

/// Parse compound selection
named!(pub compound_selection<&[u8], CompoundSelectStatement>,
    complete!(chain!(
        first_select: nested_selection ~
        other_selects: many0!(
            complete!(
                chain!(multispace? ~
                       op: compound_op ~
                       multispace ~
                       select: nested_selection ~
                       || {
                           (Some(op), select)
                       }
                )
            )
        ) ~
        multispace? ~
        order: order_clause? ~
        limit: limit_clause?,
        || {
            let mut v = vec![(None, first_select)];
            v.extend(other_selects);

            CompoundSelectStatement {
                selects: v,
                order: order,
                limit: limit,
            }
        }
    ))
);

#[cfg(test)]
mod tests {
    use super::*;
    use column::Column;
    use common::FieldExpression;
    use table::Table;

    #[test]
    fn union() {
        let qstr = "SELECT id, 1 FROM Vote UNION SELECT id, stars from Rating;";
        let res = compound_selection(qstr.as_bytes());

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldExpression::Col(Column::from("id")),
                FieldExpression::Literal(1.into()),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldExpression::Col(Column::from("id")),
                FieldExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundOperation::DistinctUnion), second_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
    }

    #[test]
    fn multi_union() {
        let qstr = "SELECT id, 1 FROM Vote \
                    UNION SELECT id, stars from Rating \
                    UNION DISTINCT SELECT 42, 5 FROM Vote;";
        let res = compound_selection(qstr.as_bytes());

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldExpression::Col(Column::from("id")),
                FieldExpression::Literal(1.into()),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldExpression::Col(Column::from("id")),
                FieldExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let third_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldExpression::Literal(42.into()),
                FieldExpression::Literal(5.into()),
            ],
            ..Default::default()
        };

        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundOperation::DistinctUnion), second_select),
                (Some(CompoundOperation::DistinctUnion), third_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
    }

    #[test]
    fn union_all() {
        let qstr = "SELECT id, 1 FROM Vote UNION ALL SELECT id, stars from Rating;";
        let res = compound_selection(qstr.as_bytes());

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldExpression::Col(Column::from("id")),
                FieldExpression::Literal(1.into()),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldExpression::Col(Column::from("id")),
                FieldExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundOperation::Union), second_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
    }
}
<commit_msg>Avoid subsuming simple into compound selections<commit_after>use nom::multispace;
use nom::{Err, ErrorKind, IResult, Needed};
use std::str;

use select::{limit_clause, nested_selection, order_clause, LimitClause, OrderClause,
             SelectStatement};

#[derive(Clone, Debug, Hash, PartialEq, Deserialize, Serialize)]
pub enum CompoundOperation {
    Union,
    DistinctUnion,
    Intersect,
    Except,
}

#[derive(Clone, Debug, Hash, PartialEq, Deserialize, Serialize)]
pub struct CompoundSelectStatement {
    pub selects: Vec<(Option<CompoundOperation>, SelectStatement)>,
    pub order: Option<OrderClause>,
    pub limit: Option<LimitClause>,
}

/// Parse compound operator
named!(compound_op<&[u8], CompoundOperation>,
    alt_complete!(
          chain!(
              caseless_tag!("union") ~
              distinct: opt!(
                  preceded!(multispace,
                            alt_complete!(  map!(caseless_tag!("all"), |_| { false })
                                          | map!(caseless_tag!("distinct"), |_| { true }))
                            )),
              || {
                  match distinct {
                      // DISTINCT is the default in both MySQL and SQLite
                      None => CompoundOperation::DistinctUnion,
                      Some(d) => {
                          if d {
                              CompoundOperation::DistinctUnion
                          } else {
                              CompoundOperation::Union
                          }
                      },
                  }
              }
          )
        | map!(caseless_tag!("intersect"), |_| CompoundOperation::Intersect)
        | map!(caseless_tag!("except"), |_| CompoundOperation::Except)
    )
);

/// Parse compound selection
named!(pub compound_selection<&[u8], CompoundSelectStatement>,
    complete!(chain!(
        first_select: nested_selection ~
        other_selects: many1!(
            complete!(
                chain!(multispace? ~
                       op: compound_op ~
                       multispace ~
                       select: nested_selection ~
                       || {
                           (Some(op), select)
                       }
                )
            )
        ) ~
        multispace? ~
        order: order_clause? ~
        limit: limit_clause?,
        || {
            let mut v = vec![(None, first_select)];
            v.extend(other_selects);

            CompoundSelectStatement {
                selects: v,
                order: order,
                limit: limit,
            }
        }
    ))
);

#[cfg(test)]
mod tests {
    use super::*;
    use column::Column;
    use common::FieldExpression;
    use table::Table;

    #[test]
    fn union() {
        let qstr = "SELECT id, 1 FROM Vote UNION SELECT id, stars from Rating;";
        let res = compound_selection(qstr.as_bytes());

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldExpression::Col(Column::from("id")),
                FieldExpression::Literal(1.into()),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldExpression::Col(Column::from("id")),
                FieldExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundOperation::DistinctUnion), second_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
    }

    #[test]
    fn multi_union() {
        let qstr = "SELECT id, 1 FROM Vote \
                    UNION SELECT id, stars from Rating \
                    UNION DISTINCT SELECT 42, 5 FROM Vote;";
        let res = compound_selection(qstr.as_bytes());

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldExpression::Col(Column::from("id")),
                FieldExpression::Literal(1.into()),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldExpression::Col(Column::from("id")),
                FieldExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let third_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldExpression::Literal(42.into()),
                FieldExpression::Literal(5.into()),
            ],
            ..Default::default()
        };

        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundOperation::DistinctUnion), second_select),
                (Some(CompoundOperation::DistinctUnion), third_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
    }

    #[test]
    fn union_all() {
        let qstr = "SELECT id, 1 FROM Vote UNION ALL SELECT id, stars from Rating;";
        let res = compound_selection(qstr.as_bytes());

        let first_select = SelectStatement {
            tables: vec![Table::from("Vote")],
            fields: vec![
                FieldExpression::Col(Column::from("id")),
                FieldExpression::Literal(1.into()),
            ],
            ..Default::default()
        };
        let second_select = SelectStatement {
            tables: vec![Table::from("Rating")],
            fields: vec![
                FieldExpression::Col(Column::from("id")),
                FieldExpression::Col(Column::from("stars")),
            ],
            ..Default::default()
        };
        let expected = CompoundSelectStatement {
            selects: vec![
                (None, first_select),
                (Some(CompoundOperation::Union), second_select),
            ],
            order: None,
            limit: None,
        };

        assert_eq!(res.unwrap().1, expected);
    }
}
<|endoftext|>


<commit_before>use std::str;
use std::sync::RwLock;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::collections::BTreeMap;

use rocksdb::{self, DB};
use kite::{Term, TermRef};
use kite::query::term_selector::TermSelector;

use key_builder::KeyBuilder;

/// Manages the index's "term dictionary"
///
/// Because terms can be very long, we don't use their byte-representations as
/// keys. We generate a unique number for each one to use instead.
///
/// The term dictionary is a mapping between terms and their internal IDs
/// (aka. TermRef). It is entirely held in memory and persisted to the disk.
pub struct TermDictionaryManager {
    next_term_ref: AtomicUsize,
    terms: RwLock<BTreeMap<Vec<u8>, TermRef>>,
}

impl TermDictionaryManager {
    /// Generates a new term dictionary
    pub fn new(db: &DB) -> Result<TermDictionaryManager, rocksdb::Error> {
        // TODO: Raise error if .next_term_ref already exists
        // Next term ref
        try!(db.put(b".next_term_ref", b"1"));

        Ok(TermDictionaryManager {
            next_term_ref: AtomicUsize::new(1),
            terms: RwLock::new(BTreeMap::new()),
        })
    }

    /// Loads the term dictionary from an index
    pub fn open(db: &DB) -> Result<TermDictionaryManager, rocksdb::Error> {
        let next_term_ref = match try!(db.get(b".next_term_ref")) {
            Some(next_term_ref) => {
                next_term_ref.to_utf8().unwrap().parse::<u32>().unwrap()
            }
            None => 1,  // TODO: error
        };

        // Read dictionary
        let mut terms = BTreeMap::new();
        let mut iter = db.iterator();
        iter.seek(b"t");
        while iter.next() {
            let k = iter.key().unwrap();

            if k[0] != b't' {
                break;
            }

            let term_ref = TermRef::new(str::from_utf8(&iter.value().unwrap()).unwrap().parse::<u32>().unwrap());
            terms.insert(k[1..].to_vec(), term_ref);
        }

        Ok(TermDictionaryManager {
            next_term_ref: AtomicUsize::new(next_term_ref as usize),
            terms: RwLock::new(terms),
        })
    }

    /// Retrieves the TermRef for the given term
    pub fn get(&self, term_bytes: &Vec<u8>) -> Option<TermRef> {
        self.terms.read().unwrap().get(term_bytes).cloned()
    }

    /// Iterates over terms in the dictionary which match the selector
    pub fn select(&self, term_selector: &TermSelector) -> Vec<TermRef> {
        self.terms.read().unwrap().iter()
            .filter(|&(term, _term_ref)| {
                term_selector.matches_bytes(term)
            })
            .map(|(_term, term_ref)| *term_ref)
            .collect()
    }

    /// Retrieves the TermRef for the given term, adding the term to the
    /// dictionary if it doesn't exist
    pub fn get_or_create(&self, db: &DB, term: &Term) -> Result<TermRef, rocksdb::Error> {
        let term_bytes = term.to_bytes();

        if let Some(term_ref) = self.get(&term_bytes) {
            return Ok(term_ref);
        }

        // Term doesn't exist in the term dictionary

        // Increment next_term_ref
        let next_term_ref = self.next_term_ref.fetch_add(1, Ordering::SeqCst) as u32;
        try!(db.put(b".next_term_ref", (next_term_ref + 1).to_string().as_bytes()));

        // Create term ref
        let term_ref = TermRef::new(next_term_ref);

        // Get exclusive lock to term dictionary
        let mut terms = self.terms.write().unwrap();

        // It's possible that another thread has written the term to the dictionary
        // since we checked earlier. If this is the case, We should forget about
        // writing our TermRef and use the one that has been inserted already.
        if let Some(term_ref) = terms.get(&term_bytes) {
            return Ok(*term_ref);
        }

        // Write it to the on-disk term dictionary
        let kb = KeyBuilder::term_dict_mapping(&term_bytes);
        try!(db.put(kb.key(), next_term_ref.to_string().as_bytes()));

        // Write it to the term dictionary
        terms.insert(term_bytes, term_ref);

        Ok(term_ref)
    }
}
<commit_msg>Add second write lock to term dictionary<commit_after>use std::str;
use std::sync::{Mutex, RwLock};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::collections::BTreeMap;

use rocksdb::{self, DB};
use kite::{Term, TermRef};
use kite::query::term_selector::TermSelector;

use key_builder::KeyBuilder;

/// Manages the index's "term dictionary"
///
/// Because terms can be very long, we don't use their byte-representations as
/// keys. We generate a unique number for each one to use instead.
///
/// The term dictionary is a mapping between terms and their internal IDs
/// (aka. TermRef). It is entirely held in memory and persisted to the disk.
pub struct TermDictionaryManager {
    next_term_ref: AtomicUsize,
    terms: RwLock<BTreeMap<Vec<u8>, TermRef>>,
    write_lock: Mutex<i32>,
}

impl TermDictionaryManager {
    /// Generates a new term dictionary
    pub fn new(db: &DB) -> Result<TermDictionaryManager, rocksdb::Error> {
        // TODO: Raise error if .next_term_ref already exists
        // Next term ref
        try!(db.put(b".next_term_ref", b"1"));

        Ok(TermDictionaryManager {
            next_term_ref: AtomicUsize::new(1),
            terms: RwLock::new(BTreeMap::new()),
            write_lock: Mutex::new(0),
        })
    }

    /// Loads the term dictionary from an index
    pub fn open(db: &DB) -> Result<TermDictionaryManager, rocksdb::Error> {
        let next_term_ref = match try!(db.get(b".next_term_ref")) {
            Some(next_term_ref) => {
                next_term_ref.to_utf8().unwrap().parse::<u32>().unwrap()
            }
            None => 1,  // TODO: error
        };

        // Read dictionary
        let mut terms = BTreeMap::new();
        let mut iter = db.iterator();
        iter.seek(b"t");
        while iter.next() {
            let k = iter.key().unwrap();

            if k[0] != b't' {
                break;
            }

            let term_ref = TermRef::new(str::from_utf8(&iter.value().unwrap()).unwrap().parse::<u32>().unwrap());
            terms.insert(k[1..].to_vec(), term_ref);
        }

        Ok(TermDictionaryManager {
            next_term_ref: AtomicUsize::new(next_term_ref as usize),
            terms: RwLock::new(terms),
            write_lock: Mutex::new(0),
        })
    }

    /// Retrieves the TermRef for the given term
    pub fn get(&self, term_bytes: &Vec<u8>) -> Option<TermRef> {
        self.terms.read().unwrap().get(term_bytes).cloned()
    }

    /// Iterates over terms in the dictionary which match the selector
    pub fn select(&self, term_selector: &TermSelector) -> Vec<TermRef> {
        self.terms.read().unwrap().iter()
            .filter(|&(term, _term_ref)| {
                term_selector.matches_bytes(term)
            })
            .map(|(_term, term_ref)| *term_ref)
            .collect()
    }

    /// Retrieves the TermRef for the given term, adding the term to the
    /// dictionary if it doesn't exist
    pub fn get_or_create(&self, db: &DB, term: &Term) -> Result<TermRef, rocksdb::Error> {
        let term_bytes = term.to_bytes();

        if let Some(term_ref) = self.get(&term_bytes) {
            return Ok(term_ref);
        }

        // Term doesn't exist in the term dictionary

        // Increment next_term_ref
        let next_term_ref = self.next_term_ref.fetch_add(1, Ordering::SeqCst) as u32;
        try!(db.put(b".next_term_ref", (next_term_ref + 1).to_string().as_bytes()));

        // Create term ref
        let term_ref = TermRef::new(next_term_ref);

        // Get write lock
        // Note: We have a separate lock so we don't need to keep an exclusive
        // lock on the in-memory term dictionary while writing to disk, as this
        // blocks readers.
        let _guard = self.write_lock.lock().unwrap();

        // It's possible that another thread has written the term to the dictionary
        // since we checked earlier. If this is the case, We should forget about
        // writing our TermRef and use the one that has been inserted already.
        if let Some(term_ref) = self.terms.read().unwrap().get(&term_bytes) {
            return Ok(*term_ref);
        }

        // Write it to the on-disk term dictionary
        let kb = KeyBuilder::term_dict_mapping(&term_bytes);
        try!(db.put(kb.key(), next_term_ref.to_string().as_bytes()));

        // Write it to the term dictionary
        self.terms.write().unwrap().insert(term_bytes, term_ref);;

        Ok(term_ref)
    }
}
<|endoftext|>


<commit_before>use il;

pub fn gen(globals: Vec<il::Global>) {
    for g in globals.iter() {
        match *g {
            il::Global::TypedefVar(ref v) => {
                println!("pub type {} = {};", v.name, v.dst);
            },
            il::Global::StructVar(ref v) => {
                println!("#[repr(C)]");
                println!("pub struct {} {{", v.name);
                if v.fields.len() == 0 {
                    println!("    _dummy: (),");
                }
                for f in v.fields.iter() {
                    print!("    ");
                    if f.public {
                        print!("pub ");
                    }
                    println!("{}: {},", f.name, f.ty);
                }
                println!("}}");
                println!("new!({})", v.name);
            },
            il::Global::ConstantVar(ref v) => {
                println!("pub const {}: {} = {};", v.name, v.ty, v.val);
            },
        }
    }
}
<commit_msg>Fix: Add semicolon after new!()<commit_after>use il;

pub fn gen(globals: Vec<il::Global>) {
    for g in globals.iter() {
        match *g {
            il::Global::TypedefVar(ref v) => {
                println!("pub type {} = {};", v.name, v.dst);
            },
            il::Global::StructVar(ref v) => {
                println!("#[repr(C)]");
                println!("pub struct {} {{", v.name);
                if v.fields.len() == 0 {
                    println!("    _dummy: (),");
                }
                for f in v.fields.iter() {
                    print!("    ");
                    if f.public {
                        print!("pub ");
                    }
                    println!("{}: {},", f.name, f.ty);
                }
                println!("}}");
                println!("new!({});", v.name);
            },
            il::Global::ConstantVar(ref v) => {
                println!("pub const {}: {} = {};", v.name, v.ty, v.val);
            },
        }
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.
// spell-checker:ignore numberparse argtype
//! Errors returned by seq.
use std::error::Error;
use std::fmt::Display;

use uucore::display::Quotable;
use uucore::error::UError;

use crate::numberparse::ParseNumberError;

#[derive(Debug)]
pub enum SeqError {
    /// An error parsing the input arguments.
    ///
    /// The parameters are the [`String`] argument as read from the
    /// command line and the underlying parsing error itself.
    ParseError(String, ParseNumberError),

    /// The increment argument was zero, which is not allowed.
    ///
    /// The parameter is the increment argument as a [`String`] as read
    /// from the command line.
    ZeroIncrement(String),
}

impl SeqError {
    /// The [`String`] argument as read from the command-line.
    fn arg(&self) -> &str {
        match self {
            SeqError::ParseError(s, _) => s,
            SeqError::ZeroIncrement(s) => s,
        }
    }

    /// The type of argument that is causing the error.
    fn argtype(&self) -> &str {
        match self {
            SeqError::ParseError(_, e) => match e {
                ParseNumberError::Float => "floating point argument",
                ParseNumberError::Nan => "'not-a-number' argument",
                ParseNumberError::Hex => "hexadecimal argument",
            },
            SeqError::ZeroIncrement(_) => "Zero increment value",
        }
    }
}
impl UError for SeqError {
    /// Always return 1.
    fn code(&self) -> i32 {
        1
    }
}

impl Error for SeqError {}

impl Display for SeqError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "invalid {}: {}\nTry '{} --help' for more information.",
            self.argtype(),
            self.arg().quote(),
            uucore::execution_phrase(),
        )
    }
}
<commit_msg>seq: use usage error where appropriate<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.
// spell-checker:ignore numberparse argtype
//! Errors returned by seq.
use std::error::Error;
use std::fmt::Display;

use uucore::display::Quotable;
use uucore::error::UError;

use crate::numberparse::ParseNumberError;

#[derive(Debug)]
pub enum SeqError {
    /// An error parsing the input arguments.
    ///
    /// The parameters are the [`String`] argument as read from the
    /// command line and the underlying parsing error itself.
    ParseError(String, ParseNumberError),

    /// The increment argument was zero, which is not allowed.
    ///
    /// The parameter is the increment argument as a [`String`] as read
    /// from the command line.
    ZeroIncrement(String),
}

impl SeqError {
    /// The [`String`] argument as read from the command-line.
    fn arg(&self) -> &str {
        match self {
            Self::ParseError(s, _) => s,
            Self::ZeroIncrement(s) => s,
        }
    }

    /// The type of argument that is causing the error.
    fn argtype(&self) -> &str {
        match self {
            Self::ParseError(_, e) => match e {
                ParseNumberError::Float => "floating point argument",
                ParseNumberError::Nan => "'not-a-number' argument",
                ParseNumberError::Hex => "hexadecimal argument",
            },
            Self::ZeroIncrement(_) => "Zero increment value",
        }
    }
}
impl UError for SeqError {
    /// Always return 1.
    fn code(&self) -> i32 {
        1
    }

    fn usage(&self) -> bool {
        true
    }
}

impl Error for SeqError {}

impl Display for SeqError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "invalid {}: {}", self.argtype(), self.arg().quote())
    }
}
<|endoftext|>


<commit_before>extern crate app_units;
extern crate webrender;
extern crate glutin;
extern crate gleam;
extern crate webrender_traits;
extern crate euclid;

use euclid::{Size2D, Point2D, Rect, Matrix4D};
use gleam::gl;
use std::path::PathBuf;
use std::ffi::CStr;
use webrender_traits::{PipelineId, ServoStackingContextId, StackingContextId, DisplayListId};
use webrender_traits::{AuxiliaryListsBuilder, Epoch, ColorF, FragmentType, GlyphInstance};
use webrender_traits::RendererKind;
use std::fs::File;
use std::io::Read;
use std::env;

fn _load_file(name: &str) -> Vec<u8> {
    let mut file = File::open(name).unwrap();
    let mut buffer = vec![];
    file.read_to_end(&mut buffer).unwrap();
    buffer
}

struct Notifier {
    window_proxy: glutin::WindowProxy,
}

impl Notifier {
    fn new(window_proxy: glutin::WindowProxy) -> Notifier {
        Notifier {
            window_proxy: window_proxy,
        }
    }
}

pub struct WebRenderFrameBuilder {
    pub stacking_contexts: Vec<(StackingContextId, webrender_traits::StackingContext)>,
    pub display_lists: Vec<(DisplayListId, webrender_traits::BuiltDisplayList)>,
    pub auxiliary_lists_builder: AuxiliaryListsBuilder,
    pub root_pipeline_id: PipelineId,
    pub next_scroll_layer_id: usize,
}

impl WebRenderFrameBuilder {
    pub fn new(root_pipeline_id: PipelineId) -> WebRenderFrameBuilder {
        WebRenderFrameBuilder {
            stacking_contexts: vec![],
            display_lists: vec![],
            auxiliary_lists_builder: AuxiliaryListsBuilder::new(),
            root_pipeline_id: root_pipeline_id,
            next_scroll_layer_id: 0,
        }
    }

    pub fn add_stacking_context(&mut self,
                                api: &mut webrender_traits::RenderApi,
                                pipeline_id: PipelineId,
                                stacking_context: webrender_traits::StackingContext)
                                -> StackingContextId {
        assert!(pipeline_id == self.root_pipeline_id);
        let id = api.next_stacking_context_id();
        self.stacking_contexts.push((id, stacking_context));
        id
    }

    pub fn add_display_list(&mut self,
                            api: &mut webrender_traits::RenderApi,
                            display_list: webrender_traits::BuiltDisplayList,
                            stacking_context: &mut webrender_traits::StackingContext)
                            -> DisplayListId {
        let id = api.next_display_list_id();
        stacking_context.has_stacking_contexts = stacking_context.has_stacking_contexts ||
                                                 display_list.descriptor().has_stacking_contexts;
        stacking_context.display_lists.push(id);
        self.display_lists.push((id, display_list));
        id
    }

    pub fn next_scroll_layer_id(&mut self) -> webrender_traits::ScrollLayerId {
        let scroll_layer_id = self.next_scroll_layer_id;
        self.next_scroll_layer_id += 1;
        webrender_traits::ScrollLayerId::new(self.root_pipeline_id, scroll_layer_id)
    }

}

impl webrender_traits::RenderNotifier for Notifier {
    fn new_frame_ready(&mut self) {
        self.window_proxy.wakeup_event_loop();
    }

    fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
        self.window_proxy.wakeup_event_loop();
    }

    fn pipeline_size_changed(&mut self,
                             _: PipelineId,
                             _: Option<Size2D<f32>>) {
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        println!("{} <shader path>", args[0]);
        return;
    }

    let res_path = &args[1];

    let window = glutin::WindowBuilder::new()
                .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
                .build()
                .unwrap();

    unsafe {
        window.make_current().ok();
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
        gl::clear_color(0.3, 0.0, 0.0, 1.0);
    }

    let version = unsafe {
        let data = CStr::from_ptr(gl::GetString(gl::VERSION) as *const _).to_bytes().to_vec();
        String::from_utf8(data).unwrap()
    };

    println!("OpenGL version {}", version);
    println!("Shader resource path: {}", res_path);

    let (width, height) = window.get_inner_size().unwrap();

    let opts = webrender::RendererOptions {
        device_pixel_ratio: 1.0,
        resource_path: PathBuf::from(res_path),
        enable_aa: false,
        enable_msaa: false,
        enable_profiler: false,
        enable_recording: false,
        enable_scrollbars: false,
        debug: true,
        precache_shaders: false,
        renderer_kind: RendererKind::Native,
    };

    let (mut renderer, sender) = webrender::renderer::Renderer::new(opts);
    let mut api = sender.create_api();

//     let font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf";
//     let font_bytes = load_file(font_path);
//     let font_key = api.add_raw_font(font_bytes);

    let notifier = Box::new(Notifier::new(window.create_window_proxy()));
    renderer.set_render_notifier(notifier);

    let pipeline_id = PipelineId(0, 0);
    let epoch = Epoch(0);
    let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);

    let mut frame_builder = WebRenderFrameBuilder::new(pipeline_id);
    let root_scroll_layer_id = frame_builder.next_scroll_layer_id();

    let bounds = Rect::new(Point2D::new(0.0, 0.0), Size2D::new(width as f32, height as f32));

    let servo_id = ServoStackingContextId(FragmentType::FragmentBody, 0);
    let mut sc =
        webrender_traits::StackingContext::new(servo_id,
                                               Some(root_scroll_layer_id),
                                               webrender_traits::ScrollPolicy::Scrollable,
                                               bounds,
                                               bounds,
                                               0,
                                               &Matrix4D::identity(),
                                               &Matrix4D::identity(),
                                               true,
                                               webrender_traits::MixBlendMode::Normal,
                                               Vec::new(),
                                               &mut frame_builder.auxiliary_lists_builder);

    let mut builder = webrender_traits::DisplayListBuilder::new();

    let clip_region = webrender_traits::ClipRegion::new(&bounds,
                                                        Vec::new(),
                                                        &mut frame_builder.auxiliary_lists_builder);

    builder.push_rect(Rect::new(Point2D::new(100.0, 100.0), Size2D::new(100.0, 100.0)),
                      clip_region,
                      ColorF::new(0.0, 1.0, 0.0, 1.0));

    let _text_bounds = Rect::new(Point2D::new(100.0, 200.0), Size2D::new(700.0, 300.0));

    let _glyphs = vec![
        GlyphInstance {
            index: 48,
            x: 100.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 68,
            x: 150.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 80,
            x: 200.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 82,
            x: 250.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 81,
            x: 300.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 3,
            x: 350.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 86,
            x: 400.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 79,
            x: 450.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 72,
            x: 500.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 83,
            x: 550.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 87,
            x: 600.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 17,
            x: 650.0,
            y: 100.0,
        },
    ];

//     builder.push_text(text_bounds,
//                       clip_region,
//                       glyphs,
//                       font_key,
//                       ColorF::new(1.0, 1.0, 0.0, 1.0),
//                       Au::from_px(32),
//                       Au::from_px(0),
//                       &mut frame_builder.auxiliary_lists_builder);

    frame_builder.add_display_list(&mut api, builder.finalize(), &mut sc);
    let sc_id = frame_builder.add_stacking_context(&mut api, pipeline_id, sc);

    api.set_root_stacking_context(sc_id,
                                  root_background_color,
                                  epoch,
                                  pipeline_id,
                                  Size2D::new(width as f32, height as f32),
                                  frame_builder.stacking_contexts,
                                  frame_builder.display_lists,
                                  frame_builder.auxiliary_lists_builder
                                               .finalize());

    api.set_root_pipeline(pipeline_id);

    for event in window.wait_events() {
        gl::clear(gl::COLOR_BUFFER_BIT);
        renderer.update();

        renderer.render(Size2D::new(width, height));

        window.swap_buffers().ok();

        match event {
            glutin::Event::Closed => break,
            glutin::Event::KeyboardInput(_element_state, scan_code, _virtual_key_code) => {
                if scan_code == 9 {
                    break;
                }
            }
            _ => ()
        }
    }
}
<commit_msg>[sample] Merge pull request #5 from kvark/image_mask<commit_after>extern crate app_units;
extern crate webrender;
extern crate glutin;
extern crate gleam;
extern crate webrender_traits;
extern crate euclid;

use euclid::{Size2D, Point2D, Rect, Matrix4D};
use gleam::gl;
use std::path::PathBuf;
use std::ffi::CStr;
use webrender_traits::{PipelineId, ServoStackingContextId, StackingContextId, DisplayListId};
use webrender_traits::{AuxiliaryListsBuilder, Epoch, ColorF, FragmentType, GlyphInstance};
use webrender_traits::{ImageFormat, RendererKind};
use std::fs::File;
use std::io::Read;
use std::env;

fn _load_file(name: &str) -> Vec<u8> {
    let mut file = File::open(name).unwrap();
    let mut buffer = vec![];
    file.read_to_end(&mut buffer).unwrap();
    buffer
}

struct Notifier {
    window_proxy: glutin::WindowProxy,
}

impl Notifier {
    fn new(window_proxy: glutin::WindowProxy) -> Notifier {
        Notifier {
            window_proxy: window_proxy,
        }
    }
}

pub struct WebRenderFrameBuilder {
    pub stacking_contexts: Vec<(StackingContextId, webrender_traits::StackingContext)>,
    pub display_lists: Vec<(DisplayListId, webrender_traits::BuiltDisplayList)>,
    pub auxiliary_lists_builder: AuxiliaryListsBuilder,
    pub root_pipeline_id: PipelineId,
    pub next_scroll_layer_id: usize,
}

impl WebRenderFrameBuilder {
    pub fn new(root_pipeline_id: PipelineId) -> WebRenderFrameBuilder {
        WebRenderFrameBuilder {
            stacking_contexts: vec![],
            display_lists: vec![],
            auxiliary_lists_builder: AuxiliaryListsBuilder::new(),
            root_pipeline_id: root_pipeline_id,
            next_scroll_layer_id: 0,
        }
    }

    pub fn add_stacking_context(&mut self,
                                api: &mut webrender_traits::RenderApi,
                                pipeline_id: PipelineId,
                                stacking_context: webrender_traits::StackingContext)
                                -> StackingContextId {
        assert!(pipeline_id == self.root_pipeline_id);
        let id = api.next_stacking_context_id();
        self.stacking_contexts.push((id, stacking_context));
        id
    }

    pub fn add_display_list(&mut self,
                            api: &mut webrender_traits::RenderApi,
                            display_list: webrender_traits::BuiltDisplayList,
                            stacking_context: &mut webrender_traits::StackingContext)
                            -> DisplayListId {
        let id = api.next_display_list_id();
        stacking_context.has_stacking_contexts = stacking_context.has_stacking_contexts ||
                                                 display_list.descriptor().has_stacking_contexts;
        stacking_context.display_lists.push(id);
        self.display_lists.push((id, display_list));
        id
    }

    pub fn next_scroll_layer_id(&mut self) -> webrender_traits::ScrollLayerId {
        let scroll_layer_id = self.next_scroll_layer_id;
        self.next_scroll_layer_id += 1;
        webrender_traits::ScrollLayerId::new(self.root_pipeline_id, scroll_layer_id)
    }

}

impl webrender_traits::RenderNotifier for Notifier {
    fn new_frame_ready(&mut self) {
        self.window_proxy.wakeup_event_loop();
    }

    fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
        self.window_proxy.wakeup_event_loop();
    }

    fn pipeline_size_changed(&mut self,
                             _: PipelineId,
                             _: Option<Size2D<f32>>) {
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() != 2 {
        println!("{} <shader path>", args[0]);
        return;
    }

    let res_path = &args[1];

    let window = glutin::WindowBuilder::new()
                .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
                .build()
                .unwrap();

    unsafe {
        window.make_current().ok();
        gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
        gl::clear_color(0.3, 0.0, 0.0, 1.0);
    }

    let version = unsafe {
        let data = CStr::from_ptr(gl::GetString(gl::VERSION) as *const _).to_bytes().to_vec();
        String::from_utf8(data).unwrap()
    };

    println!("OpenGL version {}", version);
    println!("Shader resource path: {}", res_path);

    let (width, height) = window.get_inner_size().unwrap();

    let opts = webrender::RendererOptions {
        device_pixel_ratio: 1.0,
        resource_path: PathBuf::from(res_path),
        enable_aa: false,
        enable_msaa: false,
        enable_profiler: false,
        enable_recording: false,
        enable_scrollbars: false,
        debug: true,
        precache_shaders: false,
        renderer_kind: RendererKind::Native,
    };

    let (mut renderer, sender) = webrender::renderer::Renderer::new(opts);
    let mut api = sender.create_api();

//     let font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf";
//     let font_bytes = load_file(font_path);
//     let font_key = api.add_raw_font(font_bytes);

    let notifier = Box::new(Notifier::new(window.create_window_proxy()));
    renderer.set_render_notifier(notifier);

    let pipeline_id = PipelineId(0, 0);
    let epoch = Epoch(0);
    let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);

    let mut frame_builder = WebRenderFrameBuilder::new(pipeline_id);
    let root_scroll_layer_id = frame_builder.next_scroll_layer_id();

    let bounds = Rect::new(Point2D::new(0.0, 0.0), Size2D::new(width as f32, height as f32));

    let servo_id = ServoStackingContextId(FragmentType::FragmentBody, 0);
    let mut sc =
        webrender_traits::StackingContext::new(servo_id,
                                               Some(root_scroll_layer_id),
                                               webrender_traits::ScrollPolicy::Scrollable,
                                               bounds,
                                               bounds,
                                               0,
                                               &Matrix4D::identity(),
                                               &Matrix4D::identity(),
                                               true,
                                               webrender_traits::MixBlendMode::Normal,
                                               Vec::new(),
                                               &mut frame_builder.auxiliary_lists_builder);

    let mut builder = webrender_traits::DisplayListBuilder::new();

    let clip_region = {
        let rect = Rect::new(Point2D::new(100.0, 100.0), Size2D::new(100.0, 100.0));
        let mask = webrender_traits::ImageMask {
            image: api.add_image(2, 2, ImageFormat::A8, vec![0,80, 180, 255]),
            rect: rect,
            repeat: false,
        };
        let radius = webrender_traits::BorderRadius::uniform(20.0);
        let complex = webrender_traits::ComplexClipRegion::new(rect, radius);

        webrender_traits::ClipRegion::new(&bounds,
                                          vec![complex],
                                          Some(mask),
                                          &mut frame_builder.auxiliary_lists_builder)
    };

    builder.push_rect(Rect::new(Point2D::new(100.0, 100.0), Size2D::new(100.0, 100.0)),
                      clip_region,
                      ColorF::new(0.0, 1.0, 0.0, 1.0));

    let _text_bounds = Rect::new(Point2D::new(100.0, 200.0), Size2D::new(700.0, 300.0));

    let _glyphs = vec![
        GlyphInstance {
            index: 48,
            x: 100.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 68,
            x: 150.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 80,
            x: 200.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 82,
            x: 250.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 81,
            x: 300.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 3,
            x: 350.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 86,
            x: 400.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 79,
            x: 450.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 72,
            x: 500.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 83,
            x: 550.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 87,
            x: 600.0,
            y: 100.0,
        },
        GlyphInstance {
            index: 17,
            x: 650.0,
            y: 100.0,
        },
    ];

//     builder.push_text(text_bounds,
//                       clip_region,
//                       glyphs,
//                       font_key,
//                       ColorF::new(1.0, 1.0, 0.0, 1.0),
//                       Au::from_px(32),
//                       Au::from_px(0),
//                       &mut frame_builder.auxiliary_lists_builder);

    frame_builder.add_display_list(&mut api, builder.finalize(), &mut sc);
    let sc_id = frame_builder.add_stacking_context(&mut api, pipeline_id, sc);

    api.set_root_stacking_context(sc_id,
                                  root_background_color,
                                  epoch,
                                  pipeline_id,
                                  Size2D::new(width as f32, height as f32),
                                  frame_builder.stacking_contexts,
                                  frame_builder.display_lists,
                                  frame_builder.auxiliary_lists_builder
                                               .finalize());

    api.set_root_pipeline(pipeline_id);

    for event in window.wait_events() {
        gl::clear(gl::COLOR_BUFFER_BIT);
        renderer.update();

        renderer.render(Size2D::new(width, height));

        window.swap_buffers().ok();

        match event {
            glutin::Event::Closed => break,
            glutin::Event::KeyboardInput(_element_state, scan_code, _virtual_key_code) => {
                if scan_code == 9 {
                    break;
                }
            }
            _ => ()
        }
    }
}
<|endoftext|>


<commit_before>pub use self::connected::{Connected, AutocommitOff, AutocommitOn, AutocommitMode};
pub use self::hdbc_wrapper::HDbcWrapper;
pub use self::unconnected::Unconnected;
use super::*;
use sys::*;
use std::ops::DerefMut;

mod connected;
mod unconnected;
mod hdbc_wrapper;

/// A `DataSource` is used to query and manipulate a data source.
///
/// * The state of the connection
/// * The current connection-level diagnostics
/// * The handles of statements and descriptors currently allocated on the connection
/// * The current settings of each connection attribute
///
/// # States
///
/// A `DataSource` is in one of two states `Connected` or `Unconnected`. These are modeled in the
/// type at compile time. Every new `DataSource` starts out as `Unconnected`. To execute a query it
/// needs to be `Connected`. You can achieve this by calling e.g. `connect` and capture the result
/// in a new binding which will be of type `DataSource::<'env, Connected<'env>>`.
///
/// See [Connection Handles in the ODBC Reference][1]
/// [1]: https://docs.microsoft.com/sql/odbc/reference/develop-app/connection-handles
#[derive(Debug)]
pub struct DataSource<'env, S: HDbcWrapper<'env> = Unconnected<'env>> {
    /// Connection handle. Either `HDbc` for `Unconnected` or `Connected` for `Connected`.
    handle: S::Handle
}

impl<'env, Any> DataSource<'env, Any>
where
    Any: HDbcWrapper<'env>,
{
    /// Consumes the `DataSource`, returning the wrapped raw `SQLHDBC`
    ///
    /// Leaks the Connection Handle. This is usually done in order to pass ownership from Rust to
    /// another language. After calling this method, the caller is responsible for invoking
    /// `SQLFreeHandle`.
    pub fn into_raw(self) -> SQLHDBC {
        self.handle.into_hdbc().into_raw()
    }

    /// Provides access to the raw ODBC Connection Handle
    pub fn as_raw(&self) -> SQLHDBC {
        self.handle.as_raw()
    }

    /// May only be invoked with a valid Statement Handle which has been allocated using
    /// `SQLAllocHandle`. Special care must be taken that the Connection Handle passed is in a
    /// State which matches the type.
    pub unsafe fn from_raw(raw: SQLHDBC) -> Self {
        DataSource { handle: Any::from_hdbc(HDbc::from_raw(raw)) }
    }

    /// Express state transiton
    fn transit<Other: HDbcWrapper<'env>>(self) -> DataSource<'env, Other> {
        DataSource { handle: Other::from_hdbc(self.handle.into_hdbc()) }
    }
}

impl<'env> DataSource<'env, Unconnected<'env>> {
    /// Allocates a new `DataSource`. A `DataSource` may not outlive its parent `Environment`.
    ///
    /// See [Allocating a Connection Handle ODBC][1]
    /// [1]: https://docs.microsoft.com/sql/odbc/reference/develop-app/allocating-a-connection-handle-odbc
    pub fn with_parent<V>(parent: &'env Environment<V>) -> Return<Self>
    where
        V: Version,
    {
        HDbc::allocate(parent.as_henv()).map(|handle| {
            DataSource { handle: Unconnected::from_hdbc(handle) }
        })
    }

    /// Establishes connections to a driver and a data source. The connection handle references
    /// storage of all information about the connection to the data source, including status,
    /// transaction state, and error information.
    ///
    /// * See [Connecting with SQLConnect][1]
    /// * See [SQLConnectFunction][2]
    ///
    /// # State transition
    /// On success this method changes the Connection handles state from `Allocated` to `Connected`
    /// . Since this state change is expressed in the type system, the method consumes self. And
    /// returns a new instance in the result type.
    ///
    /// # Arguments
    ///
    /// * `data_source_name` - Data source name. The data might be located on the same computer as
    ///                        the program, or on another computer somewhere on a network.
    /// * `user` - User identifier.
    /// * `pwd` - Authenticatien string (typically the password).
    /// [1]: https://docs.microsoft.com/sql/odbc/reference/syntax/sqlconnect-function
    /// [2]: https://docs.microsoft.com/sql/odbc/reference/syntax/sqlconnect-function
    pub fn connect<DSN, U, P>(
        mut self,
        data_source_name: &DSN,
        user: &U,
        pwd: &P,
    ) -> Return<Connection<'env, AutocommitOn>, DataSource<'env, Unconnected<'env>>>
    where
        DSN: SqlStr + ?Sized,
        U: SqlStr + ?Sized,
        P: SqlStr + ?Sized,
    {
        match self.handle.connect(data_source_name, user, pwd) {
            Success(()) => Success(self.transit()),
            Info(()) => Info(self.transit()),
            Error(()) => Error(self.transit()),
        }
    }

    /// Connects to a data source using a connection string.
    ///
    /// For the syntax regarding the connections string see [SQLDriverConnect][1]. This method is
    /// equivalent of calling `odbc_sys::SQLDriverConnect` with the `SQL_DRIVER_NOPROMPT` parameter.
    ///
    /// See [Choosing a Data Source or Driver][2]
    /// [1]: https://docs.microsoft.com/sql/odbc/reference/syntax/sqldriverconnect-function
    /// [2]: https://docs.microsoft.com/sql/odbc/reference/develop-app/choosing-a-data-source-or-driver
    pub fn connect_with_connection_string<C>(
        mut self,
        connection_string: &C,
    ) -> Return<Connection<'env, AutocommitOn>, Self>
    where
        C: SqlStr + ?Sized,
    {
        // We do not care for now.
        let mut out_connection_string = [];
        match self.handle.driver_connect(
            connection_string,
            &mut out_connection_string,
            SQL_DRIVER_NOPROMPT,
        ) {
            Success(_) => Success(self.transit()),
            Info(_) => Info(self.transit()),
            Error(()) => Error(self.transit()),
        }
    }
}

impl<'env, AC: AutocommitMode> Connection<'env, AC> {
    /// Used by `Statement`s constructor
    pub(crate) fn as_hdbc(&self) -> &HDbc {
        &self.handle
    }

    /// When an application has finished using a data source, it calls `disconnect`. `disconnect`
    /// disconnects the driver from the data source.
    ///
    /// This will trigger implicit rollback if autocommit mode is off and current transaction was not committed nor rolled back.
    ///
    /// * See [Disconnecting from a Data Source or Driver][1]
    /// * See [SQLDisconnect Function][2]
    /// [1]: https://docs.microsoft.com/sql/odbc/reference/develop-app/disconnecting-from-a-data-source-or-driver
    /// [2]: https://docs.microsoft.com/sql/odbc/reference/syntax/sqldisconnect-function
    pub fn disconnect(mut self) -> Return<DataSource<'env, Unconnected<'env>>, Connection<'env, AC>> {
        match self.handle.rollback() {
            Success(()) | Info(()) => (),
            Error(()) => return Error(self.transit()),
        };

        match self.handle.disconnect() {
            Success(()) => Success(self.transit()),
            Info(()) => Info(self.transit()),
            Error(()) => Error(self.transit()),
        }
    }

    /// `true` if the data source is set to READ ONLY mode, `false` otherwise.
    pub fn is_read_only(&mut self) -> Return<bool> {
        self.handle.is_read_only()
    }
}

impl<'env> Connection<'env, AutocommitOff> {
    /// Set autocommit mode off, triggers implicit rollback of any running transaction
    pub fn enable_autocommit(mut self) -> Return<Connection<'env, AutocommitOn>, Self> {
        match self.handle.rollback() {
            Success(_) | Info(_) => {},
            Error(()) => return Error(self.transit()),
        };

        match self.handle.set_autocommit(true) {
            Success(_) => Success(self.transit()),
            Info(_) => Info(self.transit()),
            Error(()) => Error(self.transit()),
        }
    }

    /// Commit transaction if any, can be safely called and will be no-op if no transaction present or autocommit mode is enabled
    pub fn commit(&mut self) -> Return<()> {
        self.handle.commit()
    }

    /// Rollback transaction if any, can be safely called and will be no-op if no transaction present or autocommit mode is enabled
    pub fn rollback(&mut self) -> Return<()> {
       self.handle.rollback()
    }
}

impl<'env> Connection<'env, AutocommitOn> {
    /// Set autocommit mode off
    pub fn disable_autocommit(mut self) -> Return<Connection<'env, AutocommitOff>, Self> {
        match self.handle.set_autocommit(false) {
            Success(_) => Success(self.transit()),
            Info(_) => Info(self.transit()),
            Error(()) => Error(self.transit()),
        }
    }
}

impl<'env, S> Diagnostics for DataSource<'env, S>
where
    S: HDbcWrapper<'env>,
{
    fn diagnostics(
        &self,
        rec_number: SQLSMALLINT,
        message_text: &mut [SQLCHAR],
    ) -> ReturnOption<DiagResult> {
        self.handle.diagnostics(rec_number, message_text)
    }
}
<commit_msg>Fix doc<commit_after>pub use self::connected::{Connected, AutocommitOff, AutocommitOn, AutocommitMode};
pub use self::hdbc_wrapper::HDbcWrapper;
pub use self::unconnected::Unconnected;
use super::*;
use sys::*;
use std::ops::DerefMut;

mod connected;
mod unconnected;
mod hdbc_wrapper;

/// A `DataSource` is used to query and manipulate a data source.
///
/// * The state of the connection
/// * The current connection-level diagnostics
/// * The handles of statements and descriptors currently allocated on the connection
/// * The current settings of each connection attribute
///
/// # States
///
/// A `DataSource` is in one of two states `Connected` or `Unconnected`. These are modeled in the
/// type at compile time. Every new `DataSource` starts out as `Unconnected`. To execute a query it
/// needs to be `Connected`. You can achieve this by calling e.g. `connect` and capture the result
/// in a new binding which will be of type `DataSource::<'env, Connected<'env>>`.
///
/// See [Connection Handles in the ODBC Reference][1]
/// [1]: https://docs.microsoft.com/sql/odbc/reference/develop-app/connection-handles
#[derive(Debug)]
pub struct DataSource<'env, S: HDbcWrapper<'env> = Unconnected<'env>> {
    /// Connection handle. Either `HDbc` for `Unconnected` or `Connected` for `Connected`.
    handle: S::Handle
}

impl<'env, Any> DataSource<'env, Any>
where
    Any: HDbcWrapper<'env>,
{
    /// Consumes the `DataSource`, returning the wrapped raw `SQLHDBC`
    ///
    /// Leaks the Connection Handle. This is usually done in order to pass ownership from Rust to
    /// another language. After calling this method, the caller is responsible for invoking
    /// `SQLFreeHandle`.
    pub fn into_raw(self) -> SQLHDBC {
        self.handle.into_hdbc().into_raw()
    }

    /// Provides access to the raw ODBC Connection Handle
    pub fn as_raw(&self) -> SQLHDBC {
        self.handle.as_raw()
    }

    /// May only be invoked with a valid Statement Handle which has been allocated using
    /// `SQLAllocHandle`. Special care must be taken that the Connection Handle passed is in a
    /// State which matches the type.
    pub unsafe fn from_raw(raw: SQLHDBC) -> Self {
        DataSource { handle: Any::from_hdbc(HDbc::from_raw(raw)) }
    }

    /// Express state transiton
    fn transit<Other: HDbcWrapper<'env>>(self) -> DataSource<'env, Other> {
        DataSource { handle: Other::from_hdbc(self.handle.into_hdbc()) }
    }
}

impl<'env> DataSource<'env, Unconnected<'env>> {
    /// Allocates a new `DataSource`. A `DataSource` may not outlive its parent `Environment`.
    ///
    /// See [Allocating a Connection Handle ODBC][1]
    /// [1]: https://docs.microsoft.com/sql/odbc/reference/develop-app/allocating-a-connection-handle-odbc
    pub fn with_parent<V>(parent: &'env Environment<V>) -> Return<Self>
    where
        V: Version,
    {
        HDbc::allocate(parent.as_henv()).map(|handle| {
            DataSource { handle: Unconnected::from_hdbc(handle) }
        })
    }

    /// Establishes connections to a driver and a data source. The connection handle references
    /// storage of all information about the connection to the data source, including status,
    /// transaction state, and error information.
    ///
    /// * See [Connecting with SQLConnect][1]
    /// * See [SQLConnectFunction][2]
    ///
    /// # State transition
    /// On success this method changes the Connection handles state from `Allocated` to `Connected`
    /// . Since this state change is expressed in the type system, the method consumes self. And
    /// returns a new instance in the result type.
    ///
    /// # Arguments
    ///
    /// * `data_source_name` - Data source name. The data might be located on the same computer as
    ///                        the program, or on another computer somewhere on a network.
    /// * `user` - User identifier.
    /// * `pwd` - Authenticatien string (typically the password).
    /// [1]: https://docs.microsoft.com/sql/odbc/reference/syntax/sqlconnect-function
    /// [2]: https://docs.microsoft.com/sql/odbc/reference/syntax/sqlconnect-function
    pub fn connect<DSN, U, P>(
        mut self,
        data_source_name: &DSN,
        user: &U,
        pwd: &P,
    ) -> Return<Connection<'env, AutocommitOn>, DataSource<'env, Unconnected<'env>>>
    where
        DSN: SqlStr + ?Sized,
        U: SqlStr + ?Sized,
        P: SqlStr + ?Sized,
    {
        match self.handle.connect(data_source_name, user, pwd) {
            Success(()) => Success(self.transit()),
            Info(()) => Info(self.transit()),
            Error(()) => Error(self.transit()),
        }
    }

    /// Connects to a data source using a connection string.
    ///
    /// For the syntax regarding the connections string see [SQLDriverConnect][1]. This method is
    /// equivalent of calling `odbc_sys::SQLDriverConnect` with the `SQL_DRIVER_NOPROMPT` parameter.
    ///
    /// See [Choosing a Data Source or Driver][2]
    /// [1]: https://docs.microsoft.com/sql/odbc/reference/syntax/sqldriverconnect-function
    /// [2]: https://docs.microsoft.com/sql/odbc/reference/develop-app/choosing-a-data-source-or-driver
    pub fn connect_with_connection_string<C>(
        mut self,
        connection_string: &C,
    ) -> Return<Connection<'env, AutocommitOn>, Self>
    where
        C: SqlStr + ?Sized,
    {
        // We do not care for now.
        let mut out_connection_string = [];
        match self.handle.driver_connect(
            connection_string,
            &mut out_connection_string,
            SQL_DRIVER_NOPROMPT,
        ) {
            Success(_) => Success(self.transit()),
            Info(_) => Info(self.transit()),
            Error(()) => Error(self.transit()),
        }
    }
}

impl<'env, AC: AutocommitMode> Connection<'env, AC> {
    /// Used by `Statement`s constructor
    pub(crate) fn as_hdbc(&self) -> &HDbc {
        &self.handle
    }

    /// When an application has finished using a data source, it calls `disconnect`. `disconnect`
    /// disconnects the driver from the data source.
    ///
    /// This will trigger implicit rollback if autocommit mode is off and current transaction was not committed nor rolled back.
    ///
    /// * See [Disconnecting from a Data Source or Driver][1]
    /// * See [SQLDisconnect Function][2]
    /// [1]: https://docs.microsoft.com/sql/odbc/reference/develop-app/disconnecting-from-a-data-source-or-driver
    /// [2]: https://docs.microsoft.com/sql/odbc/reference/syntax/sqldisconnect-function
    pub fn disconnect(mut self) -> Return<DataSource<'env, Unconnected<'env>>, Connection<'env, AC>> {
        match self.handle.rollback() {
            Success(()) | Info(()) => (),
            Error(()) => return Error(self.transit()),
        };

        match self.handle.disconnect() {
            Success(()) => Success(self.transit()),
            Info(()) => Info(self.transit()),
            Error(()) => Error(self.transit()),
        }
    }

    /// `true` if the data source is set to READ ONLY mode, `false` otherwise.
    pub fn is_read_only(&mut self) -> Return<bool> {
        self.handle.is_read_only()
    }
}

impl<'env> Connection<'env, AutocommitOff> {
    /// Set autocommit mode on, triggers implicit rollback of any running transaction
    pub fn enable_autocommit(mut self) -> Return<Connection<'env, AutocommitOn>, Self> {
        match self.handle.rollback() {
            Success(_) | Info(_) => {},
            Error(()) => return Error(self.transit()),
        };

        match self.handle.set_autocommit(true) {
            Success(_) => Success(self.transit()),
            Info(_) => Info(self.transit()),
            Error(()) => Error(self.transit()),
        }
    }

    /// Commit transaction if any, can be safely called and will be no-op if no transaction present or autocommit mode is enabled
    pub fn commit(&mut self) -> Return<()> {
        self.handle.commit()
    }

    /// Rollback transaction if any, can be safely called and will be no-op if no transaction present or autocommit mode is enabled
    pub fn rollback(&mut self) -> Return<()> {
       self.handle.rollback()
    }
}

impl<'env> Connection<'env, AutocommitOn> {
    /// Set autocommit mode off
    pub fn disable_autocommit(mut self) -> Return<Connection<'env, AutocommitOff>, Self> {
        match self.handle.set_autocommit(false) {
            Success(_) => Success(self.transit()),
            Info(_) => Info(self.transit()),
            Error(()) => Error(self.transit()),
        }
    }
}

impl<'env, S> Diagnostics for DataSource<'env, S>
where
    S: HDbcWrapper<'env>,
{
    fn diagnostics(
        &self,
        rec_number: SQLSMALLINT,
        message_text: &mut [SQLCHAR],
    ) -> ReturnOption<DiagResult> {
        self.handle.diagnostics(rec_number, message_text)
    }
}
<|endoftext|>