<commit_before>pub(crate) mod by_path;
pub(crate) mod custom_attr;

use std::fmt;
use std::rc::Rc;

use protobuf::descriptor::EnumOptions;
use protobuf::descriptor::FieldOptions;
use protobuf::descriptor::FileOptions;
use protobuf::descriptor::MessageOptions;
use protobuf::reflect::EnumDescriptor;
use protobuf::reflect::FieldDescriptor;
use protobuf::reflect::MessageDescriptor;
use protobuf::reflect::OneofDescriptor;
use protobuf::rustproto;

/// Dynamic callback to customize code generation.
pub trait CustomizeCallback: 'static {
    fn customize_message(&self, message: &MessageDescriptor) -> String {
        let _ = message;
        String::new()
    }

    fn customize_field(&self, field: &FieldDescriptor) -> String {
        let _ = field;
        String::new()
    }

    fn customize_special_field(&self, message: &MessageDescriptor, field: &str) -> String {
        let _ = (message, field);
        String::new()
    }

    fn customize_enum(&self, enum_type: &EnumDescriptor) -> String {
        let _ = enum_type;
        String::new()
    }

    fn customize_oneof(&self, oneof: &OneofDescriptor) -> String {
        let _ = oneof;
        String::new()
    }
}

#[derive(Clone)]
pub(crate) struct CustomizeCallbackHolder(pub(crate) Rc<dyn CustomizeCallback>);

impl PartialEq for CustomizeCallbackHolder {
    fn eq(&self, other: &Self) -> bool {
        Rc::ptr_eq(&self.0, &other.0)
    }
}

impl fmt::Debug for CustomizeCallbackHolder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("CustomizeCallbackWrapper")
            .finish_non_exhaustive()
    }
}

/// Specifies style of generated code.
/// Generated files can be customized using this proto
/// or using `rustproto.proto` options.
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Customize {
    /// Make oneof enum public.
    pub(crate) expose_oneof: Option<bool>,
    /// When true all fields are public, and accessors are not generated
    pub(crate) expose_fields: Option<bool>,
    /// When false, `get_`, `set_`, `mut_` etc. accessors are not generated
    pub(crate) generate_accessors: Option<bool>,
    /// When false, `get_` is not generated even if `syntax = "proto2"`
    pub(crate) generate_getter: Option<bool>,
    /// Use `bytes::Bytes` for `bytes` fields
    pub(crate) carllerche_bytes_for_bytes: Option<bool>,
    /// Use `bytes::Bytes` for `string` fields
    pub(crate) carllerche_bytes_for_string: Option<bool>,
    /// Implement serde_derive for messages
    pub(crate) serde_derive: Option<bool>,
    /// When `serde_derive` is set, serde annotations will be guarded with `#[cfg(cfg, ...)]`.
    pub(crate) serde_derive_cfg: Option<String>,
    /// When `serde_derive` is set, use attribute rename_all
    pub(crate) serde_rename_all: Option<String>,
    /// Enable lite runtime
    pub(crate) lite_runtime: Option<bool>,
    /// Generate `mod.rs` in the output directory.
    ///
    /// This option allows inclusion of generated files from cargo output directory.
    ///
    /// This option will likely be on by default in rust-protobuf version 3.
    pub(crate) gen_mod_rs: Option<bool>,
    /// Used internally to generate protos bundled in protobuf crate
    /// like `descriptor.proto`
    pub(crate) inside_protobuf: Option<bool>,
    /// Dynamically alter generated code.
    pub(crate) callback: Option<CustomizeCallbackHolder>,
}

#[derive(Debug)]
pub enum CustomizeParseParameterError {
    EqNotFound,
    CannotParseBool,
    UnknownOptionName(String),
}

pub type CustomizeParseParameterResult<T> = Result<T, CustomizeParseParameterError>;

impl Customize {
    pub fn expose_oneof(mut self, expose_oneof: bool) -> Self {
        self.expose_oneof = Some(expose_oneof);
        self
    }

    pub fn expose_fields(mut self, expose_fields: bool) -> Self {
        self.expose_fields = Some(expose_fields);
        self
    }

    pub fn generate_accessors(mut self, generate_accessors: bool) -> Self {
        self.generate_accessors = Some(generate_accessors);
        self
    }

    pub fn generate_getter(mut self, generate_getter: bool) -> Self {
        self.generate_getter = Some(generate_getter);
        self
    }

    pub fn carllerche_bytes_for_bytes(mut self, carllerche_bytes_for_bytes: bool) -> Self {
        self.carllerche_bytes_for_bytes = Some(carllerche_bytes_for_bytes);
        self
    }

    pub fn carllerche_bytes_for_string(mut self, carllerche_bytes_for_string: bool) -> Self {
        self.carllerche_bytes_for_string = Some(carllerche_bytes_for_string);
        self
    }

    pub fn serde_derive(mut self, serde_derive: bool) -> Self {
        self.serde_derive = Some(serde_derive);
        self
    }

    pub fn serde_derive_cfg(mut self, serde_derive_cfg: &str) -> Self {
        self.serde_derive_cfg = Some(serde_derive_cfg.to_owned());
        self
    }

    pub fn serde_rename_all(mut self, serde_rename_all: &str) -> Self {
        self.serde_rename_all = Some(serde_rename_all.to_owned());
        self
    }

    pub fn lite_runtime(mut self, lite_runtime: bool) -> Self {
        self.lite_runtime = Some(lite_runtime);
        self
    }

    pub fn gen_mod_rs(mut self, gen_mod_rs: bool) -> Self {
        self.gen_mod_rs = Some(gen_mod_rs);
        self
    }

    pub fn inside_protobuf(mut self, inside_protobuf: bool) -> Self {
        self.inside_protobuf = Some(inside_protobuf);
        self
    }

    pub fn callback(mut self, callback: impl CustomizeCallback) -> Self {
        self.callback = Some(CustomizeCallbackHolder(Rc::new(callback)));
        self
    }

    /// Update fields of self with fields defined in other customize
    pub fn update_with(&mut self, that: &Customize) {
        if let Some(v) = that.expose_oneof {
            self.expose_oneof = Some(v);
        }
        if let Some(v) = that.expose_fields {
            self.expose_fields = Some(v);
        }
        if let Some(v) = that.generate_accessors {
            self.generate_accessors = Some(v);
        }
        if let Some(v) = that.generate_getter {
            self.generate_getter = Some(v);
        }
        if let Some(v) = that.carllerche_bytes_for_bytes {
            self.carllerche_bytes_for_bytes = Some(v);
        }
        if let Some(v) = that.carllerche_bytes_for_string {
            self.carllerche_bytes_for_string = Some(v);
        }
        if let Some(v) = that.serde_derive {
            self.serde_derive = Some(v);
        }
        if let Some(ref v) = that.serde_derive_cfg {
            self.serde_derive_cfg = Some(v.clone());
        }
        if let Some(ref v) = that.serde_rename_all {
            self.serde_rename_all = Some(v.clone());
        }
        if let Some(v) = that.lite_runtime {
            self.lite_runtime = Some(v);
        }
        if let Some(v) = that.gen_mod_rs {
            self.gen_mod_rs = Some(v);
        }
        if let Some(v) = that.inside_protobuf {
            self.inside_protobuf = Some(v);
        }
    }

    /// Update unset fields of self with fields from other customize
    pub fn set_defaults_from(&mut self, other: &Customize) {
        let mut tmp = other.clone();
        tmp.update_with(self);
        *self = tmp;
    }

    /// Parse customize options from a string passed via protoc flag.
    pub fn parse_from_parameter(parameter: &str) -> CustomizeParseParameterResult<Customize> {
        fn parse_bool(v: &str) -> CustomizeParseParameterResult<bool> {
            v.parse()
                .map_err(|_| CustomizeParseParameterError::CannotParseBool)
        }

        let mut r = Customize::default();
        for nv in parameter.split_whitespace() {
            let eq = match nv.find('=') {
                Some(eq) => eq,
                None => return Err(CustomizeParseParameterError::EqNotFound),
            };

            let n = &nv[..eq];
            let v = &nv[eq + 1..];

            if n == "expose_oneof" {
                r.expose_oneof = Some(parse_bool(v)?);
            } else if n == "expose_fields" {
                r.expose_fields = Some(parse_bool(v)?);
            } else if n == "generate_accessors" {
                r.generate_accessors = Some(parse_bool(v)?);
            } else if n == "generate_getter" {
                r.generate_getter = Some(parse_bool(v)?);
            } else if n == "carllerche_bytes_for_bytes" {
                r.carllerche_bytes_for_bytes = Some(parse_bool(v)?);
            } else if n == "carllerche_bytes_for_string" {
                r.carllerche_bytes_for_string = Some(parse_bool(v)?);
            } else if n == "serde_derive" {
                r.serde_derive = Some(parse_bool(v)?);
            } else if n == "serde_derive_cfg" {
                r.serde_derive_cfg = Some(v.to_owned());
            } else if n == "serde_rename_all" {
                r.serde_rename_all = Some(v.to_owned());
            } else if n == "lite_runtime" {
                r.lite_runtime = Some(parse_bool(v)?);
            } else if n == "gen_mod_rs" {
                r.gen_mod_rs = Some(parse_bool(v)?);
            } else if n == "inside_protobuf" {
                r.inside_protobuf = Some(parse_bool(v)?);
            } else {
                return Err(CustomizeParseParameterError::UnknownOptionName(
                    n.to_owned(),
                ));
            }
        }
        Ok(r)
    }
}

