<commit_before>use ram::cell::{Cell, CellHeader, ReadError, WriteError};
use ram::types::Id;
use server::NebServer;
use bifrost::rpc::*;

use futures_cpupool::{CpuPool};
use num_cpus;

pub static DEFAULT_SERVICE_ID: u64 = hash_ident!(NEB_CELL_RPC_SERVICE) as u64;

service! {
    rpc read_cell(key: Id) -> Cell | ReadError;
    rpc write_cell(cell: Cell) -> CellHeader | WriteError;
    rpc update_cell(cell: Cell) -> CellHeader | WriteError;
    rpc upsert_cell(cell: Cell) -> CellHeader | WriteError;
    rpc remove_cell(key: Id) -> () | WriteError;
}

pub struct NebRPCService {
    inner: Arc<NebRPCServiceInner>
}

pub struct NebRPCServiceInner {
    server: Arc<NebServer>,
    pool: CpuPool
}

impl Service for NebRPCService {
    fn read_cell(&self, key: Id) -> Box<Future<Item = Cell, Error = ReadError>> {
        NebRPCServiceInner::read_cell(self.inner.clone(), key)
    }
    fn write_cell(&self, mut cell: Cell) -> Box<Future<Item =CellHeader, Error = WriteError>> {
        NebRPCServiceInner::write_cell(self.inner.clone(), cell)
    }
    fn update_cell(&self, mut cell: Cell) -> Box<Future<Item =CellHeader, Error = WriteError>> {
        NebRPCServiceInner::update_cell(self.inner.clone(), cell)
    }
    fn upsert_cell(&self, mut cell: Cell) -> Box<Future<Item =CellHeader, Error = WriteError>> {
        NebRPCServiceInner::upsert_cell(self.inner.clone(), cell)
    }
    fn remove_cell(&self, key: Id) -> Box<Future<Item = (), Error = WriteError>> {
        NebRPCServiceInner::remove_cell(self.inner.clone(), key)
    }
}

impl NebRPCServiceInner {
    fn read_cell(this: Arc<Self>, key: Id)
        -> Box<Future<Item = Cell, Error = ReadError>>
    {
        box this.clone().pool.spawn_fn(move || this.server.chunks.read_cell(&key))
    }
    fn write_cell(this: Arc<Self>, mut cell: Cell)
        -> Box<Future<Item =CellHeader, Error = WriteError>>
    {
        box this.clone().pool.spawn_fn(move ||
            match this.server.chunks.write_cell(&mut cell) {
                Ok(header) => Ok(header),
                Err(e) => Err(e)
            }
        )
    }
    fn update_cell(this: Arc<Self>, mut cell: Cell)
        -> Box<Future<Item =CellHeader, Error = WriteError>>
    {
        box this.clone().pool.spawn_fn(move ||
            match this.server.chunks.update_cell(&mut cell) {
                Ok(header) => Ok(header),
                Err(e) => Err(e)
            }
        )
    }
    fn remove_cell(this: Arc<Self>, key: Id)
        -> Box<Future<Item = (), Error = WriteError>>
    {
        box this.clone().pool.spawn_fn(move ||this.server.chunks.remove_cell(&key))
    }
    fn upsert_cell(this: Arc<Self>, mut cell: Cell)
        -> Box<Future<Item =CellHeader, Error = WriteError>>
    {
        box this.clone().pool.spawn_fn(move ||
            match this.server.chunks.upsert_cell(&mut cell) {
                Ok(header) => Ok(header),
                Err(e) => Err(e)
            }
        )
    }
}

dispatch_rpc_service_functions!(NebRPCService);

impl NebRPCService {
    pub fn new(server: &Arc<NebServer>) -> Arc<NebRPCService> {
        Arc::new(NebRPCService {
            inner: Arc::new(NebRPCServiceInner {
                server: server.clone(),
                pool: CpuPool::new(4 * num_cpus::get())
            })
        })
    }
}<commit_msg>will not use cpu pool for neb service to avoid context switching<commit_after>use ram::cell::{Cell, CellHeader, ReadError, WriteError};
use ram::types::Id;
use server::NebServer;
use bifrost::rpc::*;

use futures::prelude::*;
use num_cpus;

pub static DEFAULT_SERVICE_ID: u64 = hash_ident!(NEB_CELL_RPC_SERVICE) as u64;

service! {
    rpc read_cell(key: Id) -> Cell | ReadError;
    rpc write_cell(cell: Cell) -> CellHeader | WriteError;
    rpc update_cell(cell: Cell) -> CellHeader | WriteError;
    rpc upsert_cell(cell: Cell) -> CellHeader | WriteError;
    rpc remove_cell(key: Id) -> () | WriteError;
}

pub struct NebRPCService {
    inner: Arc<NebRPCServiceInner>
}

pub struct NebRPCServiceInner {
    server: Arc<NebServer>
}

impl Service for NebRPCService {
    fn read_cell(&self, key: Id) -> Box<Future<Item = Cell, Error = ReadError>> {
        NebRPCServiceInner::read_cell(self.inner.clone(), key)
    }
    fn write_cell(&self, mut cell: Cell) -> Box<Future<Item =CellHeader, Error = WriteError>> {
        NebRPCServiceInner::write_cell(self.inner.clone(), cell)
    }
    fn update_cell(&self, mut cell: Cell) -> Box<Future<Item =CellHeader, Error = WriteError>> {
        NebRPCServiceInner::update_cell(self.inner.clone(), cell)
    }
    fn upsert_cell(&self, mut cell: Cell) -> Box<Future<Item =CellHeader, Error = WriteError>> {
        NebRPCServiceInner::upsert_cell(self.inner.clone(), cell)
    }
    fn remove_cell(&self, key: Id) -> Box<Future<Item = (), Error = WriteError>> {
        NebRPCServiceInner::remove_cell(self.inner.clone(), key)
    }
}

impl NebRPCServiceInner {
    fn read_cell(this: Arc<Self>, key: Id)
        -> Box<Future<Item = Cell, Error = ReadError>>
    {
        box future::result(this.server.chunks.read_cell(&key))
    }
    fn write_cell(this: Arc<Self>, mut cell: Cell)
        -> Box<Future<Item =CellHeader, Error = WriteError>>
    {
        box future::result(this.server.chunks.write_cell(&mut cell))
    }
    fn update_cell(this: Arc<Self>, mut cell: Cell)
        -> Box<Future<Item =CellHeader, Error = WriteError>>
    {
        box future::result(this.server.chunks.update_cell(&mut cell))
    }
    fn remove_cell(this: Arc<Self>, key: Id)
        -> Box<Future<Item = (), Error = WriteError>>
    {
        box future::result(this.server.chunks.remove_cell(&key))
    }
    fn upsert_cell(this: Arc<Self>, mut cell: Cell)
        -> Box<Future<Item =CellHeader, Error = WriteError>>
    {
        box future::result(this.server.chunks.upsert_cell(&mut cell))
    }
}

dispatch_rpc_service_functions!(NebRPCService);

impl NebRPCService {
    pub fn new(server: &Arc<NebServer>) -> Arc<NebRPCService> {
        Arc::new(NebRPCService {
            inner: Arc::new(NebRPCServiceInner {
                server: server.clone()
            })
        })
    }
}<|endoftext|>


<commit_before>use cargo::core::{Workspace, Source};
use cargo::sources::PathSource;
use syntex_syntax::attr;
use syntex_syntax::visit::{self, Visitor, FnKind};
use syntex_syntax::codemap::{CodeMap, Span, FilePathMapping};
use syntex_syntax::ast::{NodeId, Mac, Attribute, Stmt, StmtKind, FnDecl, Mod,
    StructField, Block, Item, ItemKind};
use syntex_syntax::parse::{self, ParseSess};
use syntex_syntax::errors::Handler;
use syntex_syntax::errors::emitter::ColorConfig;
use std::path::PathBuf;
use std::ffi::OsStr;
use std::rc::Rc;
use std::ops::Deref;
use config::Config;

struct IgnoredLines<'a> {
    lines: Vec<usize>,
    codemap: &'a CodeMap,
    config: &'a Config,
    started: bool,
}