pub fn customize_from_rustproto_for_message(source: &MessageOptions) -> Customize {
    let expose_oneof = rustproto::exts::expose_oneof.get(source);
    let expose_fields = rustproto::exts::expose_fields.get(source);
    let generate_accessors = rustproto::exts::generate_accessors.get(source);
    let generate_getter = rustproto::exts::generate_getter.get(source);
    let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes.get(source);
    let carllerche_bytes_for_string = rustproto::exts::carllerche_bytes_for_string.get(source);
    let serde_derive = rustproto::exts::serde_derive.get(source);
    let serde_derive_cfg = rustproto::exts::serde_derive_cfg.get(source);
    let lite_runtime = None;
    let gen_mod_rs = None;
    let inside_protobuf = None;
    let serde_rename_all = None;
    let callback = None;
    Customize {
        expose_oneof,
        expose_fields,
        generate_accessors,
        generate_getter,
        carllerche_bytes_for_bytes,
        carllerche_bytes_for_string,
        serde_derive,
        serde_derive_cfg,
        serde_rename_all,
        lite_runtime,
        gen_mod_rs,
        inside_protobuf,
        callback,
    }
}

pub fn customize_from_rustproto_for_enum(source: &EnumOptions) -> Customize {
    let serde_rename_all = rustproto::exts::serde_rename_all.get(source);
    let mut r = Customize::default();
    r.serde_rename_all = serde_rename_all;
    return r;
}

pub fn customize_from_rustproto_for_field(source: &FieldOptions) -> Customize {
    let expose_oneof = None;
    let expose_fields = rustproto::exts::expose_fields_field.get(source);
    let generate_accessors = rustproto::exts::generate_accessors_field.get(source);
    let generate_getter = rustproto::exts::generate_getter_field.get(source);
    let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes_field.get(source);
    let carllerche_bytes_for_string =
        rustproto::exts::carllerche_bytes_for_string_field.get(source);
    let serde_rename_all = None;
    let serde_derive = None;
    let serde_derive_cfg = None;
    let lite_runtime = None;
    let gen_mod_rs = None;
    let inside_protobuf = None;
    let callback = None;
    Customize {
        expose_oneof,
        expose_fields,
        generate_accessors,
        generate_getter,
        carllerche_bytes_for_bytes,
        carllerche_bytes_for_string,
        serde_derive,
        serde_derive_cfg,
        serde_rename_all,
        lite_runtime,
        gen_mod_rs,
        inside_protobuf,
        callback,
    }
}

pub fn customize_from_rustproto_for_file(source: &FileOptions) -> Customize {
    let expose_oneof = rustproto::exts::expose_oneof_all.get(source);
    let expose_fields = rustproto::exts::expose_fields_all.get(source);
    let generate_accessors = rustproto::exts::generate_accessors_all.get(source);
    let generate_getter = rustproto::exts::generate_getter_all.get(source);
    let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes_all.get(source);
    let carllerche_bytes_for_string = rustproto::exts::carllerche_bytes_for_string_all.get(source);
    let serde_derive = rustproto::exts::serde_derive_all.get(source);
    let serde_derive_cfg = rustproto::exts::serde_derive_cfg_all.get(source);
    let lite_runtime = rustproto::exts::lite_runtime_all.get(source);
    let gen_mod_rs = None;
    let inside_protobuf = None;
    let serde_rename_all = None;
    let callback = None;
    Customize {
        expose_oneof,
        expose_fields,
        generate_accessors,
        generate_getter,
        carllerche_bytes_for_bytes,
        carllerche_bytes_for_string,
        serde_derive,
        serde_derive_cfg,
        serde_rename_all,
        lite_runtime,
        inside_protobuf,
        gen_mod_rs,
        callback,
    }
}
<commit_msg>Remove Customize::callback field<commit_after>pub(crate) mod by_path;
pub(crate) mod custom_attr;

use std::fmt;
use std::rc::Rc;

use protobuf::descriptor::EnumOptions;
use protobuf::descriptor::FieldOptions;
use protobuf::descriptor::FileOptions;
use protobuf::descriptor::MessageOptions;
use protobuf::reflect::EnumDescriptor;
use protobuf::reflect::FieldDescriptor;
use protobuf::reflect::MessageDescriptor;
use protobuf::reflect::OneofDescriptor;
use protobuf::rustproto;

/// Dynamic callback to customize code generation.
pub trait CustomizeCallback: 'static {
    fn customize_message(&self, message: &MessageDescriptor) -> String {
        let _ = message;
        String::new()
    }

    fn customize_field(&self, field: &FieldDescriptor) -> String {
        let _ = field;
        String::new()
    }

    fn customize_special_field(&self, message: &MessageDescriptor, field: &str) -> String {
        let _ = (message, field);
        String::new()
    }

    fn customize_enum(&self, enum_type: &EnumDescriptor) -> String {
        let _ = enum_type;
        String::new()
    }

    fn customize_oneof(&self, oneof: &OneofDescriptor) -> String {
        let _ = oneof;
        String::new()
    }
}

#[derive(Clone)]
pub(crate) struct CustomizeCallbackHolder(pub(crate) Rc<dyn CustomizeCallback>);

impl PartialEq for CustomizeCallbackHolder {
    fn eq(&self, other: &Self) -> bool {
        Rc::ptr_eq(&self.0, &other.0)
    }
}

impl fmt::Debug for CustomizeCallbackHolder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("CustomizeCallbackWrapper")
            .finish_non_exhaustive()
    }
}

/// Specifies style of generated code.
/// Generated files can be customized using this proto
/// or using `rustproto.proto` options.
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Customize {
    /// Make oneof enum public.
    pub(crate) expose_oneof: Option<bool>,
    /// When true all fields are public, and accessors are not generated
    pub(crate) expose_fields: Option<bool>,
    /// When false, `get_`, `set_`, `mut_` etc. accessors are not generated
    pub(crate) generate_accessors: Option<bool>,
    /// When false, `get_` is not generated even if `syntax = "proto2"`
    pub(crate) generate_getter: Option<bool>,
    /// Use `bytes::Bytes` for `bytes` fields
    pub(crate) carllerche_bytes_for_bytes: Option<bool>,
    /// Use `bytes::Bytes` for `string` fields
    pub(crate) carllerche_bytes_for_string: Option<bool>,
    /// Implement serde_derive for messages
    pub(crate) serde_derive: Option<bool>,
    /// When `serde_derive` is set, serde annotations will be guarded with `#[cfg(cfg, ...)]`.
    pub(crate) serde_derive_cfg: Option<String>,
    /// When `serde_derive` is set, use attribute rename_all
    pub(crate) serde_rename_all: Option<String>,
    /// Enable lite runtime
    pub(crate) lite_runtime: Option<bool>,
    /// Generate `mod.rs` in the output directory.
    ///
    /// This option allows inclusion of generated files from cargo output directory.
    ///
    /// This option will likely be on by default in rust-protobuf version 3.
    pub(crate) gen_mod_rs: Option<bool>,
    /// Used internally to generate protos bundled in protobuf crate
    /// like `descriptor.proto`
    pub(crate) inside_protobuf: Option<bool>,
}

#[derive(Debug)]
pub enum CustomizeParseParameterError {
    EqNotFound,
    CannotParseBool,
    UnknownOptionName(String),
}

pub type CustomizeParseParameterResult<T> = Result<T, CustomizeParseParameterError>;

impl Customize {
    pub fn expose_oneof(mut self, expose_oneof: bool) -> Self {
        self.expose_oneof = Some(expose_oneof);
        self
    }

    pub fn expose_fields(mut self, expose_fields: bool) -> Self {
        self.expose_fields = Some(expose_fields);
        self
    }

    pub fn generate_accessors(mut self, generate_accessors: bool) -> Self {
        self.generate_accessors = Some(generate_accessors);
        self
    }

    pub fn generate_getter(mut self, generate_getter: bool) -> Self {
        self.generate_getter = Some(generate_getter);
        self
    }

    pub fn carllerche_bytes_for_bytes(mut self, carllerche_bytes_for_bytes: bool) -> Self {
        self.carllerche_bytes_for_bytes = Some(carllerche_bytes_for_bytes);
        self
    }

    pub fn carllerche_bytes_for_string(mut self, carllerche_bytes_for_string: bool) -> Self {
        self.carllerche_bytes_for_string = Some(carllerche_bytes_for_string);
        self
    }

    pub fn serde_derive(mut self, serde_derive: bool) -> Self {
        self.serde_derive = Some(serde_derive);
        self
    }

    pub fn serde_derive_cfg(mut self, serde_derive_cfg: &str) -> Self {
        self.serde_derive_cfg = Some(serde_derive_cfg.to_owned());
        self
    }

    pub fn serde_rename_all(mut self, serde_rename_all: &str) -> Self {
        self.serde_rename_all = Some(serde_rename_all.to_owned());
        self
    }

    pub fn lite_runtime(mut self, lite_runtime: bool) -> Self {
        self.lite_runtime = Some(lite_runtime);
        self
    }

    pub fn gen_mod_rs(mut self, gen_mod_rs: bool) -> Self {
        self.gen_mod_rs = Some(gen_mod_rs);
        self
    }

    pub fn inside_protobuf(mut self, inside_protobuf: bool) -> Self {
        self.inside_protobuf = Some(inside_protobuf);
        self
    }

    /// Update fields of self with fields defined in other customize
    pub fn update_with(&mut self, that: &Customize) {
        if let Some(v) = that.expose_oneof {
            self.expose_oneof = Some(v);
        }
        if let Some(v) = that.expose_fields {
            self.expose_fields = Some(v);
        }
        if let Some(v) = that.generate_accessors {
            self.generate_accessors = Some(v);
        }
        if let Some(v) = that.generate_getter {
            self.generate_getter = Some(v);
        }
        if let Some(v) = that.carllerche_bytes_for_bytes {
            self.carllerche_bytes_for_bytes = Some(v);
        }
        if let Some(v) = that.carllerche_bytes_for_string {
            self.carllerche_bytes_for_string = Some(v);
        }
        if let Some(v) = that.serde_derive {
            self.serde_derive = Some(v);
        }
        if let Some(ref v) = that.serde_derive_cfg {
            self.serde_derive_cfg = Some(v.clone());
        }
        if let Some(ref v) = that.serde_rename_all {
            self.serde_rename_all = Some(v.clone());
        }
        if let Some(v) = that.lite_runtime {
            self.lite_runtime = Some(v);
        }
        if let Some(v) = that.gen_mod_rs {
            self.gen_mod_rs = Some(v);
        }
        if let Some(v) = that.inside_protobuf {
            self.inside_protobuf = Some(v);
        }
    }

    /// Update unset fields of self with fields from other customize
    pub fn set_defaults_from(&mut self, other: &Customize) {
        let mut tmp = other.clone();
        tmp.update_with(self);
        *self = tmp;
    }

    /// Parse customize options from a string passed via protoc flag.
    pub fn parse_from_parameter(parameter: &str) -> CustomizeParseParameterResult<Customize> {
        fn parse_bool(v: &str) -> CustomizeParseParameterResult<bool> {
            v.parse()
                .map_err(|_| CustomizeParseParameterError::CannotParseBool)
        }

        let mut r = Customize::default();
        for nv in parameter.split_whitespace() {
            let eq = match nv.find('=') {
                Some(eq) => eq,
                None => return Err(CustomizeParseParameterError::EqNotFound),
            };

            let n = &nv[..eq];
            let v = &nv[eq + 1..];

            if n == "expose_oneof" {
                r.expose_oneof = Some(parse_bool(v)?);
            } else if n == "expose_fields" {
                r.expose_fields = Some(parse_bool(v)?);
            } else if n == "generate_accessors" {
                r.generate_accessors = Some(parse_bool(v)?);
            } else if n == "generate_getter" {
                r.generate_getter = Some(parse_bool(v)?);
            } else if n == "carllerche_bytes_for_bytes" {
                r.carllerche_bytes_for_bytes = Some(parse_bool(v)?);
            } else if n == "carllerche_bytes_for_string" {
                r.carllerche_bytes_for_string = Some(parse_bool(v)?);
            } else if n == "serde_derive" {
                r.serde_derive = Some(parse_bool(v)?);
            } else if n == "serde_derive_cfg" {
                r.serde_derive_cfg = Some(v.to_owned());
            } else if n == "serde_rename_all" {
                r.serde_rename_all = Some(v.to_owned());
            } else if n == "lite_runtime" {
                r.lite_runtime = Some(parse_bool(v)?);
            } else if n == "gen_mod_rs" {
                r.gen_mod_rs = Some(parse_bool(v)?);
            } else if n == "inside_protobuf" {
                r.inside_protobuf = Some(parse_bool(v)?);
            } else {
                return Err(CustomizeParseParameterError::UnknownOptionName(
                    n.to_owned(),
                ));
            }
        }
        Ok(r)
    }
}

pub fn customize_from_rustproto_for_message(source: &MessageOptions) -> Customize {
    let expose_oneof = rustproto::exts::expose_oneof.get(source);
    let expose_fields = rustproto::exts::expose_fields.get(source);
    let generate_accessors = rustproto::exts::generate_accessors.get(source);
    let generate_getter = rustproto::exts::generate_getter.get(source);
    let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes.get(source);
    let carllerche_bytes_for_string = rustproto::exts::carllerche_bytes_for_string.get(source);
    let serde_derive = rustproto::exts::serde_derive.get(source);
    let serde_derive_cfg = rustproto::exts::serde_derive_cfg.get(source);
    let lite_runtime = None;
    let gen_mod_rs = None;
    let inside_protobuf = None;
    let serde_rename_all = None;
    Customize {
        expose_oneof,
        expose_fields,
        generate_accessors,
        generate_getter,
        carllerche_bytes_for_bytes,
        carllerche_bytes_for_string,
        serde_derive,
        serde_derive_cfg,
        serde_rename_all,
        lite_runtime,
        gen_mod_rs,
        inside_protobuf,
    }
}

pub fn customize_from_rustproto_for_enum(source: &EnumOptions) -> Customize {
    let serde_rename_all = rustproto::exts::serde_rename_all.get(source);
    let mut r = Customize::default();
    r.serde_rename_all = serde_rename_all;
    return r;
}

pub fn customize_from_rustproto_for_field(source: &FieldOptions) -> Customize {
    let expose_oneof = None;
    let expose_fields = rustproto::exts::expose_fields_field.get(source);
    let generate_accessors = rustproto::exts::generate_accessors_field.get(source);
    let generate_getter = rustproto::exts::generate_getter_field.get(source);
    let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes_field.get(source);
    let carllerche_bytes_for_string =
        rustproto::exts::carllerche_bytes_for_string_field.get(source);
    let serde_rename_all = None;
    let serde_derive = None;
    let serde_derive_cfg = None;
    let lite_runtime = None;
    let gen_mod_rs = None;
    let inside_protobuf = None;
    Customize {
        expose_oneof,
        expose_fields,
        generate_accessors,
        generate_getter,
        carllerche_bytes_for_bytes,
        carllerche_bytes_for_string,
        serde_derive,
        serde_derive_cfg,
        serde_rename_all,
        lite_runtime,
        gen_mod_rs,
        inside_protobuf,
    }
}

pub fn customize_from_rustproto_for_file(source: &FileOptions) -> Customize {
    let expose_oneof = rustproto::exts::expose_oneof_all.get(source);
    let expose_fields = rustproto::exts::expose_fields_all.get(source);
    let generate_accessors = rustproto::exts::generate_accessors_all.get(source);
    let generate_getter = rustproto::exts::generate_getter_all.get(source);
    let carllerche_bytes_for_bytes = rustproto::exts::carllerche_bytes_for_bytes_all.get(source);
    let carllerche_bytes_for_string = rustproto::exts::carllerche_bytes_for_string_all.get(source);
    let serde_derive = rustproto::exts::serde_derive_all.get(source);
    let serde_derive_cfg = rustproto::exts::serde_derive_cfg_all.get(source);
    let lite_runtime = rustproto::exts::lite_runtime_all.get(source);
    let gen_mod_rs = None;
    let inside_protobuf = None;
    let serde_rename_all = None;
    Customize {
        expose_oneof,
        expose_fields,
        generate_accessors,
        generate_getter,
        carllerche_bytes_for_bytes,
        carllerche_bytes_for_string,
        serde_derive,
        serde_derive_cfg,
        serde_rename_all,
        lite_runtime,
        inside_protobuf,
        gen_mod_rs,
    }
}
<|endoftext|>


<commit_before>use std::path::{Path,PathBuf};
use std::fmt;
use std::thread;
use store::{Store, Values};
use std::sync::{Arc,Mutex, Condvar};
use std::error::Error;
use std::io::{self, Write};
use yak_client::Datum;
use sqlite3::{self, DatabaseConnection, ResultRowAccess};

type SeqCVar = Arc<(Mutex<i64>, Condvar)>;

#[derive(Clone)]
pub struct SqliteStore {
  path:  PathBuf,
  seqnotify: SeqCVar
}

#[automatically_derived]
impl fmt::Debug for SqliteStore {
  fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
    write!(fmt, "SqliteStore{{ path: {:?} }}", self.path)
  }
}

struct SqliteIterator{
  db: DatabaseConnection,
  space: String,
  next_idx: i64,
  seqnotify: SeqCVar
}

#[derive(Debug)]
pub enum SqliteError {
  SqliteError(sqlite3::SqliteError),
  IoError(io::Error),
}

impl fmt::Display for SqliteError {
  fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
    match self {
      &SqliteError::SqliteError(ref err) => write!(fmt, "Store error:{}", err),
      &SqliteError::IoError(ref err) => write!(fmt, "IO error:{}", err),
    }
  }
}

impl Error for SqliteError {
  fn description(&self) -> &str {
    match self {
      &SqliteError::SqliteError(ref mdb) => mdb.description(),
      &SqliteError::IoError(ref err) => err.description(),
    }
  }
}

const EMPTY_SEQ_INIT : i64 = -1;

impl SqliteStore {
  pub fn new(path: &Path) -> Result<SqliteStore, SqliteError> {
    let mut buf = path.to_path_buf();
    buf.push("queues.sqlite");
    let store = SqliteStore { path: buf, seqnotify: Arc::new((Mutex::new(EMPTY_SEQ_INIT), Condvar::new())) };
    let mut db = try!(store.open_db());
    try!(db.exec("CREATE TABLE IF NOT EXISTS logs (
                 space           VARCHAR NOT NULL,
                 seq             INT NOT NULL,
                 key             BLOB NOT NULL,
                 value           BLOB NOT NULL,
                 PRIMARY KEY (space, seq)
               )"));
    Ok(store)
  }

  fn open_db(&self) -> Result<DatabaseConnection, SqliteError> {
    let res = sqlite3::access::open(&self.path.to_string_lossy(), None);
    match &res {
      &Ok(_) => trace!("Opened {:?}!", self.path),
      &Err(ref e) => error!("Open failed:{}", e)
    }
    let db = try!(res);
    Ok(db)
  }
}

impl Store for SqliteStore {
  type Iter = SqliteIterator;
  type Error = SqliteError;

  fn truncate(&self, space: &str) -> Result<(), SqliteError> {
    let db = try!(self.open_db());
    {
      let sql = "DELETE FROM logs WHERE space = ?1";
      trace!("{}@[{:?}]", sql, space);
      let mut stmt = try!(db.prepare(sql));
      try!(stmt.bind_text(1, space));
      let mut results = stmt.execute();
      while let Some(_) = try!(results.step()) { }
    }
    Ok(())
  }