/// Returns a list of files and line numbers to ignore (not indexes!)
pub fn get_lines_to_ignore(project: &Workspace, config: &Config) -> Vec<(PathBuf, usize)> {
    let mut result: Vec<(PathBuf, usize)> = Vec::new();

    let pkg = project.current().unwrap();
    let mut src = PathSource::new(pkg.root(), pkg.package_id().source_id(), project.config());
    // If this fails we should just iterate over no files. No need to care.
    let _ = src.update();

    let codemap = Rc::new(CodeMap::new(FilePathMapping::empty()));
    let handler = Handler::with_tty_emitter(ColorConfig::Auto, false, false, Some(codemap.clone()));
    let parse_session = ParseSess::with_span_handler(handler, codemap.clone());

    for file in src.list_files(&pkg).unwrap().iter() {
        if !(config.ignore_tests && file.starts_with(project.root().join("tests"))) {
            if file.extension() == Some(OsStr::new("rs")) {
                // Rust source file
                let mut parser = parse::new_parser_from_file(&parse_session, &file);
                if let Ok(krate) = parser.parse_crate_mod() {
                    let mut visitor = IgnoredLines::from_session(&parse_session, config);
                    visitor.visit_mod(&krate.module, krate.span, &krate.attrs, NodeId::new(0));
                    result.append(&mut visitor.lines.iter()
                                                    .map(|x| (file.to_path_buf(), *x))
                                                    .collect::<Vec<_>>());
                }
            }
        }
    }
    result
}

impl<'a> IgnoredLines<'a> {
    /// Construct a new ignored lines object for the given project
    fn from_session(session: &'a ParseSess, config: &'a Config) -> IgnoredLines<'a> {
        IgnoredLines {
            lines: vec![],
            codemap: session.codemap(),
            config: config,
            started: false
        }
    }

    fn ignore_lines(&mut self, span: Span) {
        if let Ok(s) = self.codemap.span_to_lines(span) {
            for line in &s.lines {
                // Line number is index+1
                self.lines.push(line.line_index + 1);
            }
        }
    }

}

impl<'v, 'a> Visitor<'v> for IgnoredLines<'a> {

    fn visit_item(&mut self, i: &'v Item) {
        match i.node {
            ItemKind::ExternCrate(..) => self.ignore_lines(i.span),
            ItemKind::Fn(_, _, _, _, _, ref block) => {
                if attr::contains_name(&i.attrs, "test") && self.config.ignore_tests {
                    self.ignore_lines(i.span);
                    self.ignore_lines(block.deref().span);
                }
            },
            _ => {},
        }
        visit::walk_item(self, i);
    }

    fn visit_mod(&mut self, m: &'v Mod, s: Span, _attrs: &[Attribute], _n: NodeId) {
        // We want to limit ourselves to only this source file.
        // This avoids repeated hits and issues where there are multiple compilation targets
        if self.started == false {
            self.started = true;
            visit::walk_mod(self, m);
        } else {
            // Needs to be more advanced - cope with mod { .. } in file.
            // Also if mod is cfg(test) and --ignore-tests ignore contents!
            if let Ok(fl) = self.codemap.span_to_lines(s) {
                if fl.lines.len() > 1 {
                    visit::walk_mod(self, m);
                } else {
                    // one line mod, so either referencing another file or something
                    // not worth covering.
                    self.ignore_lines(s);
                }
            }
        }
    }

    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, s: Span, _: NodeId) {
        visit::walk_fn(self, fk, fd, s);
    }

    fn visit_stmt(&mut self, s: &Stmt) {
        match s.node {
            StmtKind::Mac(_) => visit::walk_stmt(self, s),
            _ => {},
        }
    }

    fn visit_mac(&mut self, mac: &Mac) {
        // Use this to ignore unreachable lines
        let mac_text = &format!("{}", mac.node.path)[..];
        // TODO unimplemented should have extra logic to exclude the
        // function from coverage
        match mac_text {
            "unimplemented" => self.ignore_lines(mac.span),
            "unreachable" => self.ignore_lines(mac.span),
            _ => {},
        }
        visit::walk_mac(self, mac);
    }

    /// Ignores attributes which may get identified as coverable lines.
    fn visit_attribute(&mut self, attr: &Attribute) {
        if attr.check_name("derive") {
            self.ignore_lines(attr.span);
        }
    }

    /// Struct fields are mistakenly identified as instructions and uncoverable.
    fn visit_struct_field(&mut self, s: &'v StructField) {
        self.ignore_lines(s.span);
        visit::walk_struct_field(self, s);
    }

    fn visit_block(&mut self, b: &'v Block) {

        visit::walk_block(self, b);
    }
}

<commit_msg>Handle non-test functions in cfg(test) mod.<commit_after>use cargo::core::{Workspace, Source};
use cargo::sources::PathSource;
use syntex_syntax::attr;
use syntex_syntax::visit::{self, Visitor, FnKind};
use syntex_syntax::codemap::{CodeMap, Span, FilePathMapping};
use syntex_syntax::ast::{NodeId, Mac, Attribute, Stmt, StmtKind, FnDecl, Mod,
    StructField, Block, Item, ItemKind};
use syntex_syntax::parse::{self, ParseSess};
use syntex_syntax::errors::Handler;
use syntex_syntax::errors::emitter::ColorConfig;
use std::path::PathBuf;
use std::ffi::OsStr;
use std::rc::Rc;
use std::ops::Deref;
use config::Config;

struct IgnoredLines<'a> {
    lines: Vec<usize>,
    codemap: &'a CodeMap,
    config: &'a Config,
    started: bool,
}

/// Returns a list of files and line numbers to ignore (not indexes!)
pub fn get_lines_to_ignore(project: &Workspace, config: &Config) -> Vec<(PathBuf, usize)> {
    let mut result: Vec<(PathBuf, usize)> = Vec::new();

    let pkg = project.current().unwrap();
    let mut src = PathSource::new(pkg.root(), pkg.package_id().source_id(), project.config());
    // If this fails we should just iterate over no files. No need to care.
    let _ = src.update();

    let codemap = Rc::new(CodeMap::new(FilePathMapping::empty()));
    let handler = Handler::with_tty_emitter(ColorConfig::Auto, false, false, Some(codemap.clone()));
    let parse_session = ParseSess::with_span_handler(handler, codemap.clone());

    for file in src.list_files(&pkg).unwrap().iter() {
        if !(config.ignore_tests && file.starts_with(project.root().join("tests"))) {
            if file.extension() == Some(OsStr::new("rs")) {
                // Rust source file
                let mut parser = parse::new_parser_from_file(&parse_session, &file);
                if let Ok(krate) = parser.parse_crate_mod() {
                    let mut visitor = IgnoredLines::from_session(&parse_session, config);
                    visitor.visit_mod(&krate.module, krate.span, &krate.attrs, NodeId::new(0));
                    result.append(&mut visitor.lines.iter()
                                                    .map(|x| (file.to_path_buf(), *x))
                                                    .collect::<Vec<_>>());
                }
            }
        }
    }
    result
}

impl<'a> IgnoredLines<'a> {
    /// Construct a new ignored lines object for the given project
    fn from_session(session: &'a ParseSess, config: &'a Config) -> IgnoredLines<'a> {
        IgnoredLines {
            lines: vec![],
            codemap: session.codemap(),
            config: config,
            started: false
        }
    }

    fn ignore_lines(&mut self, span: Span) {
        if let Ok(s) = self.codemap.span_to_lines(span) {
            for line in &s.lines {
                // Line number is index+1
                self.lines.push(line.line_index + 1);
            }
        }
    }

    fn contains_cfg_test(&mut self, attrs: &[Attribute]) -> bool {
        let mut result = false;
        'outer: for attr in attrs.iter() {
            if attr.path == "cfg" {
                if let Some(items) = attr.meta_item_list() {
                    for item in items {
                        if let Some(word) = item.word() {
                            if word.name().as_str() == "test" {
                                result = true;
                                break 'outer;
                            }
                        }
                    }
                }
            }
        }
        result
    }

}

impl<'v, 'a> Visitor<'v> for IgnoredLines<'a> {

    fn visit_item(&mut self, i: &'v Item) {
        match i.node {
            ItemKind::ExternCrate(..) => self.ignore_lines(i.span),
            ItemKind::Fn(_, _, _, _, _, ref block) => {
                if attr::contains_name(&i.attrs, "test") && self.config.ignore_tests {
                    self.ignore_lines(i.span);
                    self.ignore_lines(block.deref().span);
                }
            },
            _ => {},
        }
        visit::walk_item(self, i);
    }

    fn visit_mod(&mut self, m: &'v Mod, s: Span, _attrs: &[Attribute], _n: NodeId) {
        // We want to limit ourselves to only this source file.
        // This avoids repeated hits and issues where there are multiple compilation targets
        if self.started == false {
            self.started = true;
            visit::walk_mod(self, m);
        } else {
            // Needs to be more advanced - cope with mod { .. } in file.
            // Also if mod is cfg(test) and --ignore-tests ignore contents!
            if let Ok(fl) = self.codemap.span_to_lines(s) {
                if fl.lines.len() > 1 {
                    if self.config.ignore_tests && self.contains_cfg_test(_attrs) {
                        self.ignore_lines(s);
                    }
                    visit::walk_mod(self, m);
                } else {
                    // one line mod, so either referencing another file or something
                    // not worth covering.
                    self.ignore_lines(s);
                }
            }
        }
    }

    fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, s: Span, _: NodeId) {
        visit::walk_fn(self, fk, fd, s);
    }

    fn visit_stmt(&mut self, s: &Stmt) {
        match s.node {
            StmtKind::Mac(_) => visit::walk_stmt(self, s),
            _ => {},
        }
    }

    fn visit_mac(&mut self, mac: &Mac) {
        // Use this to ignore unreachable lines
        let mac_text = &format!("{}", mac.node.path)[..];
        // TODO unimplemented should have extra logic to exclude the
        // function from coverage
        match mac_text {
            "unimplemented" => self.ignore_lines(mac.span),
            "unreachable" => self.ignore_lines(mac.span),
            _ => {},
        }
        visit::walk_mac(self, mac);
    }

    /// Ignores attributes which may get identified as coverable lines.
    fn visit_attribute(&mut self, attr: &Attribute) {
        if attr.check_name("derive") {
            self.ignore_lines(attr.span);
        }
    }

    /// Struct fields are mistakenly identified as instructions and uncoverable.
    fn visit_struct_field(&mut self, s: &'v StructField) {
        self.ignore_lines(s.span);
        visit::walk_struct_field(self, s);
    }

    fn visit_block(&mut self, b: &'v Block) {

        visit::walk_block(self, b);
    }
}

<|endoftext|>


<commit_before>use ffi;
use std::str::from_utf8;
use std::slice::from_raw_parts;
use std::mem::{size_of, transmute};
use std::ffi::CString;

pub unsafe trait OdbcType<'a>: Sized {
    fn sql_data_type() -> ffi::SqlDataType;
    fn c_data_type() -> ffi::SqlCDataType;
    fn convert(_: &'a [u8]) -> Self;
    fn column_size(&self) -> ffi::SQLULEN;
    fn value_ptr(&self) -> ffi::SQLPOINTER;
    fn decimal_digits(&self) -> ffi::SQLSMALLINT {
        0
    }
}