  fn read(&self, space: &str, key: &[u8]) -> Result<Values, SqliteError> {
    trace!("#read:{:?}", key);

    let db = try!(self.open_db());
    let mut res = Vec::new();

    {
      let sql = "SELECT value FROM logs WHERE space = ?1 AND key = ?2";
      let mut stmt = try!(db.prepare(sql));
      trace!("{}@[{:?}, {:?}]", sql, space, key);
      try!(stmt.bind_text(1, space));
      try!(stmt.bind_blob(2, key));
      let mut results = stmt.execute();
      while let Some(mut row) = try!(results.step()) {
        let v = row.get(0);
        res.push(v)
      }
    }

    Ok(res)
  }

  fn write(&self, space: &str, key: &[u8], val: &[u8]) -> Result<(), SqliteError> {
    trace!("#write: {:?}/{:?}={:?}", space, key, val);
    let db = try!(self.open_db());

    let idx = {
      try!(retry_on_locked(|| {
        let sql = "SELECT seq+1 FROM logs WHERE space = ? ORDER BY seq DESC LIMIT 1";
        trace!("{}@[{:?}]", sql, space);
        let mut stmt = try!(db.prepare(sql));
        try!(stmt.bind_text(1, space));
        let mut results = stmt.execute();
        let mut idx = 0;
        while let Some(mut row) = try!(results.step()) {
          idx = row.get(0);
        }
        Ok(idx)
      }))
    };

    try!(retry_on_locked(|| {
      let sql = "INSERT INTO logs (seq, space, key, value) VALUES (?, ?, ?, ?)";
      trace!("{}@[{:?}, {:?}, {:?}, {:?}]", sql, idx, space, key, val);
      let mut ins = try!(db.prepare(sql));
      try!(ins.bind_int64(1, idx));
      try!(ins.bind_text(2, space));
      try!(ins.bind_blob(3, key));
      try!(ins.bind_blob(4, val));
      let mut results = ins.execute();

      while let Some(_) = try!(results.step()) { }
      Ok(())
    }));

    {
      debug!("Notify of new idx: {}", idx);
      let &(ref lock, ref cvar) = &*self.seqnotify;
      let mut idx_ref = lock.lock().unwrap();
      debug!("Obtained lock! {} → {}", &*idx_ref, idx);
      *idx_ref = idx;
      cvar.notify_all();
    }

    Ok(())
  }

  fn subscribe(&self, space: &str) -> Result<Self::Iter, SqliteError> {
    trace!("#subscribe: {:?}", space);
    let db = try!(self.open_db());
    Ok(SqliteIterator{ db: db, space: space.to_string(), next_idx: 0, seqnotify: self.seqnotify.clone() })
  }
}

fn retry_on_locked<T, F>(mut f: F) -> Result<T, sqlite3::SqliteError> where F: FnMut() -> Result<T, sqlite3::SqliteError> {
  let mut backoff = 1;
  loop {
    let r = f();
    match r {
      Err(sqlite3::SqliteError { kind, .. }) if kind == sqlite3::SqliteErrorCode::SQLITE_LOCKED || kind == sqlite3::SqliteErrorCode::SQLITE_BUSY => {
        debug!("retry-redo: {:?}; sleep: {}ms", kind, backoff);
        thread::sleep_ms(backoff);
        backoff <<= 1;
      },
      Ok(_) => return r,
      Err(e) => return Err(e),
    }
  }
}

impl SqliteIterator {
  fn fetch_next(&mut self) -> Result<Option<Datum>, SqliteError> {
    trace!("#fetch_next: {:?}", self);
    loop {
      let query = retry_on_locked(|| {
        let sql = "SELECT seq, key, value FROM logs WHERE space = ? AND seq = ? ORDER BY seq ASC /* LIMIT 1 */";
        trace!("{}@[{}, {}]", sql, self.space, self.next_idx);
        let mut q = try!(self.db.prepare(sql));
        try!(q.bind_text(1, &self.space));
        try!(q.bind_int64(2, self.next_idx));
        let mut results = q.execute();

        let mut answer = None;
        while let Some(mut row) = try!(results.step()) {
          let seq : i64 = row.get(0);
          let key = row.get(1);
          let value = row.get(2);
          let datum = Datum { key: key, content: value };
          debug!("Result:{} / @{:?} {:?}", row.column_count(), seq, datum);
          self.next_idx = seq+1;
          answer = Some(datum);
        }
        Ok(answer)
      });
      match query {
        Ok(None) => (),
        ret => return ret.map_err(From::from),
      }

      {
        let &(ref lock, ref cvar) = &*self.seqnotify;
        trace!("Nothing found: @{:?}; waiting", self);
        let mut seq = lock.lock().unwrap();
        while self.next_idx > *seq {
          trace!("Wait! want next-idx:{:?} > current:{:?}", &*seq, self.next_idx);
          let (lockp, _no_timeout) = cvar.wait_timeout_ms(seq, 1000).unwrap();
          seq = lockp;
          trace!("Awoken! current:{:?}; expected next-idx:{:?}; timeout? {:?}", &*seq, self.next_idx, _no_timeout);
        }
      }
    }
  }

}
impl Iterator for SqliteIterator {
  type Item = Datum;

  fn next(&mut self) -> Option<Self::Item> {
    trace!("Iterator#next {:?}", self);

    self.fetch_next().unwrap()
  }
}

impl fmt::Debug for SqliteIterator {
  fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
    write!(fmt, "SqliteIterator{{ db: <db>, next_idx:{:?}, space:{:?} }}",
      &self.next_idx, &self.space)
  }
}
impl From<sqlite3::SqliteError> for SqliteError {
  fn from(err: sqlite3::SqliteError) -> SqliteError {
    SqliteError::SqliteError(err)
  }
}

impl From<io::Error> for SqliteError {
  fn from(err: io::Error) -> SqliteError {
    SqliteError::IoError(err)
  }
}

#[cfg(test)]
mod test {
  use super::SqliteStore;
  use store::test::TestableStore;
  use quickcheck::TestResult;
  use rand::Rng;
  use std::path::PathBuf;
  use std::fs;

  impl TestableStore for SqliteStore {
    fn build() -> SqliteStore {
      let mut rng = ::rand::thread_rng();
      let p = PathBuf::from(format!("target/sqlite3_store/{}", rng.gen_ascii_chars().take(16).collect::<String>()));
      fs::create_dir_all(&p).unwrap();
      SqliteStore::new(&p).unwrap()
    }
  }

  build_store_tests!(SqliteStore);
}
<commit_msg>Trace subscription watermarks.<commit_after>use std::path::{Path,PathBuf};
use std::fmt;
use std::thread;
use store::{Store, Values};
use std::sync::{Arc,Mutex, Condvar};
use std::error::Error;
use std::io::{self, Write};
use yak_client::Datum;
use sqlite3::{self, DatabaseConnection, ResultRowAccess};

type SeqCVar = Arc<(Mutex<i64>, Condvar)>;

#[derive(Clone)]
pub struct SqliteStore {
  path:  PathBuf,
  seqnotify: SeqCVar
}

#[automatically_derived]
impl fmt::Debug for SqliteStore {
  fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
    write!(fmt, "SqliteStore{{ path: {:?} }}", self.path)
  }
}

struct SqliteIterator{
  db: DatabaseConnection,
  space: String,
  next_idx: i64,
  seqnotify: SeqCVar
}

#[derive(Debug)]
pub enum SqliteError {
  SqliteError(sqlite3::SqliteError),
  IoError(io::Error),
}

impl fmt::Display for SqliteError {
  fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
    match self {
      &SqliteError::SqliteError(ref err) => write!(fmt, "Store error:{}", err),
      &SqliteError::IoError(ref err) => write!(fmt, "IO error:{}", err),
    }
  }
}

impl Error for SqliteError {
  fn description(&self) -> &str {
    match self {
      &SqliteError::SqliteError(ref mdb) => mdb.description(),
      &SqliteError::IoError(ref err) => err.description(),
    }
  }
}

const EMPTY_SEQ_INIT : i64 = -1;

impl SqliteStore {
  pub fn new(path: &Path) -> Result<SqliteStore, SqliteError> {
    let mut buf = path.to_path_buf();
    buf.push("queues.sqlite");
    let store = SqliteStore { path: buf, seqnotify: Arc::new((Mutex::new(EMPTY_SEQ_INIT), Condvar::new())) };
    let mut db = try!(store.open_db());
    try!(db.exec("CREATE TABLE IF NOT EXISTS logs (
                 space           VARCHAR NOT NULL,
                 seq             INT NOT NULL,
                 key             BLOB NOT NULL,
                 value           BLOB NOT NULL,
                 PRIMARY KEY (space, seq)
               )"));
    Ok(store)
  }

  fn open_db(&self) -> Result<DatabaseConnection, SqliteError> {
    let res = sqlite3::access::open(&self.path.to_string_lossy(), None);
    match &res {
      &Ok(_) => trace!("Opened {:?}!", self.path),
      &Err(ref e) => error!("Open failed:{}", e)
    }
    let db = try!(res);
    Ok(db)
  }
}

impl Store for SqliteStore {
  type Iter = SqliteIterator;
  type Error = SqliteError;

  fn truncate(&self, space: &str) -> Result<(), SqliteError> {
    let db = try!(self.open_db());
    {
      let sql = "DELETE FROM logs WHERE space = ?1";
      trace!("{}@[{:?}]", sql, space);
      let mut stmt = try!(db.prepare(sql));
      try!(stmt.bind_text(1, space));
      let mut results = stmt.execute();
      while let Some(_) = try!(results.step()) { }
    }
    Ok(())
  }