unsafe impl<'a> OdbcType<'a> for &'a[u8] {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_VARBINARY
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_BINARY
    }

    fn convert(buffer: &'a [u8]) -> Self {
        buffer
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for Vec<u8> {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_VARBINARY
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_BINARY
    }

    fn convert(buffer: &'a [u8]) -> Self {
        buffer.to_vec()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for &'a[u16] {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_WVARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_WCHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        unsafe { from_raw_parts(buffer.as_ptr() as *const u16, buffer.len() / 2) }
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for Vec<u16> {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_WVARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_WCHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        let buffer = unsafe { from_raw_parts(buffer.as_ptr() as *const u16, buffer.len() / 2) };
        buffer.to_vec()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for CString {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_VARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        CString::new(buffer).unwrap()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.as_bytes().len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_bytes().as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for String {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_VARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        from_utf8(buffer).unwrap().to_owned()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.as_bytes().len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_bytes().as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for &'a str {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_VARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        from_utf8(buffer).unwrap()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.as_bytes().len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_bytes().as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

fn convert_primitive<T>(buf: &[u8]) -> T
where
    T: Copy,
{
    unsafe { from_raw_parts(buf.as_ptr() as *const T, 1)[0] }
}

unsafe impl<'a> OdbcType<'a> for u8 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_SMALLINT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_UTINYINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for i8 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_SMALLINT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_STINYINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for i16 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_SMALLINT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SSHORT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for u16 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_SMALLINT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_USHORT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for i32 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_INTEGER
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SLONG
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for u32 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_INTEGER
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_ULONG
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for i64 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_INTEGER
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SBIGINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for u64 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_INTEGER
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_UBIGINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for f32 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_FLOAT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_FLOAT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for f64 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_DOUBLE
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_DOUBLE
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

pub type SqlDate = ffi::SQL_DATE_STRUCT;

unsafe impl<'a> OdbcType<'a> for SqlDate {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_DATE
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_DATE
    }

    fn convert(buffer: &'a [u8]) -> Self {
        assert_eq!(buffer.len(), size_of::<Self>());
        unsafe {
            let ptr = buffer.as_ptr() as *const [u8; size_of::<Self>()];
            transmute(*ptr)
        }
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

pub type SqlTime = ffi::SQL_TIME_STRUCT;

unsafe impl<'a> OdbcType<'a> for SqlTime {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_TIME
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_TIME
    }

    fn convert(buffer: &'a [u8]) -> Self {
        assert_eq!(buffer.len(), size_of::<Self>());
        unsafe {
            let ptr = buffer.as_ptr() as *const [u8; size_of::<Self>()];
            transmute(*ptr)
        }
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

pub type SqlTimestamp = ffi::SQL_TIMESTAMP_STRUCT;

unsafe impl<'a> OdbcType<'a> for SqlTimestamp {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_TIMESTAMP
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_TYPE_TIMESTAMP
    }

    fn convert(buffer: &'a [u8]) -> Self {
        assert_eq!(buffer.len(), size_of::<Self>());
        unsafe {
            let ptr = buffer.as_ptr() as *const [u8; size_of::<Self>()];
            transmute(*ptr)
        }
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

pub type SqlSsTime2 = ffi::SQL_SS_TIME2_STRUCT;

unsafe impl<'a> OdbcType<'a> for SqlSsTime2 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_VARBINARY
    }
    fn c_data_type() -> ffi::SqlCDataType {
        // NOTE: ODBC 3.5 and earlier
        ffi::SQL_C_BINARY
    }

    fn convert(buffer: &'a [u8]) -> Self {
        assert_eq!(buffer.len(), size_of::<Self>());
        unsafe {
            let ptr = buffer.as_ptr() as *const [u8; size_of::<Self>()];
            transmute(*ptr)
        }
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}<commit_msg>impl OdbcType for bool as SQL_C_BIT<commit_after>use ffi;
use std::str::from_utf8;
use std::slice::from_raw_parts;
use std::mem::{size_of, transmute};
use std::ffi::CString;

pub unsafe trait OdbcType<'a>: Sized {
    fn sql_data_type() -> ffi::SqlDataType;
    fn c_data_type() -> ffi::SqlCDataType;
    fn convert(_: &'a [u8]) -> Self;
    fn column_size(&self) -> ffi::SQLULEN;
    fn value_ptr(&self) -> ffi::SQLPOINTER;
    fn decimal_digits(&self) -> ffi::SQLSMALLINT {
        0
    }
}

unsafe impl<'a> OdbcType<'a> for &'a[u8] {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_VARBINARY
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_BINARY
    }

    fn convert(buffer: &'a [u8]) -> Self {
        buffer
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for Vec<u8> {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_VARBINARY
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_BINARY
    }

    fn convert(buffer: &'a [u8]) -> Self {
        buffer.to_vec()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for &'a[u16] {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_WVARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_WCHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        unsafe { from_raw_parts(buffer.as_ptr() as *const u16, buffer.len() / 2) }
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for Vec<u16> {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_WVARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_WCHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        let buffer = unsafe { from_raw_parts(buffer.as_ptr() as *const u16, buffer.len() / 2) };
        buffer.to_vec()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for CString {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_VARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        CString::new(buffer).unwrap()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.as_bytes().len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_bytes().as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for String {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_VARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        from_utf8(buffer).unwrap().to_owned()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.as_bytes().len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_bytes().as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for &'a str {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_VARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        from_utf8(buffer).unwrap()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.as_bytes().len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_bytes().as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

fn convert_primitive<T>(buf: &[u8]) -> T
where
    T: Copy,
{
    unsafe { from_raw_parts(buf.as_ptr() as *const T, 1)[0] }
}

unsafe impl<'a> OdbcType<'a> for u8 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_SMALLINT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_UTINYINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for i8 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_SMALLINT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_STINYINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for i16 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_SMALLINT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SSHORT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for u16 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_SMALLINT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_USHORT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for i32 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_INTEGER
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SLONG
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for u32 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_INTEGER
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_ULONG
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for i64 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_INTEGER
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SBIGINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for u64 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_INTEGER
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_UBIGINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for f32 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_FLOAT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_FLOAT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for f64 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_DOUBLE
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_DOUBLE
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

unsafe impl<'a> OdbcType<'a> for bool {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_BIT
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_BIT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        assert!(buffer.len() == 1);
        buffer[0] > 0
    }

    fn column_size(&self) -> ffi::SQLULEN {
        1 as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

pub type SqlDate = ffi::SQL_DATE_STRUCT;

unsafe impl<'a> OdbcType<'a> for SqlDate {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_DATE
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_DATE
    }

    fn convert(buffer: &'a [u8]) -> Self {
        assert_eq!(buffer.len(), size_of::<Self>());
        unsafe {
            let ptr = buffer.as_ptr() as *const [u8; size_of::<Self>()];
            transmute(*ptr)
        }
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

pub type SqlTime = ffi::SQL_TIME_STRUCT;

unsafe impl<'a> OdbcType<'a> for SqlTime {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_TIME
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_TIME
    }

    fn convert(buffer: &'a [u8]) -> Self {
        assert_eq!(buffer.len(), size_of::<Self>());
        unsafe {
            let ptr = buffer.as_ptr() as *const [u8; size_of::<Self>()];
            transmute(*ptr)
        }
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

pub type SqlTimestamp = ffi::SQL_TIMESTAMP_STRUCT;

unsafe impl<'a> OdbcType<'a> for SqlTimestamp {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_TIMESTAMP
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_TYPE_TIMESTAMP
    }

    fn convert(buffer: &'a [u8]) -> Self {
        assert_eq!(buffer.len(), size_of::<Self>());
        unsafe {
            let ptr = buffer.as_ptr() as *const [u8; size_of::<Self>()];
            transmute(*ptr)
        }
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}

pub type SqlSsTime2 = ffi::SQL_SS_TIME2_STRUCT;

unsafe impl<'a> OdbcType<'a> for SqlSsTime2 {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_EXT_VARBINARY
    }
    fn c_data_type() -> ffi::SqlCDataType {
        // NOTE: ODBC 3.5 and earlier
        ffi::SQL_C_BINARY
    }

    fn convert(buffer: &'a [u8]) -> Self {
        assert_eq!(buffer.len(), size_of::<Self>());
        unsafe {
            let ptr = buffer.as_ptr() as *const [u8; size_of::<Self>()];
            transmute(*ptr)
        }
    }

    fn column_size(&self) -> ffi::SQLULEN {
        size_of::<Self>() as ffi::SQLULEN
    }
    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self as *const Self as ffi::SQLPOINTER
    }
}<|endoftext|>


<commit_before>use crate::ast::Field;
use crate::attr::Display;
use proc_macro2::TokenTree;
use quote::{format_ident, quote_spanned};
use std::collections::HashSet as Set;
use syn::ext::IdentExt;
use syn::parse::{ParseStream, Parser};
use syn::{Ident, Index, LitStr, Member, Result, Token};

impl Display<'_> {
    // Transform `"error {var}"` to `"error {}", var`.
    pub fn expand_shorthand(&mut self, fields: &[Field]) {
        let raw_args = self.args.clone();
        let mut named_args = explicit_named_args.parse2(raw_args).unwrap();
        let fields: Set<Member> = fields.iter().map(|f| f.member.clone()).collect();

        let span = self.fmt.span();
        let fmt = self.fmt.value();
        let mut read = fmt.as_str();
        let mut out = String::new();
        let mut args = self.args.clone();
        let mut has_bonus_display = false;

        let mut has_trailing_comma = false;
        if let Some(TokenTree::Punct(punct)) = args.clone().into_iter().last() {
            if punct.as_char() == ',' {
                has_trailing_comma = true;
            }
        }

        while let Some(brace) = read.find('{') {
            out += &read[..brace + 1];
            read = &read[brace + 1..];
            if read.starts_with('{') {
                out.push('{');
                read = &read[1..];
                continue;
            }
            let next = match read.chars().next() {
                Some(next) => next,
                None => return,
            };
            let member = match next {
                '0'..='9' => {
                    let int = take_int(&mut read);
                    let member = match int.parse::<u32>() {
                        Ok(index) => Member::Unnamed(Index { index, span }),
                        Err(_) => return,
                    };
                    if !fields.contains(&member) {
                        out += ∫
                        continue;
                    }
                    member
                }
                'a'..='z' | 'A'..='Z' | '_' => {
                    let mut ident = take_ident(&mut read);
                    ident.set_span(span);
                    Member::Named(ident)
                }
                _ => continue,
            };
            let local = match &member {
                Member::Unnamed(index) => format_ident!("_{}", index),
                Member::Named(ident) => ident.clone(),
            };
            let mut formatvar = local.clone();
            if formatvar.to_string().starts_with("r#") {
                formatvar = format_ident!("r_{}", formatvar);
            }
            if formatvar.to_string().starts_with('_') {
                // Work around leading underscore being rejected by 1.40 and
                // older compilers. https://github.com/rust-lang/rust/pull/66847
                formatvar = format_ident!("field_{}", formatvar);
            }
            out += &formatvar.to_string();
            if !named_args.insert(formatvar.clone()) {
                // Already specified in the format argument list.
                continue;
            }
            if !has_trailing_comma {
                args.extend(quote_spanned!(span=> ,));
            }
            args.extend(quote_spanned!(span=> #formatvar = #local));
            if read.starts_with('}') && fields.contains(&member) {
                has_bonus_display = true;
                args.extend(quote_spanned!(span=> .as_display()));
            }
            has_trailing_comma = false;
        }

        out += read;
        self.fmt = LitStr::new(&out, self.fmt.span());
        self.args = args;
        self.has_bonus_display = has_bonus_display;
    }
}

fn explicit_named_args(input: ParseStream) -> Result<Set<Ident>> {
    let mut named_args = Set::new();

    while !input.is_empty() {
        if input.peek(Token![,]) && input.peek2(Ident::peek_any) && input.peek3(Token![=]) {
            input.parse::<Token![,]>()?;
            let ident: Ident = input.parse()?;
            input.parse::<Token![=]>()?;
            named_args.insert(ident);
        } else {
            input.parse::<TokenTree>()?;
        }
    }

    Ok(named_args)
}

fn take_int(read: &mut &str) -> String {
    let mut int = String::new();
    for (i, ch) in read.char_indices() {
        match ch {
            '0'..='9' => int.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    int
}

fn take_ident(read: &mut &str) -> Ident {
    let mut ident = String::new();
    let raw = read.starts_with("r#");
    if raw {
        ident.push_str("r#");
        *read = &read[2..];
    }
    for (i, ch) in read.char_indices() {
        match ch {
            'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => ident.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    syn::parse_str(&ident).unwrap()
}
<commit_msg>Fix first place that keyword fmt argument is failing<commit_after>use crate::ast::Field;
use crate::attr::Display;
use proc_macro2::TokenTree;
use quote::{format_ident, quote_spanned};
use std::collections::HashSet as Set;
use syn::ext::IdentExt;
use syn::parse::{ParseStream, Parser};
use syn::{Ident, Index, LitStr, Member, Result, Token};

impl Display<'_> {
    // Transform `"error {var}"` to `"error {}", var`.
    pub fn expand_shorthand(&mut self, fields: &[Field]) {
        let raw_args = self.args.clone();
        let mut named_args = explicit_named_args.parse2(raw_args).unwrap();
        let fields: Set<Member> = fields.iter().map(|f| f.member.clone()).collect();

        let span = self.fmt.span();
        let fmt = self.fmt.value();
        let mut read = fmt.as_str();
        let mut out = String::new();
        let mut args = self.args.clone();
        let mut has_bonus_display = false;

        let mut has_trailing_comma = false;
        if let Some(TokenTree::Punct(punct)) = args.clone().into_iter().last() {
            if punct.as_char() == ',' {
                has_trailing_comma = true;
            }
        }

        while let Some(brace) = read.find('{') {
            out += &read[..brace + 1];
            read = &read[brace + 1..];
            if read.starts_with('{') {
                out.push('{');
                read = &read[1..];
                continue;
            }
            let next = match read.chars().next() {
                Some(next) => next,
                None => return,
            };
            let member = match next {
                '0'..='9' => {
                    let int = take_int(&mut read);
                    let member = match int.parse::<u32>() {
                        Ok(index) => Member::Unnamed(Index { index, span }),
                        Err(_) => return,
                    };
                    if !fields.contains(&member) {
                        out += ∫
                        continue;
                    }
                    member
                }
                'a'..='z' | 'A'..='Z' | '_' => {
                    let mut ident = take_ident(&mut read);
                    ident.set_span(span);
                    Member::Named(ident)
                }
                _ => continue,
            };
            let local = match &member {
                Member::Unnamed(index) => format_ident!("_{}", index),
                Member::Named(ident) => ident.clone(),
            };
            let mut formatvar = local.clone();
            if formatvar.to_string().starts_with("r#") {
                formatvar = format_ident!("r_{}", formatvar);
            }
            if formatvar.to_string().starts_with('_') {
                // Work around leading underscore being rejected by 1.40 and
                // older compilers. https://github.com/rust-lang/rust/pull/66847
                formatvar = format_ident!("field_{}", formatvar);
            }
            out += &formatvar.to_string();
            if !named_args.insert(formatvar.clone()) {
                // Already specified in the format argument list.
                continue;
            }
            if !has_trailing_comma {
                args.extend(quote_spanned!(span=> ,));
            }
            args.extend(quote_spanned!(span=> #formatvar = #local));
            if read.starts_with('}') && fields.contains(&member) {
                has_bonus_display = true;
                args.extend(quote_spanned!(span=> .as_display()));
            }
            has_trailing_comma = false;
        }

        out += read;
        self.fmt = LitStr::new(&out, self.fmt.span());
        self.args = args;
        self.has_bonus_display = has_bonus_display;
    }
}

fn explicit_named_args(input: ParseStream) -> Result<Set<Ident>> {
    let mut named_args = Set::new();

    while !input.is_empty() {
        if input.peek(Token![,]) && input.peek2(Ident::peek_any) && input.peek3(Token![=]) {
            input.parse::<Token![,]>()?;
            let ident = input.call(Ident::parse_any)?;
            input.parse::<Token![=]>()?;
            named_args.insert(ident);
        } else {
            input.parse::<TokenTree>()?;
        }
    }

    Ok(named_args)
}

fn take_int(read: &mut &str) -> String {
    let mut int = String::new();
    for (i, ch) in read.char_indices() {
        match ch {
            '0'..='9' => int.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    int
}

fn take_ident(read: &mut &str) -> Ident {
    let mut ident = String::new();
    let raw = read.starts_with("r#");
    if raw {
        ident.push_str("r#");
        *read = &read[2..];
    }
    for (i, ch) in read.char_indices() {
        match ch {
            'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => ident.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    syn::parse_str(&ident).unwrap()
}
<|endoftext|>


<commit_before>use crate::ReadableKey;
use crate::{KeySet, StringKey, WriteableKey};
use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::ptr::NonNull;
use {KDBError::*, LogicalError::*, PermanentError::*, ResourceError::*, ValidationError::*};

/// General methods to access the Key database.
/// For example usage see [the Readme](https://github.com/ElektraInitiative/libelektra/tree/master/src/bindings/rust).
#[derive(Debug)]
pub struct KDB {
    ptr: NonNull<elektra_sys::KDB>,
    _marker: std::marker::PhantomData<elektra_sys::KDB>,
}

impl Drop for KDB {
    fn drop(&mut self) {
        let mut err_key = StringKey::new_empty();
        unsafe {
            elektra_sys::kdbClose(self.as_ptr(), err_key.as_ptr());
        }
    }
}

impl KDB {
    /// Opens the session with the Key database.
    pub fn open<'a>() -> Result<Self, KDBError<'a>> {
        let mut key = StringKey::new_empty();
        let kdb_ptr = unsafe { elektra_sys::kdbOpen(key.as_ptr()) };

        if kdb_ptr.is_null() {
            Err(map_kdb_error(&key))
        } else {
            Ok(KDB {
                ptr: NonNull::new(kdb_ptr).unwrap(),
                _marker: std::marker::PhantomData,
            })
        }
    }

    /// Retrieve keys in an atomic and universal way.
    /// Note that the provided keyset is modified and contains the result.
    /// The provided `key` is used to give a hint about which keys should be retrieved.
    /// The return value is true, if the keys were successfully retrieved
    /// and false if there were no changes to the keyset.
    pub fn get<'a>(
        &mut self,
        keyset: &mut KeySet,
        key: &mut StringKey<'a>,
    ) -> Result<bool, KDBError<'a>> {
        let ret_val = unsafe { elektra_sys::kdbGet(self.as_ptr(), keyset.as_ptr(), key.as_ptr()) };

        if ret_val == 1 {
            Ok(true)
        } else if ret_val == 0 {
            Ok(false)
        } else {
            Err(map_kdb_error(key))
        }
    }

    /// Set keys in an atomic and universal way.
    /// The provided `key` is used to give a hint about which keys should be stored.
    /// The return value is true on success,
    /// and false if there were no changes to the KDB.
    /// # Notes
    /// You have to call [`get`](#method.get) with `keyset` first.
    pub fn set<'a>(
        &mut self,
        keyset: &mut KeySet,
        key: &mut StringKey<'a>,
    ) -> Result<bool, KDBError<'a>> {
        let ret_val = unsafe { elektra_sys::kdbSet(self.as_ptr(), keyset.as_ptr(), key.as_ptr()) };

        if ret_val == 1 {
            Ok(true)
        } else if ret_val == 0 {
            Ok(false)
        } else {
            Err(map_kdb_error(key))
        }
    }

    /// This method can be used the given KDB handle meets certain clauses, specified in contract.
    /// The return value is true on success,
    /// and false if clauses of the contract are unmet.
    pub fn ensure<'a>(
        &mut self,
        keyset: &mut KeySet,
        key: &mut StringKey<'a>,
    ) -> Result<bool, KDBError<'a>> {
        let ret_val =
            unsafe { elektra_sys::kdbEnsure(self.as_ptr(), keyset.as_ptr(), key.as_ptr()) };

        if ret_val == 0 {
            Ok(true)
        } else if ret_val == 1 {
            Ok(false)
        } else {
            Err(map_kdb_error(key))
        }
    }
    /// Returns the raw pointer of the KDB object.
    /// Should be used with caution. In particular,
    /// the pointer should only be modified with
    /// `elektra_sys::kdb*` functions, but `kdbClose`
    /// should not be called.
    pub fn as_ptr(&mut self) -> *mut elektra_sys::KDB {
        self.ptr.as_ptr()
    }
}

impl AsRef<elektra_sys::KDB> for KDB {
    fn as_ref(&self) -> &elektra_sys::KDB {
        unsafe { self.ptr.as_ref() }
    }
}

const ELEKTRA_ERROR_OUT_OF_MEMORY: &str = "C01110";
const ELEKTRA_ERROR_INTERNAL: &str = "C01310";
const ELEKTRA_ERROR_INSTALLATION: &str = "C01200";
const ELEKTRA_ERROR_INTERFACE: &str = "C01320";
const ELEKTRA_ERROR_PLUGIN_MISBEHAVIOR: &str = "C01330";
const ELEKTRA_ERROR_CONFLICTING_STATE: &str = "C02000";
const ELEKTRA_ERROR_VALIDATION_SYNTACTIC: &str = "C03100";
const ELEKTRA_ERROR_VALIDATION_SEMANTIC: &str = "C03200";

#[derive(Debug)]
pub enum KDBError<'a> {
    Permanent(PermanentError<'a>),
    ConflictingState(KDBErrorWrapper<'a>),
    Validation(ValidationError<'a>),
}

#[derive(Debug)]
pub enum PermanentError<'a> {
    Resource(ResourceError<'a>),
    Logical(LogicalError<'a>),
    Installation(KDBErrorWrapper<'a>),
}

#[derive(Debug)]
pub enum LogicalError<'a> {
    Internal(KDBErrorWrapper<'a>),
    Interface(KDBErrorWrapper<'a>),
    PluginMisbehavior(KDBErrorWrapper<'a>),
}

#[derive(Debug)]
pub enum ResourceError<'a> {
    OutOfMemory(KDBErrorWrapper<'a>),
}

#[derive(Debug)]
pub enum ValidationError<'a> {
    Syntactic(KDBErrorWrapper<'a>),
    Semantic(KDBErrorWrapper<'a>),
}

/// Wraps a key that contains error metakeys
#[derive(Debug)]
pub struct KDBErrorWrapper<'a> {
    error_key: StringKey<'a>,
}

impl<'a> KDBErrorWrapper<'a> {
    /// Constructs a new KDBErrorWrapper from a StringKey.
    /// Only pass keys where the metakeys error/* are set.
    pub fn new(error_key: StringKey) -> KDBErrorWrapper {
        KDBErrorWrapper { error_key }
    }

    /// Returns the error number or an empty string if unavailable.
    pub fn number(&self) -> String {
        self.error_key_or_empty_string("error/number")
    }

    /// Returns the error reason or an empty string if unavailable.
    pub fn reason(&self) -> String {
        self.error_key_or_empty_string("error/reason")
    }

    /// Returns the module where the error occured or an empty string if unavailable.
    pub fn module(&self) -> String {
        self.error_key_or_empty_string("error/module")
    }

    /// Returns a description of the error or an empty string if unavailable.
    pub fn description(&self) -> String {
        self.error_key_or_empty_string("error/description")
    }

    /// Returns the source file from where the error information comes or an empty string if unavailable.
    pub fn file(&self) -> String {
        self.error_key_or_empty_string("error/file")
    }

    /// Returns the exact line of that source file or an empty string if unavailable.
    pub fn line(&self) -> String {
        self.error_key_or_empty_string("error/line")
    }

    fn error_key_or_empty_string(&self, error_key: &str) -> String {
        if let Ok(meta) = self.error_key.meta(error_key) {
            meta.value().to_owned().to_string()
        } else {
            "".into()
        }
    }

    /// Returns a formatted error message
    pub fn to_error_message(&self) -> String {
        format!(
            "Sorry, module {module} issued error {error_number}:\n{description}: {reason}",
            module = self.module(),
            error_number = self.number(),
            description = self.description(),
            reason = self.reason()
        )
    }
}

// Display + Error impl for all variants. Needed such that an error can be catched an printed, instead of
// matched all the way down, since only KDBErrorWrapper implements the actual message conversion.

impl<'a> Display for KDBError<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
        match self {
            KDBError::ConflictingState(err) => write!(f, "{}", err),
            KDBError::Permanent(err) => write!(f, "{}", err),
            KDBError::Validation(err) => write!(f, "{}", err),
        }
    }
}

impl<'a> Error for KDBError<'a> {}

impl<'a> Display for PermanentError<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
        match self {
            PermanentError::Installation(err) => write!(f, "{}", err),
            PermanentError::Logical(err) => write!(f, "{}", err),
            PermanentError::Resource(err) => write!(f, "{}", err),
        }
    }
}

impl<'a> Error for PermanentError<'a> {}

impl<'a> Display for ResourceError<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
        match self {
            ResourceError::OutOfMemory(err) => write!(f, "{}", err),
        }
    }
}

impl<'a> Error for ResourceError<'a> {}

impl<'a> Display for LogicalError<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
        match self {
            LogicalError::Interface(err) => write!(f, "{}", err),
            LogicalError::Internal(err) => write!(f, "{}", err),
            LogicalError::PluginMisbehavior(err) => write!(f, "{}", err),
        }
    }
}

impl<'a> Error for LogicalError<'a> {}

impl<'a> Display for ValidationError<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
        match self {
            ValidationError::Semantic(err) => write!(f, "{}", err),
            ValidationError::Syntactic(err) => write!(f, "{}", err),
        }
    }
}

impl<'a> Error for ValidationError<'a> {}

impl<'a> Display for KDBErrorWrapper<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
        write!(f, "{}", self.to_error_message())
    }
}

impl<'a> Error for KDBErrorWrapper<'a> {}

fn map_kdb_error<'a, 'b>(error_key: &'a StringKey) -> KDBError<'b> {
    let err_num_key_res = error_key.meta("error/number");
    if let Ok(err_num_key) = err_num_key_res {
        let err_wrapper = KDBErrorWrapper::new(error_key.duplicate());

        match err_num_key.value().to_owned().to_string().as_str() {
            ELEKTRA_ERROR_OUT_OF_MEMORY => {
                return Permanent(Resource(OutOfMemory(err_wrapper)));
            }
            ELEKTRA_ERROR_INSTALLATION => {
                return Permanent(Installation(err_wrapper));
            }
            ELEKTRA_ERROR_INTERNAL => {
                return Permanent(Logical(Internal(err_wrapper)));
            }
            ELEKTRA_ERROR_INTERFACE => {
                return Permanent(Logical(Interface(err_wrapper)));
            }
            ELEKTRA_ERROR_PLUGIN_MISBEHAVIOR => {
                return Permanent(Logical(PluginMisbehavior(err_wrapper)));
            }
            ELEKTRA_ERROR_CONFLICTING_STATE => {
                return ConflictingState(err_wrapper);
            }
            ELEKTRA_ERROR_VALIDATION_SYNTACTIC => {
                return Validation(Syntactic(err_wrapper));
            }
            ELEKTRA_ERROR_VALIDATION_SEMANTIC => {
                return Validation(Semantic(err_wrapper));
            }
            _ => {
                panic!("Unknown error code {}", err_num_key.value());
            }
        }
    }
    panic!("No error/number metakey is available.")
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::{KeyBuilder, LookupOption};

    const PARENT_KEY: &str = "user/sw/tests/rust/1/";
    const KEY_1_NAME: &str = "user/sw/tests/rust/1/key_name";
    const KEY_2_NAME: &str = "user/sw/tests/rust/1/key_name/2";

    const KEY_1_VALUE: &str = "key_value_1";
    const KEY_2_VALUE: &str = "key_value_2";

    fn create_test_keys<'a>() -> (StringKey<'a>, StringKey<'a>, StringKey<'a>) {
        let parent_key = StringKey::new(PARENT_KEY).unwrap();
        let key1: StringKey = KeyBuilder::new(KEY_1_NAME)
            .unwrap()
            .value(KEY_1_VALUE)
            .build();
        let key2: StringKey = KeyBuilder::new(KEY_2_NAME)
            .unwrap()
            .value(KEY_2_VALUE)
            .build();
        (parent_key, key1, key2)
    }

    #[test]
    fn can_use_kdb() {
        let (mut parent_key, key1, key2) = create_test_keys();
        {
            let mut kdb = KDB::open().unwrap();
            let mut ks = KeySet::with_capacity(10);
            kdb.get(&mut ks, &mut parent_key).unwrap();
            ks.append_key(key1);
            ks.append_key(key2);
            kdb.set(&mut ks, &mut parent_key).unwrap();
        }
        {
            let mut kdb = KDB::open().unwrap();
            let mut ks = KeySet::with_capacity(2);
            kdb.get(&mut ks, &mut parent_key).unwrap();
            let key1_lookup = ks
                .lookup_by_name(KEY_1_NAME, Default::default())
                .unwrap()
                .duplicate();
            assert_eq!(key1_lookup.value(), KEY_1_VALUE);

            let key2_lookup = ks
                .lookup_by_name(KEY_2_NAME, Default::default())
                .unwrap()
                .duplicate();
            assert_eq!(key2_lookup.value(), KEY_2_VALUE);
        }
        remove_test_keys();
    }

    fn remove_test_keys() {
        let (mut parent_key, _, _) = create_test_keys();
        let mut kdb = KDB::open().unwrap();
        let mut ks = KeySet::with_capacity(10);
        kdb.get(&mut ks, &mut parent_key).unwrap();
        ks.lookup_by_name(KEY_1_NAME, LookupOption::KDB_O_POP)
            .unwrap();
        ks.lookup_by_name(KEY_2_NAME, LookupOption::KDB_O_POP)
            .unwrap();
        kdb.set(&mut ks, &mut parent_key).unwrap();
    }
}
<commit_msg>rust: Add GeneralResourceError & more error logs<commit_after>use crate::ReadableKey;
use crate::{KeySet, StringKey, WriteableKey};
use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::ptr::NonNull;
use {KDBError::*, LogicalError::*, PermanentError::*, ResourceError::*, ValidationError::*};

/// General methods to access the Key database.
/// For example usage see [the Readme](https://github.com/ElektraInitiative/libelektra/tree/master/src/bindings/rust).
#[derive(Debug)]
pub struct KDB {
    ptr: NonNull<elektra_sys::KDB>,
    _marker: std::marker::PhantomData<elektra_sys::KDB>,
}

impl Drop for KDB {
    fn drop(&mut self) {
        let mut err_key = StringKey::new_empty();
        unsafe {
            elektra_sys::kdbClose(self.as_ptr(), err_key.as_ptr());
        }
    }
}

impl KDB {
    /// Opens the session with the Key database.
    pub fn open<'a>() -> Result<Self, KDBError<'a>> {
        let mut key = StringKey::new_empty();
        let kdb_ptr = unsafe { elektra_sys::kdbOpen(key.as_ptr()) };

        if kdb_ptr.is_null() {
            Err(map_kdb_error(&key))
        } else {
            Ok(KDB {
                ptr: NonNull::new(kdb_ptr).unwrap(),
                _marker: std::marker::PhantomData,
            })
        }
    }

    /// Retrieve keys in an atomic and universal way.
    /// Note that the provided keyset is modified and contains the result.
    /// The provided `key` is used to give a hint about which keys should be retrieved.
    /// The return value is true, if the keys were successfully retrieved
    /// and false if there were no changes to the keyset.
    pub fn get<'a>(
        &mut self,
        keyset: &mut KeySet,
        key: &mut StringKey<'a>,
    ) -> Result<bool, KDBError<'a>> {
        let ret_val = unsafe { elektra_sys::kdbGet(self.as_ptr(), keyset.as_ptr(), key.as_ptr()) };

        if ret_val == 1 {
            Ok(true)
        } else if ret_val == 0 {
            Ok(false)
        } else {
            Err(map_kdb_error(key))
        }
    }

    /// Set keys in an atomic and universal way.
    /// The provided `key` is used to give a hint about which keys should be stored.
    /// The return value is true on success,
    /// and false if there were no changes to the KDB.
    /// # Notes
    /// You have to call [`get`](#method.get) with `keyset` first.
    pub fn set<'a>(
        &mut self,
        keyset: &mut KeySet,
        key: &mut StringKey<'a>,
    ) -> Result<bool, KDBError<'a>> {
        let ret_val = unsafe { elektra_sys::kdbSet(self.as_ptr(), keyset.as_ptr(), key.as_ptr()) };

        if ret_val == 1 {
            Ok(true)
        } else if ret_val == 0 {
            Ok(false)
        } else {
            Err(map_kdb_error(key))
        }
    }

    /// This method can be used the given KDB handle meets certain clauses, specified in contract.
    /// The return value is true on success,
    /// and false if clauses of the contract are unmet.
    pub fn ensure<'a>(
        &mut self,
        keyset: &mut KeySet,
        key: &mut StringKey<'a>,
    ) -> Result<bool, KDBError<'a>> {
        let ret_val =
            unsafe { elektra_sys::kdbEnsure(self.as_ptr(), keyset.as_ptr(), key.as_ptr()) };

        if ret_val == 0 {
            Ok(true)
        } else if ret_val == 1 {
            Ok(false)
        } else {
            Err(map_kdb_error(key))
        }
    }
    /// Returns the raw pointer of the KDB object.
    /// Should be used with caution. In particular,
    /// the pointer should only be modified with
    /// `elektra_sys::kdb*` functions, but `kdbClose`
    /// should not be called.
    pub fn as_ptr(&mut self) -> *mut elektra_sys::KDB {
        self.ptr.as_ptr()
    }
}

impl AsRef<elektra_sys::KDB> for KDB {
    fn as_ref(&self) -> &elektra_sys::KDB {
        unsafe { self.ptr.as_ref() }
    }
}
const ELEKTRA_ERROR_RESOURCE: &str = "C01100";
const ELEKTRA_ERROR_OUT_OF_MEMORY: &str = "C01110";
const ELEKTRA_ERROR_INTERNAL: &str = "C01310";
const ELEKTRA_ERROR_INSTALLATION: &str = "C01200";
const ELEKTRA_ERROR_INTERFACE: &str = "C01320";
const ELEKTRA_ERROR_PLUGIN_MISBEHAVIOR: &str = "C01330";
const ELEKTRA_ERROR_CONFLICTING_STATE: &str = "C02000";
const ELEKTRA_ERROR_VALIDATION_SYNTACTIC: &str = "C03100";
const ELEKTRA_ERROR_VALIDATION_SEMANTIC: &str = "C03200";

#[derive(Debug)]
pub enum KDBError<'a> {
    Permanent(PermanentError<'a>),
    ConflictingState(KDBErrorWrapper<'a>),
    Validation(ValidationError<'a>),
}

#[derive(Debug)]
pub enum PermanentError<'a> {
    Resource(ResourceError<'a>),
    Logical(LogicalError<'a>),
    Installation(KDBErrorWrapper<'a>),
}

#[derive(Debug)]
pub enum LogicalError<'a> {
    Internal(KDBErrorWrapper<'a>),
    Interface(KDBErrorWrapper<'a>),
    PluginMisbehavior(KDBErrorWrapper<'a>),
}

#[derive(Debug)]
pub enum ResourceError<'a> {
    GeneralResourceError(KDBErrorWrapper<'a>),
    OutOfMemory(KDBErrorWrapper<'a>),
}

#[derive(Debug)]
pub enum ValidationError<'a> {
    Syntactic(KDBErrorWrapper<'a>),
    Semantic(KDBErrorWrapper<'a>),
}

/// Wraps a key that contains error metakeys
#[derive(Debug)]
pub struct KDBErrorWrapper<'a> {
    error_key: StringKey<'a>,
}

impl<'a> KDBErrorWrapper<'a> {
    /// Constructs a new KDBErrorWrapper from a StringKey.
    /// Only pass keys where the metakeys error/* are set.
    pub fn new(error_key: StringKey) -> KDBErrorWrapper {
        KDBErrorWrapper { error_key }
    }

    /// Returns the error number or an empty string if unavailable.
    pub fn number(&self) -> String {
        self.error_key_or_empty_string("error/number")
    }

    /// Returns the error reason or an empty string if unavailable.
    pub fn reason(&self) -> String {
        self.error_key_or_empty_string("error/reason")
    }

    /// Returns the module where the error occured or an empty string if unavailable.
    pub fn module(&self) -> String {
        self.error_key_or_empty_string("error/module")
    }

    /// Returns a description of the error or an empty string if unavailable.
    pub fn description(&self) -> String {
        self.error_key_or_empty_string("error/description")
    }

    /// Returns the source file from where the error information comes or an empty string if unavailable.
    pub fn file(&self) -> String {
        self.error_key_or_empty_string("error/file")
    }

    /// Returns the exact line of that source file or an empty string if unavailable.
    pub fn line(&self) -> String {
        self.error_key_or_empty_string("error/line")
    }

    fn error_key_or_empty_string(&self, error_key: &str) -> String {
        if let Ok(meta) = self.error_key.meta(error_key) {
            meta.value().to_owned().to_string()
        } else {
            "".into()
        }
    }

    /// Returns a formatted error message
    pub fn to_error_message(&self) -> String {
        format!(
            "Sorry, module {module} issued error {error_number}:\n{description}: {reason}",
            module = self.module(),
            error_number = self.number(),
            description = self.description(),
            reason = self.reason()
        )
    }
}

// Display + Error impl for all variants. Needed such that an error can be catched an printed, instead of
// matched all the way down, since only KDBErrorWrapper implements the actual message conversion.

impl<'a> Display for KDBError<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
        match self {
            KDBError::ConflictingState(err) => write!(f, "{}", err),
            KDBError::Permanent(err) => write!(f, "{}", err),
            KDBError::Validation(err) => write!(f, "{}", err),
        }
    }
}

impl<'a> Error for KDBError<'a> {}

impl<'a> Display for PermanentError<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
        match self {
            PermanentError::Installation(err) => write!(f, "{}", err),
            PermanentError::Logical(err) => write!(f, "{}", err),
            PermanentError::Resource(err) => write!(f, "{}", err),
        }
    }
}

impl<'a> Error for PermanentError<'a> {}

impl<'a> Display for ResourceError<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
        match self {
            ResourceError::GeneralResourceError(err) => write!(f, "{}", err),
            ResourceError::OutOfMemory(err) => write!(f, "{}", err),
        }
    }
}

impl<'a> Error for ResourceError<'a> {}

impl<'a> Display for LogicalError<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
        match self {
            LogicalError::Interface(err) => write!(f, "{}", err),
            LogicalError::Internal(err) => write!(f, "{}", err),
            LogicalError::PluginMisbehavior(err) => write!(f, "{}", err),
        }
    }
}

impl<'a> Error for LogicalError<'a> {}

impl<'a> Display for ValidationError<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
        match self {
            ValidationError::Semantic(err) => write!(f, "{}", err),
            ValidationError::Syntactic(err) => write!(f, "{}", err),
        }
    }
}

impl<'a> Error for ValidationError<'a> {}

impl<'a> Display for KDBErrorWrapper<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
        write!(f, "{}", self.to_error_message())
    }
}

impl<'a> Error for KDBErrorWrapper<'a> {}

fn map_kdb_error<'a, 'b>(error_key: &'a StringKey) -> KDBError<'b> {
    let err_num_key_res = error_key.meta("error/number");
    if let Ok(err_num_key) = err_num_key_res {
        let err_wrapper = KDBErrorWrapper::new(error_key.duplicate());

        match err_num_key.value().to_owned().to_string().as_str() {
            ELEKTRA_ERROR_RESOURCE => {
                return Permanent(Resource(GeneralResourceError(err_wrapper)));
            }
            ELEKTRA_ERROR_OUT_OF_MEMORY => {
                return Permanent(Resource(OutOfMemory(err_wrapper)));
            }
            ELEKTRA_ERROR_INSTALLATION => {
                return Permanent(Installation(err_wrapper));
            }
            ELEKTRA_ERROR_INTERNAL => {
                return Permanent(Logical(Internal(err_wrapper)));
            }
            ELEKTRA_ERROR_INTERFACE => {
                return Permanent(Logical(Interface(err_wrapper)));
            }
            ELEKTRA_ERROR_PLUGIN_MISBEHAVIOR => {
                return Permanent(Logical(PluginMisbehavior(err_wrapper)));
            }
            ELEKTRA_ERROR_CONFLICTING_STATE => {
                return ConflictingState(err_wrapper);
            }
            ELEKTRA_ERROR_VALIDATION_SYNTACTIC => {
                return Validation(Syntactic(err_wrapper));
            }
            ELEKTRA_ERROR_VALIDATION_SEMANTIC => {
                return Validation(Semantic(err_wrapper));
            }
            _ => {
                panic!("Unknown error code {}. Error Message: {}", err_num_key.value(), err_wrapper.to_error_message());
            }
        }
    }
    panic!("No error/number metakey is available.")
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::{KeyBuilder, LookupOption};

    const PARENT_KEY: &str = "user/sw/tests/rust/1/";
    const KEY_1_NAME: &str = "user/sw/tests/rust/1/key_name";
    const KEY_2_NAME: &str = "user/sw/tests/rust/1/key_name/2";

    const KEY_1_VALUE: &str = "key_value_1";
    const KEY_2_VALUE: &str = "key_value_2";

    fn create_test_keys<'a>() -> (StringKey<'a>, StringKey<'a>, StringKey<'a>) {
        let parent_key = StringKey::new(PARENT_KEY).unwrap();
        let key1: StringKey = KeyBuilder::new(KEY_1_NAME)
            .unwrap()
            .value(KEY_1_VALUE)
            .build();
        let key2: StringKey = KeyBuilder::new(KEY_2_NAME)
            .unwrap()
            .value(KEY_2_VALUE)
            .build();
        (parent_key, key1, key2)
    }

    #[test]
    fn can_use_kdb() {
        let (mut parent_key, key1, key2) = create_test_keys();
        {
            let mut kdb = KDB::open().unwrap();
            let mut ks = KeySet::with_capacity(10);
            kdb.get(&mut ks, &mut parent_key).unwrap();
            ks.append_key(key1);
            ks.append_key(key2);
            kdb.set(&mut ks, &mut parent_key).unwrap();
        }
        {
            let mut kdb = KDB::open().unwrap();
            let mut ks = KeySet::with_capacity(2);
            kdb.get(&mut ks, &mut parent_key).unwrap();
            let key1_lookup = ks
                .lookup_by_name(KEY_1_NAME, Default::default())
                .unwrap()
                .duplicate();
            assert_eq!(key1_lookup.value(), KEY_1_VALUE);

            let key2_lookup = ks
                .lookup_by_name(KEY_2_NAME, Default::default())
                .unwrap()
                .duplicate();
            assert_eq!(key2_lookup.value(), KEY_2_VALUE);
        }
        remove_test_keys();
    }

    fn remove_test_keys() {
        let (mut parent_key, _, _) = create_test_keys();
        let mut kdb = KDB::open().unwrap();
        let mut ks = KeySet::with_capacity(10);
        kdb.get(&mut ks, &mut parent_key).unwrap();
        ks.lookup_by_name(KEY_1_NAME, LookupOption::KDB_O_POP)
            .unwrap();
        ks.lookup_by_name(KEY_2_NAME, LookupOption::KDB_O_POP)
            .unwrap();
        kdb.set(&mut ks, &mut parent_key).unwrap();
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::cell::RefCell;

use progress::{Timestamp, Scope};
use progress::nested::Source::ScopeOutput;
use progress::nested::Target::ScopeInput;
use progress::count_map::CountMap;

use communication::Data;
use communication::observer::{Counter, Tee};

use construction::{Stream, GraphBuilder};

pub trait ConcatExt<G: GraphBuilder, D: Data> {
    fn concat(&self, &Stream<G, D>) -> Stream<G, D>;
}

impl<G: GraphBuilder, D: Data> ConcatExt<G, D> for Stream<G, D> {
    fn concat(&self, other: &Stream<G, D>) -> Stream<G, D> {

        let (outputs, receiver) = Tee::<G::Timestamp, D>::new();
        let consumed = vec![Rc::new(RefCell::new(CountMap::new())),
                            Rc::new(RefCell::new(CountMap::new()))];

        let builder = self.builder();

        let index = builder.add_scope(ConcatScope { consumed: consumed.clone() });

        self.connect_to(ScopeInput(index, 0), Counter::new(outputs.clone(), consumed[0].clone()));
        other.connect_to(ScopeInput(index, 1), Counter::new(outputs, consumed[1].clone()));

        Stream::new(ScopeOutput(index, 0), receiver, builder)
    }
}

pub trait ConcatVecExt<G: GraphBuilder, D: Data> {
    fn concatenate(&self, Vec<Stream<G, D>>) -> Stream<G, D>;
}

impl<G: GraphBuilder, D: Data> ConcatVecExt<G, D> for G {
    fn concatenate(&self, sources: Vec<Stream<G, D>>) -> Stream<G, D> {

        if sources.len() == 0 { panic!("must pass at least one stream to concat"); }

        let (outputs, registrar) = Tee::<G::Timestamp, D>::new();
        let mut consumed = Vec::new();
        for _ in 0..sources.len() { consumed.push(Rc::new(RefCell::new(CountMap::new()))); }

        let index = self.add_scope(ConcatScope { consumed: consumed.clone() });

        for id in 0..sources.len() {
            sources[id].connect_to(ScopeInput(index, id as u64),
                                   Counter::new(outputs.clone(), consumed[id].clone()));
        }

        Stream::new(ScopeOutput(index, 0), registrar, self.clone())
    }
}

pub struct ConcatScope<T:Timestamp> {
    consumed:   Vec<Rc<RefCell<CountMap<T>>>>
}

impl<T:Timestamp> Scope<T> for ConcatScope<T> {
    fn name(&self) -> String { format!("Concat") }
    fn inputs(&self) -> u64 { self.consumed.len() as u64 }
    fn outputs(&self) -> u64 { 1 }

    fn pull_internal_progress(&mut self, _frontier_progress: &mut [CountMap<T>],
                                          messages_consumed: &mut [CountMap<T>],
                                          messages_produced: &mut [CountMap<T>]) -> bool
    {
        for (index, updates) in self.consumed.iter().enumerate() {
            while let Some((key, val)) = updates.borrow_mut().pop() {
                messages_consumed[index].update(&key, val);
                messages_produced[0].update(&key, val);
            }
        }

        return false;   // no reason to keep running on Concat's account
    }

    fn notify_me(&self) -> bool { false }
}
<commit_msg>concat/concatenate violated the current observer discipline, and were rewritten<commit_after>use std::rc::Rc;
use std::cell::RefCell;

use progress::{Timestamp, Scope};
use progress::nested::Source::ScopeOutput;
use progress::nested::Target::ScopeInput;
use progress::count_map::CountMap;

use communication::Data;
use communication::observer::{Counter, Tee, Extensions};
use communication::pact::Pipeline;

use construction::{Stream, GraphBuilder};
use construction::operators::binary::BinaryStreamExt;

// NOTE : These used to have more exotic implementations that connected observers in a tangle.
// NOTE : It was defective when used with the Observer protocol, because it just forwarded open and
// NOTE : shut messages, without concern for the fact that there would be multiple opens and shuts,
// NOTE : from each of its inputs. This implementation does more staging of data, but should be
// NOTE : less wrong.

pub trait ConcatExt<G: GraphBuilder, D: Data> {
    fn concat(&self, &Stream<G, D>) -> Stream<G, D>;
}

impl<G: GraphBuilder, D: Data> ConcatExt<G, D> for Stream<G, D> {
    fn concat(&self, other: &Stream<G, D>) -> Stream<G, D> {
        self.binary_stream(other, Pipeline, Pipeline, "concat", |input1, input2, output| {
            while let Some((time, data)) = input1.pull() {
                output.give_message_at(time, data);
            }
            while let Some((time, data)) = input2.pull() {
                output.give_message_at(time, data);
            }
        })
    }
}

pub trait ConcatVecExt<G: GraphBuilder, D: Data> {
    fn concatenate(&self, Vec<Stream<G, D>>) -> Stream<G, D>;
}

impl<G: GraphBuilder, D: Data> ConcatVecExt<G, D> for G {
    fn concatenate(&self, mut sources: Vec<Stream<G, D>>) -> Stream<G, D> {
        if let Some(mut result) = sources.pop() {
            while let Some(next) = sources.pop() {
                result = result.concat(&next);
            }
            result
        }
        else {
            panic!("must pass at least one stream to concatenate");
        }
    }
}
<|endoftext|>