  fn read(&self, space: &str, key: &[u8]) -> Result<Values, SqliteError> {
    trace!("#read:{:?}", key);

    let db = try!(self.open_db());
    let mut res = Vec::new();

    {
      let sql = "SELECT value FROM logs WHERE space = ?1 AND key = ?2";
      let mut stmt = try!(db.prepare(sql));
      trace!("{}@[{:?}, {:?}]", sql, space, key);
      try!(stmt.bind_text(1, space));
      try!(stmt.bind_blob(2, key));
      let mut results = stmt.execute();
      while let Some(mut row) = try!(results.step()) {
        let v = row.get(0);
        res.push(v)
      }
    }

    Ok(res)
  }

  fn write(&self, space: &str, key: &[u8], val: &[u8]) -> Result<(), SqliteError> {
    trace!("#write: {:?}/{:?}={:?}", space, key, val);
    let db = try!(self.open_db());

    let idx = {
      try!(retry_on_locked(|| {
        let sql = "SELECT seq+1 FROM logs WHERE space = ? ORDER BY seq DESC LIMIT 1";
        trace!("{}@[{:?}]", sql, space);
        let mut stmt = try!(db.prepare(sql));
        try!(stmt.bind_text(1, space));
        let mut results = stmt.execute();
        let mut idx = 0;
        while let Some(mut row) = try!(results.step()) {
          idx = row.get(0);
        }
        Ok(idx)
      }))
    };

    try!(retry_on_locked(|| {
      let sql = "INSERT INTO logs (seq, space, key, value) VALUES (?, ?, ?, ?)";
      trace!("{}@[{:?}, {:?}, {:?}, {:?}]", sql, idx, space, key, val);
      let mut ins = try!(db.prepare(sql));
      try!(ins.bind_int64(1, idx));
      try!(ins.bind_text(2, space));
      try!(ins.bind_blob(3, key));
      try!(ins.bind_blob(4, val));
      let mut results = ins.execute();

      while let Some(_) = try!(results.step()) { }
      Ok(())
    }));

    {
      debug!("Notify of new idx: {}", idx);
      let &(ref lock, ref cvar) = &*self.seqnotify;
      let mut idx_ref = lock.lock().unwrap();
      debug!("Obtained lock! {} → {}", &*idx_ref, idx);
      *idx_ref = idx;
      cvar.notify_all();
    }

    Ok(())
  }

  fn subscribe(&self, space: &str) -> Result<Self::Iter, SqliteError> {
    trace!("#subscribe: {:?}", space);
    let db = try!(self.open_db());
    Ok(SqliteIterator{ db: db, space: space.to_string(), next_idx: 0, seqnotify: self.seqnotify.clone() })
  }
}

fn retry_on_locked<T, F>(mut f: F) -> Result<T, sqlite3::SqliteError> where F: FnMut() -> Result<T, sqlite3::SqliteError> {
  let mut backoff = 1;
  loop {
    let r = f();
    match r {
      Err(sqlite3::SqliteError { kind, .. }) if kind == sqlite3::SqliteErrorCode::SQLITE_LOCKED || kind == sqlite3::SqliteErrorCode::SQLITE_BUSY => {
        debug!("retry-redo: {:?}; sleep: {}ms", kind, backoff);
        thread::sleep_ms(backoff);
        backoff <<= 1;
      },
      Ok(_) => return r,
      Err(e) => return Err(e),
    }
  }
}

impl SqliteIterator {
  fn fetch_next(&mut self) -> Result<Option<Datum>, SqliteError> {
    trace!("#fetch_next: {:?}", self);
    loop {
      let query = retry_on_locked(|| {
        let sql = "SELECT seq, key, value FROM logs WHERE space = ? AND seq = ? ORDER BY seq ASC /* LIMIT 1 */";
        let mut q = try!(self.db.prepare(sql));
        trace!("{}@[{}, {}]", sql, self.space, self.next_idx);
        try!(q.bind_text(1, &self.space));
        try!(q.bind_int64(2, self.next_idx));
        let mut results = q.execute();

        let mut answer = None;
        while let Some(mut row) = try!(results.step()) {
          let seq : i64 = row.get(0);
          let key = row.get(1);
          let value = row.get(2);
          let datum = Datum { key: key, content: value };
          debug!("Result:{} / @{:?} {:?}", row.column_count(), seq, datum);
          self.next_idx = seq+1;
          answer = Some(datum);
        }
        Ok(answer)
      });
      match query {
        Ok(None) => (),
        ret => return ret.map_err(From::from),
      }

      {
        let &(ref lock, ref cvar) = &*self.seqnotify;
        trace!("Nothing found: @{:?}; waiting", self);
        let mut seq = lock.lock().unwrap();
        trace!("Current seq: {:?}; db seq: {:?};", self.next_idx, *seq);
        while self.next_idx > *seq {
          trace!("Wait! want next-idx:{:?} > current:{:?}", &*seq, self.next_idx);
          let (lockp, _no_timeout) = cvar.wait_timeout_ms(seq, 1000).unwrap();
          seq = lockp;
          trace!("Awoken! current:{:?}; expected next-idx:{:?}; timeout? {:?}", &*seq, self.next_idx, _no_timeout);
        }
      }
    }
  }

}
impl Iterator for SqliteIterator {
  type Item = Datum;

  fn next(&mut self) -> Option<Self::Item> {
    trace!("Iterator#next {:?}", self);

    self.fetch_next().unwrap()
  }
}

impl fmt::Debug for SqliteIterator {
  fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
    write!(fmt, "SqliteIterator{{ db: <db>, next_idx:{:?}, space:{:?} }}",
      &self.next_idx, &self.space)
  }
}
impl From<sqlite3::SqliteError> for SqliteError {
  fn from(err: sqlite3::SqliteError) -> SqliteError {
    SqliteError::SqliteError(err)
  }
}

impl From<io::Error> for SqliteError {
  fn from(err: io::Error) -> SqliteError {
    SqliteError::IoError(err)
  }
}

#[cfg(test)]
mod test {
  use super::SqliteStore;
  use store::test::TestableStore;
  use quickcheck::TestResult;
  use rand::Rng;
  use std::path::PathBuf;
  use std::fs;

  impl TestableStore for SqliteStore {
    fn build() -> SqliteStore {
      let mut rng = ::rand::thread_rng();
      let p = PathBuf::from(format!("target/sqlite3_store/{}", rng.gen_ascii_chars().take(16).collect::<String>()));
      fs::create_dir_all(&p).unwrap();
      SqliteStore::new(&p).unwrap()
    }
  }

  build_store_tests!(SqliteStore);
}
<|endoftext|>


<commit_before>use std::libc::*;

use color::*;
use ffi::*;
pub use self::bitmap_flag::*;

fn target_bitmap_check(desired_target: *mut ALLEGRO_BITMAP)
{
	unsafe
	{
		if al_get_target_bitmap() != desired_target
		{
			al_set_target_bitmap(desired_target)
		}
	}
}

flag_type!(
	mod bitmap_flag
	{
		BitmapDrawingFlags
		{
			FLIP_NONE = 0x1,
			FLIP_HORIZONTAL = 0x2,
			FLIP_VERTICAL = 0x4
		}
	}
)

pub trait BitmapLike
{
	fn get_bitmap(&self) -> *mut ALLEGRO_BITMAP;
}

pub trait DrawTarget
{
	fn get_target_bitmap(&self) -> *mut ALLEGRO_BITMAP;
}

pub trait CoreDrawing : DrawTarget
{
	fn clear_to_color(&self, color: Color)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_clear_to_color(*color);
		}
	}

	fn draw_pixel(&self, x: float, y: float, color: Color)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_pixel(x as c_float, y as c_float, *color);
		}
	}

	fn draw_bitmap<T: BitmapLike>(&self, bitmap: &T, dx: float, dy: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_bitmap(bitmap.get_bitmap(), dx as c_float, dy as c_float, (flags.get() << 1) as c_int);
		}
	}

	fn draw_bitmap_region<T: BitmapLike>(&self, bitmap: &T, sx: float, sy: float, sw: float, sh: float, dx: float, dy: float, flags: BitmapDrawingFlags)
    {
        target_bitmap_check(self.get_target_bitmap());
        unsafe
        {
            al_draw_bitmap_region(bitmap.get_bitmap(), sx as c_float, sy as c_float, sw as c_float, sh as c_float, dx as c_float, dy as c_float, (flags.get() << 1) as c_int);
        }
    }

	fn draw_scaled_bitmap<T: BitmapLike>(&self, bitmap: &T, sx: float, sy: float, sw: float, sh: float, dx: float, dy: float, dw: float, dh: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_scaled_bitmap(bitmap.get_bitmap(), sx as c_float, sy as c_float, sw as c_float, sh as c_float, dx as c_float, dy as c_float, dw as c_float, dh as c_float, (flags.get() << 1) as c_int);
		}
	}

	fn draw_rotated_bitmap<T: BitmapLike>(&self, bitmap: &T, cx: float, cy: float, dx: float, dy: float, angle: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_rotated_bitmap(bitmap.get_bitmap(), cx as c_float, cy as c_float, dx as c_float, dy as c_float, angle as c_float, (flags.get() << 1) as c_int);
		}
	}

	fn draw_scaled_rotated_bitmap<T: BitmapLike>(&self, bitmap: &T, cx: float, cy: float, dx: float, dy: float, xscale: float, yscale: float, angle: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_scaled_rotated_bitmap(bitmap.get_bitmap(), cx as c_float, cy as c_float, dx as c_float, dy as c_float, xscale as c_float, yscale as c_float, angle as c_float, (flags.get() << 1) as c_int);
		}
	}

	fn draw_tinted_bitmap<T: BitmapLike>(&self, bitmap: &T, tint: Color, dx: float, dy: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_tinted_bitmap(bitmap.get_bitmap(), *tint, dx as c_float, dy as c_float, (flags.get() << 1) as c_int);
		}
	}

	fn draw_tinted_bitmap_region<T: BitmapLike>(&self, bitmap: &T, tint: Color, sx: float, sy: float, sw: float, sh: float, dx: float, dy: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_tinted_bitmap_region(bitmap.get_bitmap(), *tint, sx as c_float, sy as c_float, sw as c_float, sh as c_float, dx as c_float, dy as c_float, (flags.get() << 1) as c_int);
		}
	}

	fn draw_tinted_scaled_bitmap<T: BitmapLike>(&self, bitmap: &T, tint: Color, sx: float, sy: float, sw: float, sh: float, dx: float, dy: float, dw: float, dh: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_tinted_scaled_bitmap(bitmap.get_bitmap(), *tint, sx as c_float, sy as c_float, sw as c_float, sh as c_float, dx as c_float, dy as c_float, dw as c_float, dh as c_float, (flags.get() << 1) as c_int);
		}
	}

	fn draw_tinted_rotated_bitmap<T: BitmapLike>(&self, bitmap: &T, tint: Color, cx: float, cy: float, dx: float, dy: float, angle: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_tinted_rotated_bitmap(bitmap.get_bitmap(), *tint, cx as c_float, cy as c_float, dx as c_float, dy as c_float, angle as c_float, (flags.get() << 1) as c_int);
		}
	}

	fn draw_tinted_scaled_rotated_bitmap<T: BitmapLike>(&self, bitmap: &T, tint: Color, cx: float, cy: float, dx: float, dy: float, xscale: float, yscale: float, angle: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_tinted_scaled_rotated_bitmap(bitmap.get_bitmap(), *tint, cx as c_float, cy as c_float, dx as c_float, dy as c_float, xscale as c_float, yscale as c_float, angle as c_float, (flags.get() << 1) as c_int);
		}
	}

	fn draw_tinted_scaled_rotated_bitmap_region<T: BitmapLike>(&self, bitmap: &T, sx: float, sy: float, sw: float, sh: float, tint: Color, cx: float, cy: float, dx: float, dy: float, xscale: float, yscale: float, angle: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_tinted_scaled_rotated_bitmap_region(bitmap.get_bitmap(), sx as c_float, sy as c_float, sw as c_float, sh as c_float, *tint, cx as c_float, cy as c_float, dx as c_float, dy as c_float, xscale as c_float, yscale as c_float, angle as c_float, (flags.get() << 1) as c_int);
		}
	}
}
<commit_msg>Shifts were wrong<commit_after>use std::libc::*;

use color::*;
use ffi::*;
pub use self::bitmap_flag::*;

fn target_bitmap_check(desired_target: *mut ALLEGRO_BITMAP)
{
	unsafe
	{
		if al_get_target_bitmap() != desired_target
		{
			al_set_target_bitmap(desired_target)
		}
	}
}

flag_type!(
	mod bitmap_flag
	{
		BitmapDrawingFlags
		{
			FLIP_NONE = 0x1,
			FLIP_HORIZONTAL = 0x2,
			FLIP_VERTICAL = 0x4
		}
	}
)

pub trait BitmapLike
{
	fn get_bitmap(&self) -> *mut ALLEGRO_BITMAP;
}

pub trait DrawTarget
{
	fn get_target_bitmap(&self) -> *mut ALLEGRO_BITMAP;
}

pub trait CoreDrawing : DrawTarget
{
	fn clear_to_color(&self, color: Color)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_clear_to_color(*color);
		}
	}

	fn draw_pixel(&self, x: float, y: float, color: Color)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_pixel(x as c_float, y as c_float, *color);
		}
	}

	fn draw_bitmap<T: BitmapLike>(&self, bitmap: &T, dx: float, dy: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_bitmap(bitmap.get_bitmap(), dx as c_float, dy as c_float, (flags.get() >> 1) as c_int);
		}
	}

	fn draw_bitmap_region<T: BitmapLike>(&self, bitmap: &T, sx: float, sy: float, sw: float, sh: float, dx: float, dy: float, flags: BitmapDrawingFlags)
    {
        target_bitmap_check(self.get_target_bitmap());
        unsafe
        {
            al_draw_bitmap_region(bitmap.get_bitmap(), sx as c_float, sy as c_float, sw as c_float, sh as c_float, dx as c_float, dy as c_float, (flags.get() >> 1) as c_int);
        }
    }

	fn draw_scaled_bitmap<T: BitmapLike>(&self, bitmap: &T, sx: float, sy: float, sw: float, sh: float, dx: float, dy: float, dw: float, dh: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_scaled_bitmap(bitmap.get_bitmap(), sx as c_float, sy as c_float, sw as c_float, sh as c_float, dx as c_float, dy as c_float, dw as c_float, dh as c_float, (flags.get() >> 1) as c_int);
		}
	}

	fn draw_rotated_bitmap<T: BitmapLike>(&self, bitmap: &T, cx: float, cy: float, dx: float, dy: float, angle: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_rotated_bitmap(bitmap.get_bitmap(), cx as c_float, cy as c_float, dx as c_float, dy as c_float, angle as c_float, (flags.get() >> 1) as c_int);
		}
	}

	fn draw_scaled_rotated_bitmap<T: BitmapLike>(&self, bitmap: &T, cx: float, cy: float, dx: float, dy: float, xscale: float, yscale: float, angle: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_scaled_rotated_bitmap(bitmap.get_bitmap(), cx as c_float, cy as c_float, dx as c_float, dy as c_float, xscale as c_float, yscale as c_float, angle as c_float, (flags.get() >> 1) as c_int);
		}
	}

	fn draw_tinted_bitmap<T: BitmapLike>(&self, bitmap: &T, tint: Color, dx: float, dy: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_tinted_bitmap(bitmap.get_bitmap(), *tint, dx as c_float, dy as c_float, (flags.get() >> 1) as c_int);
		}
	}

	fn draw_tinted_bitmap_region<T: BitmapLike>(&self, bitmap: &T, tint: Color, sx: float, sy: float, sw: float, sh: float, dx: float, dy: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_tinted_bitmap_region(bitmap.get_bitmap(), *tint, sx as c_float, sy as c_float, sw as c_float, sh as c_float, dx as c_float, dy as c_float, (flags.get() >> 1) as c_int);
		}
	}

	fn draw_tinted_scaled_bitmap<T: BitmapLike>(&self, bitmap: &T, tint: Color, sx: float, sy: float, sw: float, sh: float, dx: float, dy: float, dw: float, dh: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_tinted_scaled_bitmap(bitmap.get_bitmap(), *tint, sx as c_float, sy as c_float, sw as c_float, sh as c_float, dx as c_float, dy as c_float, dw as c_float, dh as c_float, (flags.get() >> 1) as c_int);
		}
	}

	fn draw_tinted_rotated_bitmap<T: BitmapLike>(&self, bitmap: &T, tint: Color, cx: float, cy: float, dx: float, dy: float, angle: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_tinted_rotated_bitmap(bitmap.get_bitmap(), *tint, cx as c_float, cy as c_float, dx as c_float, dy as c_float, angle as c_float, (flags.get() >> 1) as c_int);
		}
	}

	fn draw_tinted_scaled_rotated_bitmap<T: BitmapLike>(&self, bitmap: &T, tint: Color, cx: float, cy: float, dx: float, dy: float, xscale: float, yscale: float, angle: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_tinted_scaled_rotated_bitmap(bitmap.get_bitmap(), *tint, cx as c_float, cy as c_float, dx as c_float, dy as c_float, xscale as c_float, yscale as c_float, angle as c_float, (flags.get() >> 1) as c_int);
		}
	}

	fn draw_tinted_scaled_rotated_bitmap_region<T: BitmapLike>(&self, bitmap: &T, sx: float, sy: float, sw: float, sh: float, tint: Color, cx: float, cy: float, dx: float, dy: float, xscale: float, yscale: float, angle: float, flags: BitmapDrawingFlags)
	{
		target_bitmap_check(self.get_target_bitmap());
		unsafe
		{
			al_draw_tinted_scaled_rotated_bitmap_region(bitmap.get_bitmap(), sx as c_float, sy as c_float, sw as c_float, sh as c_float, *tint, cx as c_float, cy as c_float, dx as c_float, dy as c_float, xscale as c_float, yscale as c_float, angle as c_float, (flags.get() >> 1) as c_int);
		}
	}
}
<|endoftext|>


<commit_before>/// Strongly borrowed from TypedArena
/// Differs in growth strategy (non-doubling)
/// And only for variable-sized strings

use std::borrow::Borrow;
use std::cell::{Cell,RefCell};
use std::cmp::max;
use std::collections::LinkedList;
use std::collections::hash_map::HashMap;
use std::default::Default;
use std::ops::Deref;
use std::slice;
use std::{fmt,hash,mem,ptr,str};

struct Chunk {
    start: *mut u8,
    capacity: usize,
}

impl Chunk {
    fn new(capacity: usize) -> Chunk {
        let mut slab: Vec<u8> = Vec::with_capacity(capacity);
        let start = slab.as_mut_ptr();

        // We will manually track the buffer and then drop it ourselves
        unsafe {
            mem::forget(slab);
        }

        Chunk {
            start: start,
            capacity: capacity,
        }
    }

    // Returns a pointer to the beginning of the allocated space.
    #[inline]
    fn start(&self) -> *const u8 {
        self.start as *const u8
    }

    // Returns a pointer to the end of the allocated space.
    #[inline]
    fn end(&self) -> *const u8 {
        unsafe { self.start().offset(self.capacity as isize) }
    }
}

impl Drop for Chunk {
    fn drop(&mut self) {
        // This is safe because we only ever store u8, which doesn't
        // have a destructor. This means the len doesn't matter, only
        // the capacity.
        unsafe {
            Vec::from_raw_parts(self.start, self.capacity, self.capacity);
        }
    }
}

#[allow(raw_pointer_derive)]
#[derive(Copy,Clone)]
pub struct InternedString {
    data: *const u8,
    len: usize,
}

impl InternedString {
    fn from_parts(data: *const u8, len: usize) -> InternedString {
        InternedString {
            data: data,
            len: len,
        }
    }

    pub fn from_str(s: &str) -> InternedString {
        let bytes: &[u8] = s.as_bytes();
        InternedString {
            data: bytes.as_ptr(),
            len: bytes.len(),
        }
    }

    pub fn as_slice<'s>(&self) -> &'s str {
        unsafe {
            let bytes = slice::from_raw_parts(self.data, self.len);
            str::from_utf8_unchecked(bytes)
        }
    }
}

impl fmt::Debug for InternedString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}

impl PartialEq for InternedString {
    fn eq(&self, other: &InternedString) -> bool {
        self.as_slice().eq(other.as_slice())
    }
}

impl PartialEq<str> for InternedString {
    fn eq(&self, other: &str) -> bool {
        self.as_slice().eq(other)
    }
}

impl Eq for InternedString {}

impl hash::Hash for InternedString {
    fn hash<H>(&self, state: &mut H)
        where H: hash::Hasher
    {
        self.as_slice().hash(state)
    }
}

impl Borrow<str> for InternedString {
    fn borrow(&self) -> &str {
        self.as_slice()
    }
}

impl Deref for InternedString {
    type Target = str;

    fn deref(&self) -> &str {
        self.as_slice()
    }
}

pub struct StringPool {
    start: Cell<*mut u8>,
    end: Cell<*const u8>,
    chunks: RefCell<LinkedList<Chunk>>,
    index: RefCell<HashMap<InternedString, InternedString>>,
}

static CAPACITY: usize = 10240;

impl StringPool {
    pub fn new() -> StringPool {
        StringPool{
            start: Cell::new(ptr::null_mut()),
            end: Cell::new(ptr::null()),
            chunks: RefCell::new(LinkedList::new()),
            index: RefCell::new(Default::default()),
        }
    }

    pub fn intern<'s>(&'s self, s: &str) -> &'s str {
        if s == "" { return ""; }

        let search_string = InternedString::from_str(s);

        let mut index = self.index.borrow_mut();
        let interned_str = *index.entry(search_string).or_insert_with(|| self.do_intern(s));

        // The lifetime is really matched to us
        unsafe { mem::transmute(interned_str) }
    }

    fn do_intern(&self, s: &str) -> InternedString {
        self.ensure_capacity(s.len());
        self.store(s)
    }

    fn ensure_capacity(&self, str_len: usize) {
        let remaining = self.end.get() as usize - self.start.get() as usize;
        if remaining < str_len {
            self.allocate_another(max(CAPACITY, str_len))
        }
    }

    fn allocate_another(&self, capacity: usize) {
        let chunk = Chunk::new(capacity);
        self.start.set(chunk.start() as *mut u8);
        self.end.set(chunk.end());
        self.chunks.borrow_mut().push_front(chunk);
    }

    fn store(&self, s: &str) -> InternedString {
        let str_start = s.as_bytes().as_ptr();
        let str_len = s.len();

        unsafe {
            ptr::copy_nonoverlapping(str_start, self.start.get(), str_len);

            // Rebuild the string from our buffer
            let interned_str = InternedString::from_parts(self.start.get() as *const u8, str_len);

            // Increase current pointer
            self.start.set(self.start.get().offset(str_len as isize));

            interned_str
        }
    }
}

#[cfg(test)]
mod test {
    use std::borrow::ToOwned;

    use super::StringPool;

    #[test]
    fn keeps_the_same_string() {
        let s = StringPool::new();

        let interned = s.intern("hello");

        assert_eq!(interned, "hello");
    }

    #[test]
    fn does_not_reuse_the_pointer_of_the_input() {
        let s = StringPool::new();
        let input = "hello";

        let interned = s.intern(input);

        assert!(
            input.as_bytes().as_ptr() !=
            interned.as_bytes().as_ptr()
        );
    }

    #[test]
    fn reuses_the_pointer_for_repeated_input() {
        let s = StringPool::new();

        let interned1 = s.intern("world");
        let interned2 = s.intern("world");

        assert_eq!(
            interned1.as_bytes().as_ptr(),
            interned2.as_bytes().as_ptr()
        );
    }

    #[test]
    #[cfg(feature = "compile_failure")]
    fn string_cannot_outlive_the_pool() {
        let z = {
            let s = StringPool::new();
            s.intern("hello")
        };
    }

    #[test]
    fn ignores_the_lifetime_of_the_input_string() {
        let s = StringPool::new();

        let interned = {
            let allocated_string = "green".to_owned();
            s.intern(&allocated_string)
        };

        // allocated_string is gone now, but we should be able to
        // access the result value until the storage goes away.

        assert_eq!(interned, "green");
    }

    #[test]
    fn can_be_dropped_immediately() {
        StringPool::new();
    }

    fn return_populated_storage() -> (StringPool, *const u8) {
        let s = StringPool::new();
        let ptr = {
            let interned = s.intern("hello");
            interned.as_ptr()
        };
        (s, ptr)
    }

    #[test]
    fn can_return_storage_populated_with_values() {
        let (s, ptr_val) = return_populated_storage();
        let interned = s.intern("hello");
        assert_eq!(interned.as_ptr(), ptr_val);
    }
}

#[cfg(feature = "unstable")]
mod bench {
    extern crate test;

    use self::test::Bencher;

    use super::StringPool;

    #[bench]
    fn single_string(b: &mut Bencher) {
        let s = StringPool::new();
        b.iter(|| s.intern("hello"));
        b.bytes = "hello".len() as u64;
    }

    #[bench]
    fn many_unique_string(b: &mut Bencher) {
        let s = StringPool::new();

        let strings: Vec<String> =
            (0..1000)
            .map(|i| format!("str{}str", i))
            .collect();
        b.iter(|| {
            for ss in strings.iter() {
                s.intern(ss);
            }
        });
        b.bytes = strings.iter().fold(0, |a, s| a + s.len()) as u64;
    }

    #[bench]
    fn many_repeated_string(b: &mut Bencher) {
        let s = StringPool::new();

        let strings: Vec<String> =
            (0..1000)
            .map(|i| format!("str{}str", i % 100))
            .collect();
        b.iter(|| {
            for ss in strings.iter() {
                s.intern(ss);
            }
        });
        b.bytes = strings.iter().fold(0, |a, s| a + s.len()) as u64;
    }
}
<commit_msg>leaking memory is not unsafe anymore<commit_after>/// Strongly borrowed from TypedArena
/// Differs in growth strategy (non-doubling)
/// And only for variable-sized strings

use std::borrow::Borrow;
use std::cell::{Cell,RefCell};
use std::cmp::max;
use std::collections::LinkedList;
use std::collections::hash_map::HashMap;
use std::default::Default;
use std::ops::Deref;
use std::slice;
use std::{fmt,hash,mem,ptr,str};

struct Chunk {
    start: *mut u8,
    capacity: usize,
}

impl Chunk {
    fn new(capacity: usize) -> Chunk {
        let mut slab: Vec<u8> = Vec::with_capacity(capacity);
        let start = slab.as_mut_ptr();

        // We will manually track the buffer and then drop it ourselves
        mem::forget(slab);

        Chunk {
            start: start,
            capacity: capacity,
        }
    }

    // Returns a pointer to the beginning of the allocated space.
    #[inline]
    fn start(&self) -> *const u8 {
        self.start as *const u8
    }

    // Returns a pointer to the end of the allocated space.
    #[inline]
    fn end(&self) -> *const u8 {
        unsafe { self.start().offset(self.capacity as isize) }
    }
}

impl Drop for Chunk {
    fn drop(&mut self) {
        // This is safe because we only ever store u8, which doesn't
        // have a destructor. This means the len doesn't matter, only
        // the capacity.
        unsafe {
            Vec::from_raw_parts(self.start, self.capacity, self.capacity);
        }
    }
}

#[allow(raw_pointer_derive)]
#[derive(Copy,Clone)]
pub struct InternedString {
    data: *const u8,
    len: usize,
}

impl InternedString {
    fn from_parts(data: *const u8, len: usize) -> InternedString {
        InternedString {
            data: data,
            len: len,
        }
    }

    pub fn from_str(s: &str) -> InternedString {
        let bytes: &[u8] = s.as_bytes();
        InternedString {
            data: bytes.as_ptr(),
            len: bytes.len(),
        }
    }

    pub fn as_slice<'s>(&self) -> &'s str {
        unsafe {
            let bytes = slice::from_raw_parts(self.data, self.len);
            str::from_utf8_unchecked(bytes)
        }
    }
}

impl fmt::Debug for InternedString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}

impl PartialEq for InternedString {
    fn eq(&self, other: &InternedString) -> bool {
        self.as_slice().eq(other.as_slice())
    }
}

impl PartialEq<str> for InternedString {
    fn eq(&self, other: &str) -> bool {
        self.as_slice().eq(other)
    }
}

impl Eq for InternedString {}

impl hash::Hash for InternedString {
    fn hash<H>(&self, state: &mut H)
        where H: hash::Hasher
    {
        self.as_slice().hash(state)
    }
}

impl Borrow<str> for InternedString {
    fn borrow(&self) -> &str {
        self.as_slice()
    }
}

impl Deref for InternedString {
    type Target = str;

    fn deref(&self) -> &str {
        self.as_slice()
    }
}

pub struct StringPool {
    start: Cell<*mut u8>,
    end: Cell<*const u8>,
    chunks: RefCell<LinkedList<Chunk>>,
    index: RefCell<HashMap<InternedString, InternedString>>,
}

static CAPACITY: usize = 10240;

impl StringPool {
    pub fn new() -> StringPool {
        StringPool{
            start: Cell::new(ptr::null_mut()),
            end: Cell::new(ptr::null()),
            chunks: RefCell::new(LinkedList::new()),
            index: RefCell::new(Default::default()),
        }
    }

    pub fn intern<'s>(&'s self, s: &str) -> &'s str {
        if s == "" { return ""; }

        let search_string = InternedString::from_str(s);

        let mut index = self.index.borrow_mut();
        let interned_str = *index.entry(search_string).or_insert_with(|| self.do_intern(s));

        // The lifetime is really matched to us
        unsafe { mem::transmute(interned_str) }
    }

    fn do_intern(&self, s: &str) -> InternedString {
        self.ensure_capacity(s.len());
        self.store(s)
    }

    fn ensure_capacity(&self, str_len: usize) {
        let remaining = self.end.get() as usize - self.start.get() as usize;
        if remaining < str_len {
            self.allocate_another(max(CAPACITY, str_len))
        }
    }

    fn allocate_another(&self, capacity: usize) {
        let chunk = Chunk::new(capacity);
        self.start.set(chunk.start() as *mut u8);
        self.end.set(chunk.end());
        self.chunks.borrow_mut().push_front(chunk);
    }

    fn store(&self, s: &str) -> InternedString {
        let str_start = s.as_bytes().as_ptr();
        let str_len = s.len();

        unsafe {
            ptr::copy_nonoverlapping(str_start, self.start.get(), str_len);

            // Rebuild the string from our buffer
            let interned_str = InternedString::from_parts(self.start.get() as *const u8, str_len);

            // Increase current pointer
            self.start.set(self.start.get().offset(str_len as isize));

            interned_str
        }
    }
}

#[cfg(test)]
mod test {
    use std::borrow::ToOwned;

    use super::StringPool;

    #[test]
    fn keeps_the_same_string() {
        let s = StringPool::new();

        let interned = s.intern("hello");

        assert_eq!(interned, "hello");
    }

    #[test]
    fn does_not_reuse_the_pointer_of_the_input() {
        let s = StringPool::new();
        let input = "hello";

        let interned = s.intern(input);

        assert!(
            input.as_bytes().as_ptr() !=
            interned.as_bytes().as_ptr()
        );
    }

    #[test]
    fn reuses_the_pointer_for_repeated_input() {
        let s = StringPool::new();

        let interned1 = s.intern("world");
        let interned2 = s.intern("world");

        assert_eq!(
            interned1.as_bytes().as_ptr(),
            interned2.as_bytes().as_ptr()
        );
    }

    #[test]
    #[cfg(feature = "compile_failure")]
    fn string_cannot_outlive_the_pool() {
        let z = {
            let s = StringPool::new();
            s.intern("hello")
        };
    }

    #[test]
    fn ignores_the_lifetime_of_the_input_string() {
        let s = StringPool::new();

        let interned = {
            let allocated_string = "green".to_owned();
            s.intern(&allocated_string)
        };

        // allocated_string is gone now, but we should be able to
        // access the result value until the storage goes away.

        assert_eq!(interned, "green");
    }

    #[test]
    fn can_be_dropped_immediately() {
        StringPool::new();
    }

    fn return_populated_storage() -> (StringPool, *const u8) {
        let s = StringPool::new();
        let ptr = {
            let interned = s.intern("hello");
            interned.as_ptr()
        };
        (s, ptr)
    }

    #[test]
    fn can_return_storage_populated_with_values() {
        let (s, ptr_val) = return_populated_storage();
        let interned = s.intern("hello");
        assert_eq!(interned.as_ptr(), ptr_val);
    }
}

#[cfg(feature = "unstable")]
mod bench {
    extern crate test;

    use self::test::Bencher;

    use super::StringPool;

    #[bench]
    fn single_string(b: &mut Bencher) {
        let s = StringPool::new();
        b.iter(|| s.intern("hello"));
        b.bytes = "hello".len() as u64;
    }

    #[bench]
    fn many_unique_string(b: &mut Bencher) {
        let s = StringPool::new();

        let strings: Vec<String> =
            (0..1000)
            .map(|i| format!("str{}str", i))
            .collect();
        b.iter(|| {
            for ss in strings.iter() {
                s.intern(ss);
            }
        });
        b.bytes = strings.iter().fold(0, |a, s| a + s.len()) as u64;
    }

    #[bench]
    fn many_repeated_string(b: &mut Bencher) {
        let s = StringPool::new();

        let strings: Vec<String> =
            (0..1000)
            .map(|i| format!("str{}str", i % 100))
            .collect();
        b.iter(|| {
            for ss in strings.iter() {
                s.intern(ss);
            }
        });
        b.bytes = strings.iter().fold(0, |a, s| a + s.len()) as u64;
    }
}
<|endoftext|>


<commit_before>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

use super::Term;

pub fn handle(term: &mut Term, ch: char) {
    match ch {
        '\x1b' => { // Escape key
            term.editor.switch_mode();
        }
        '\x7f' => { // Backspace key
            let line = term.current_line() + term.cursor.pos.y;
            term.cursor.save_pos();

            if term.cursor.pos.x == 0 {
                let mut rem = term.editor.contents[line].clone();
                let pos = term.editor.contents[line - 1].len() - 1;

                term.editor.contents[line - 1].remove(pos);
                term.editor.contents[line - 1].append(&mut rem);
                term.editor.contents.remove(line);

                if term.cursor.pos.y != 0 {
                    term.cursor.pos.y -= 1;
                }

                term.cursor.pos.x = pos;
                term.redraw_file();
            } else {
                term.cursor.pos.x -= 1;
                let pos = term.cursor.pos.x;

                term.editor.contents[line].remove(pos);
                term.redraw_file();
            }
        }
        '\r' => {
            let line = term.current_line() + term.cursor.pos.y;
            term.editor.contents.insert(line, vec![b'\n']);

            term.cursor.save_pos();
            term.cursor.pos.x = 0;
            term.cursor.pos.y += 1;

            term.redraw_file();
        }
        '\t' => {
            for i in 0..4 {
                let x = term.cursor.pos.x + i;
                term.term[(x, term.cursor.pos.y)].set_ch(' ');
            }

            term.cursor.save_pos();
            term.cursor.pos.x += 4;
        }
        c @ _ => {
            let line = term.current_line() + term.cursor.pos.y;
            let pos = term.cursor.pos.x;

            term.editor.contents[line].insert(pos, c as u8);

            term.cursor.save_pos();
            term.cursor.pos.x += 1;
            term.redraw_file();
        }
    }
}
<commit_msg>ENTER works within lines<commit_after>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

use super::Term;

pub fn handle(term: &mut Term, ch: char) {
    match ch {
        '\x1b' => { // Escape key
            term.editor.switch_mode();
        }
        '\x7f' => { // Backspace key
            let line = term.current_line() + term.cursor.pos.y;
            term.cursor.save_pos();

            if term.cursor.pos.x == 0 {
                let mut rem = term.editor.contents[line].clone();
                let pos = term.editor.contents[line - 1].len() - 1;

                term.editor.contents[line - 1].remove(pos);
                term.editor.contents[line - 1].append(&mut rem);
                term.editor.contents.remove(line);

                if term.cursor.pos.y != 0 {
                    term.cursor.pos.y -= 1;
                }

                term.cursor.pos.x = pos;
                term.redraw_file();
            } else {
                term.cursor.pos.x -= 1;
                let pos = term.cursor.pos.x;

                term.editor.contents[line].remove(pos);
                term.redraw_file();
            }
        }
        '\r' => {
            let line = term.current_line() + term.cursor.pos.y;
            let pos = term.cursor.pos.x;

            let mut rem = term.editor.contents[line].split_off(pos);
            rem.push(b'\n');
            term.editor.contents.insert(line + 1, rem);

            term.cursor.save_pos();
            term.cursor.pos.x = 0;
            term.cursor.pos.y += 1;

            term.redraw_file();
        }
        '\t' => {
            for i in 0..4 {
                let x = term.cursor.pos.x + i;
                term.term[(x, term.cursor.pos.y)].set_ch(' ');
            }

            term.cursor.save_pos();
            term.cursor.pos.x += 4;
        }
        c @ _ => {
            let line = term.current_line() + term.cursor.pos.y;
            let pos = term.cursor.pos.x;

            term.editor.contents[line].insert(pos, c as u8);

            term.cursor.save_pos();
            term.cursor.pos.x += 1;
            term.redraw_file();
        }
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::path::Path;
use command::*;

// Somke test only
#[test]
fn smoke() {
    let mut d = env::current_dir().unwrap();
    d.push(Path::new(".git"));
    let c = Config {
        repo: "ssh://git@.github.com:22/rhysd/git-brws.git".to_string(),
        branch: None,
        git_dir: d,
        args: vec![],
    };
    match url(c) {
        Ok(u) => assert_eq!(u, "https://github.com/rhysd/git-brws", "Unexpected URL: {}", u),
        Err(e) => assert!(false, "command::url() was not processed properly: {}", e),
    }
}
<commit_msg>fix repository URL in a smoke test<commit_after>use std::env;
use std::path::Path;
use command::*;

// Somke test only
#[test]
fn smoke() {
    let mut d = env::current_dir().unwrap();
    d.push(Path::new(".git"));
    let c = Config {
        repo: "ssh://git@github.com:22/rhysd/git-brws.git".to_string(),
        branch: None,
        git_dir: d,
        args: vec![],
    };
    match url(c) {
        Ok(u) => assert_eq!(u, "https://github.com/rhysd/git-brws", "Unexpected URL: {}", u),
        Err(e) => assert!(false, "command::url() was not processed properly: {}", e),
    }
}
<|endoftext|>