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

#[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,
    }
}
<commit_msg>Reduce function visibility<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(crate) 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(crate) 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(crate) 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(crate) 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>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Servo, the mighty web browser engine from the future.
//!
//! This is a very simple library that wires all of Servo's components
//! together as type `Browser`, along with a generic client
//! implementing the `WindowMethods` trait, to create a working web
//! browser.
//!
//! The `Browser` type is responsible for configuring a
//! `Constellation`, which does the heavy lifting of coordinating all
//! of Servo's internal subsystems, including the `ScriptThread` and the
//! `LayoutThread`, as well maintains the navigation context.
//!
//! The `Browser` is fed events from a generic type that implements the
//! `WindowMethods` trait.

#[cfg(not(target_os = "windows"))]
extern crate gaol;
#[macro_use]
extern crate util as _util;

mod export {
    extern crate canvas;
    extern crate canvas_traits;
    extern crate compositing;
    extern crate devtools;
    extern crate devtools_traits;
    extern crate euclid;
    extern crate gfx;
    extern crate gleam;
    extern crate ipc_channel;
    extern crate layers;
    extern crate layout;
    extern crate msg;
    extern crate net;
    extern crate net_traits;
    extern crate profile;
    extern crate profile_traits;
    extern crate script;
    extern crate script_traits;
    extern crate style;
    extern crate url;
}

#[cfg(feature = "webdriver")]
extern crate webdriver_server;

extern crate webrender;
extern crate webrender_traits;

#[cfg(feature = "webdriver")]
fn webdriver(port: u16, constellation: Sender<ConstellationMsg>) {
    webdriver_server::start_server(port, constellation);
}

#[cfg(not(feature = "webdriver"))]
fn webdriver(_port: u16, _constellation: Sender<ConstellationMsg>) { }

use compositing::CompositorEventListener;
use compositing::CompositorMsg as ConstellationMsg;
use compositing::compositor_thread::InitialCompositorState;
use compositing::constellation::InitialConstellationState;
use compositing::pipeline::UnprivilegedPipelineContent;
#[cfg(not(target_os = "windows"))]
use compositing::sandboxing;
use compositing::windowing::WindowEvent;
use compositing::windowing::WindowMethods;
use compositing::{CompositorProxy, CompositorThread, Constellation};
#[cfg(not(target_os = "windows"))]
use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
use gfx::font_cache_thread::FontCacheThread;
use ipc_channel::ipc::{self, IpcSender};
use net::image_cache_thread::new_image_cache_thread;
use net::resource_thread::new_resource_thread;
use net::storage_thread::StorageThreadFactory;
use net_traits::storage_thread::StorageThread;
use profile::mem as profile_mem;
use profile::time as profile_time;
use profile_traits::mem;
use profile_traits::time;
use std::borrow::Borrow;
use std::rc::Rc;
use std::sync::mpsc::Sender;
use util::opts;
use util::resource_files::resources_dir_path;

pub use _util as util;
pub use export::canvas;
pub use export::canvas_traits;
pub use export::compositing;
pub use export::devtools;
pub use export::devtools_traits;
pub use export::euclid;
pub use export::gfx;
pub use export::gleam::gl;
pub use export::ipc_channel;
pub use export::layers;
pub use export::layout;
pub use export::msg;
pub use export::net;
pub use export::net_traits;
pub use export::profile;
pub use export::profile_traits;
pub use export::script;
pub use export::script_traits;
pub use export::style;
pub use export::url;

/// The in-process interface to Servo.
///
/// It does everything necessary to render the web, primarily
/// orchestrating the interaction between JavaScript, CSS layout,
/// rendering, and the client window.
///
/// Clients create a `Browser` for a given reference-counted type
/// implementing `WindowMethods`, which is the bridge to whatever
/// application Servo is embedded in. Clients then create an event
/// loop to pump messages between the embedding application and
/// various browser components.
pub struct Browser {
    compositor: Box<CompositorEventListener + 'static>,
}

impl Browser {
    pub fn new<Window>(window: Option<Rc<Window>>) -> Browser
                       where Window: WindowMethods + 'static {
        // Global configuration options, parsed from the command line.
        let opts = opts::get();

        script::init();

        // Get both endpoints of a special channel for communication between
        // the client window and the compositor. This channel is unique because
        // messages to client may need to pump a platform-specific event loop
        // to deliver the message.
        let (compositor_proxy, compositor_receiver) =
            WindowMethods::create_compositor_channel(&window);
        let supports_clipboard = match window {
            Some(ref win_rc) => {
                let win: &Window = win_rc.borrow();
                win.supports_clipboard()
            }
            None => false
        };
        let time_profiler_chan = profile_time::Profiler::create(opts.time_profiler_period);
        let mem_profiler_chan = profile_mem::Profiler::create(opts.mem_profiler_period);
        let devtools_chan = opts.devtools_port.map(|port| {
            devtools::start_server(port)
        });

        let (webrender, webrender_api_sender) = if opts::get().use_webrender {
            let mut resource_path = resources_dir_path();
            resource_path.push("shaders");

            // TODO(gw): Duplicates device_pixels_per_screen_px from compositor. Tidy up!
            let hidpi_factor = window.as_ref()
                                     .map(|window| window.hidpi_factor().get())
                                     .unwrap_or(1.0);
            let device_pixel_ratio = match opts.device_pixels_per_px {
                Some(device_pixels_per_px) => device_pixels_per_px,
                None => match opts.output_file {
                    Some(_) => 1.0,
                    None => hidpi_factor,
                }
            };

            let (webrender, webrender_sender) =
                webrender::Renderer::new(webrender::RendererOptions {
                    device_pixel_ratio: device_pixel_ratio,
                    resource_path: resource_path,
                    enable_aa: opts.enable_text_antialiasing,
                    enable_msaa: opts.use_msaa,
                    enable_profiler: opts.webrender_stats,
                });
            (Some(webrender), Some(webrender_sender))
        } else {
            (None, None)
        };

        // Create the constellation, which maintains the engine
        // pipelines, including the script and layout threads, as well
        // as the navigation context.
        let constellation_chan = create_constellation(opts.clone(),
                                                      compositor_proxy.clone_compositor_proxy(),
                                                      time_profiler_chan.clone(),
                                                      mem_profiler_chan.clone(),
                                                      devtools_chan,
                                                      supports_clipboard,
                                                      webrender_api_sender.clone());

        if cfg!(feature = "webdriver") {
            if let Some(port) = opts.webdriver_port {
                webdriver(port, constellation_chan.clone());
            }
        }

        // The compositor coordinates with the client window to create the final
        // rendered page and display it somewhere.
        let compositor = CompositorThread::create(window, InitialCompositorState {
            sender: compositor_proxy,
            receiver: compositor_receiver,
            constellation_chan: constellation_chan,
            time_profiler_chan: time_profiler_chan,
            mem_profiler_chan: mem_profiler_chan,
            webrender: webrender,
            webrender_api_sender: webrender_api_sender,
        });

        Browser {
            compositor: compositor,
        }
    }

    pub fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool {
        self.compositor.handle_events(events)
    }

    pub fn repaint_synchronously(&mut self) {
        self.compositor.repaint_synchronously()
    }

    pub fn pinch_zoom_level(&self) -> f32 {
        self.compositor.pinch_zoom_level()
    }

    pub fn request_title_for_main_frame(&self) {
        self.compositor.title_for_main_frame()
    }
}

fn create_constellation(opts: opts::Opts,
                        compositor_proxy: Box<CompositorProxy + Send>,
                        time_profiler_chan: time::ProfilerChan,
                        mem_profiler_chan: mem::ProfilerChan,
                        devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
                        supports_clipboard: bool,
                        webrender_api_sender: Option<webrender_traits::RenderApiSender>) -> Sender<ConstellationMsg> {
    let resource_thread = new_resource_thread(opts.user_agent.clone(), devtools_chan.clone());
    let image_cache_thread = new_image_cache_thread(resource_thread.clone(),
                                                    webrender_api_sender.as_ref().map(|wr| wr.create_api()));
    let font_cache_thread = FontCacheThread::new(resource_thread.clone(),
                                                 webrender_api_sender.as_ref().map(|wr| wr.create_api()));
    let storage_thread: StorageThread = StorageThreadFactory::new();

    let initial_state = InitialConstellationState {
        compositor_proxy: compositor_proxy,
        devtools_chan: devtools_chan,
        image_cache_thread: image_cache_thread,
        font_cache_thread: font_cache_thread,
        resource_thread: resource_thread,
        storage_thread: storage_thread,
        time_profiler_chan: time_profiler_chan,
        mem_profiler_chan: mem_profiler_chan,
        supports_clipboard: supports_clipboard,
        webrender_api_sender: webrender_api_sender,
    };
    let constellation_chan =
        Constellation::<layout::layout_thread::LayoutThread,
                        script::script_thread::ScriptThread>::start(initial_state);

    // Send the URL command to the constellation.
    match opts.url {
        Some(url) => {
            constellation_chan.send(ConstellationMsg::InitLoadUrl(url)).unwrap();
        },
        None => ()
    };

    constellation_chan
}

/// Content process entry point.
pub fn run_content_process(token: String) {
    let (unprivileged_content_sender, unprivileged_content_receiver) =
        ipc::channel::<UnprivilegedPipelineContent>().unwrap();
    let connection_bootstrap: IpcSender<IpcSender<UnprivilegedPipelineContent>> =
        IpcSender::connect(token).unwrap();
    connection_bootstrap.send(unprivileged_content_sender).unwrap();

    let unprivileged_content = unprivileged_content_receiver.recv().unwrap();
    opts::set_defaults(unprivileged_content.opts());

    // Enter the sandbox if necessary.
    if opts::get().sandbox {
       create_sandbox();
    }

    script::init();

    unprivileged_content.start_all::<layout::layout_thread::LayoutThread,
                                     script::script_thread::ScriptThread>(true);
}

// This is a workaround for https://github.com/rust-lang/rust/pull/30175 until
// https://github.com/lfairy/rust-errno/pull/5 lands, and should be removed once
// we update Servo with the rust-errno crate.
#[cfg(target_os = "android")]
#[no_mangle]
pub unsafe extern fn __errno_location() -> *mut i32 {
    extern { fn __errno() -> *mut i32; }
    __errno()
}

#[cfg(not(target_os = "windows"))]
fn create_sandbox() {
    ChildSandbox::new(sandboxing::content_process_sandbox_profile()).activate().unwrap();
}

#[cfg(target_os = "windows")]
fn create_sandbox() {
    panic!("Sandboxing is not supported on Windows.");
}
<commit_msg>Properly use "pub extern crate"<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Servo, the mighty web browser engine from the future.
//!
//! This is a very simple library that wires all of Servo's components
//! together as type `Browser`, along with a generic client
//! implementing the `WindowMethods` trait, to create a working web
//! browser.
//!
//! The `Browser` type is responsible for configuring a
//! `Constellation`, which does the heavy lifting of coordinating all
//! of Servo's internal subsystems, including the `ScriptThread` and the
//! `LayoutThread`, as well maintains the navigation context.
//!
//! The `Browser` is fed events from a generic type that implements the
//! `WindowMethods` trait.

#[cfg(not(target_os = "windows"))]
extern crate gaol;
#[macro_use]
extern crate gleam;

pub extern crate canvas;
pub extern crate canvas_traits;
pub extern crate compositing;
pub extern crate devtools;
pub extern crate devtools_traits;
pub extern crate euclid;
pub extern crate gfx;
pub extern crate ipc_channel;
pub extern crate layers;
pub extern crate layout;
pub extern crate msg;
pub extern crate net;
pub extern crate net_traits;
pub extern crate profile;
pub extern crate profile_traits;
pub extern crate script;
pub extern crate script_traits;
pub extern crate style;
pub extern crate url;
pub extern crate util;

#[cfg(feature = "webdriver")]
extern crate webdriver_server;

extern crate webrender;
extern crate webrender_traits;

#[cfg(feature = "webdriver")]
fn webdriver(port: u16, constellation: Sender<ConstellationMsg>) {
    webdriver_server::start_server(port, constellation);
}

#[cfg(not(feature = "webdriver"))]
fn webdriver(_port: u16, _constellation: Sender<ConstellationMsg>) { }

use compositing::CompositorEventListener;
use compositing::CompositorMsg as ConstellationMsg;
use compositing::compositor_thread::InitialCompositorState;
use compositing::constellation::InitialConstellationState;
use compositing::pipeline::UnprivilegedPipelineContent;
#[cfg(not(target_os = "windows"))]
use compositing::sandboxing;
use compositing::windowing::WindowEvent;
use compositing::windowing::WindowMethods;
use compositing::{CompositorProxy, CompositorThread, Constellation};
#[cfg(not(target_os = "windows"))]
use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
use gfx::font_cache_thread::FontCacheThread;
use ipc_channel::ipc::{self, IpcSender};
use net::image_cache_thread::new_image_cache_thread;
use net::resource_thread::new_resource_thread;
use net::storage_thread::StorageThreadFactory;
use net_traits::storage_thread::StorageThread;
use profile::mem as profile_mem;
use profile::time as profile_time;
use profile_traits::mem;
use profile_traits::time;
use std::borrow::Borrow;
use std::rc::Rc;
use std::sync::mpsc::Sender;
use util::opts;
use util::resource_files::resources_dir_path;

pub use gleam::gl;

/// The in-process interface to Servo.
///
/// It does everything necessary to render the web, primarily
/// orchestrating the interaction between JavaScript, CSS layout,
/// rendering, and the client window.
///
/// Clients create a `Browser` for a given reference-counted type
/// implementing `WindowMethods`, which is the bridge to whatever
/// application Servo is embedded in. Clients then create an event
/// loop to pump messages between the embedding application and
/// various browser components.
pub struct Browser {
    compositor: Box<CompositorEventListener + 'static>,
}

impl Browser {
    pub fn new<Window>(window: Option<Rc<Window>>) -> Browser
                       where Window: WindowMethods + 'static {
        // Global configuration options, parsed from the command line.
        let opts = opts::get();

        script::init();

        // Get both endpoints of a special channel for communication between
        // the client window and the compositor. This channel is unique because
        // messages to client may need to pump a platform-specific event loop
        // to deliver the message.
        let (compositor_proxy, compositor_receiver) =
            WindowMethods::create_compositor_channel(&window);
        let supports_clipboard = match window {
            Some(ref win_rc) => {
                let win: &Window = win_rc.borrow();
                win.supports_clipboard()
            }
            None => false
        };
        let time_profiler_chan = profile_time::Profiler::create(opts.time_profiler_period);
        let mem_profiler_chan = profile_mem::Profiler::create(opts.mem_profiler_period);
        let devtools_chan = opts.devtools_port.map(|port| {
            devtools::start_server(port)
        });

        let (webrender, webrender_api_sender) = if opts::get().use_webrender {
            let mut resource_path = resources_dir_path();
            resource_path.push("shaders");

            // TODO(gw): Duplicates device_pixels_per_screen_px from compositor. Tidy up!
            let hidpi_factor = window.as_ref()
                                     .map(|window| window.hidpi_factor().get())
                                     .unwrap_or(1.0);
            let device_pixel_ratio = match opts.device_pixels_per_px {
                Some(device_pixels_per_px) => device_pixels_per_px,
                None => match opts.output_file {
                    Some(_) => 1.0,
                    None => hidpi_factor,
                }
            };

            let (webrender, webrender_sender) =
                webrender::Renderer::new(webrender::RendererOptions {
                    device_pixel_ratio: device_pixel_ratio,
                    resource_path: resource_path,
                    enable_aa: opts.enable_text_antialiasing,
                    enable_msaa: opts.use_msaa,
                    enable_profiler: opts.webrender_stats,
                });
            (Some(webrender), Some(webrender_sender))
        } else {
            (None, None)
        };

        // Create the constellation, which maintains the engine
        // pipelines, including the script and layout threads, as well
        // as the navigation context.
        let constellation_chan = create_constellation(opts.clone(),
                                                      compositor_proxy.clone_compositor_proxy(),
                                                      time_profiler_chan.clone(),
                                                      mem_profiler_chan.clone(),
                                                      devtools_chan,
                                                      supports_clipboard,
                                                      webrender_api_sender.clone());

        if cfg!(feature = "webdriver") {
            if let Some(port) = opts.webdriver_port {
                webdriver(port, constellation_chan.clone());
            }
        }

        // The compositor coordinates with the client window to create the final
        // rendered page and display it somewhere.
        let compositor = CompositorThread::create(window, InitialCompositorState {
            sender: compositor_proxy,
            receiver: compositor_receiver,
            constellation_chan: constellation_chan,
            time_profiler_chan: time_profiler_chan,
            mem_profiler_chan: mem_profiler_chan,
            webrender: webrender,
            webrender_api_sender: webrender_api_sender,
        });

        Browser {
            compositor: compositor,
        }
    }

    pub fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool {
        self.compositor.handle_events(events)
    }

    pub fn repaint_synchronously(&mut self) {
        self.compositor.repaint_synchronously()
    }

    pub fn pinch_zoom_level(&self) -> f32 {
        self.compositor.pinch_zoom_level()
    }

    pub fn request_title_for_main_frame(&self) {
        self.compositor.title_for_main_frame()
    }
}

fn create_constellation(opts: opts::Opts,
                        compositor_proxy: Box<CompositorProxy + Send>,
                        time_profiler_chan: time::ProfilerChan,
                        mem_profiler_chan: mem::ProfilerChan,
                        devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
                        supports_clipboard: bool,
                        webrender_api_sender: Option<webrender_traits::RenderApiSender>) -> Sender<ConstellationMsg> {
    let resource_thread = new_resource_thread(opts.user_agent.clone(), devtools_chan.clone());
    let image_cache_thread = new_image_cache_thread(resource_thread.clone(),
                                                    webrender_api_sender.as_ref().map(|wr| wr.create_api()));
    let font_cache_thread = FontCacheThread::new(resource_thread.clone(),
                                                 webrender_api_sender.as_ref().map(|wr| wr.create_api()));
    let storage_thread: StorageThread = StorageThreadFactory::new();

    let initial_state = InitialConstellationState {
        compositor_proxy: compositor_proxy,
        devtools_chan: devtools_chan,
        image_cache_thread: image_cache_thread,
        font_cache_thread: font_cache_thread,
        resource_thread: resource_thread,
        storage_thread: storage_thread,
        time_profiler_chan: time_profiler_chan,
        mem_profiler_chan: mem_profiler_chan,
        supports_clipboard: supports_clipboard,
        webrender_api_sender: webrender_api_sender,
    };
    let constellation_chan =
        Constellation::<layout::layout_thread::LayoutThread,
                        script::script_thread::ScriptThread>::start(initial_state);

    // Send the URL command to the constellation.
    match opts.url {
        Some(url) => {
            constellation_chan.send(ConstellationMsg::InitLoadUrl(url)).unwrap();
        },
        None => ()
    };

    constellation_chan
}

/// Content process entry point.
pub fn run_content_process(token: String) {
    let (unprivileged_content_sender, unprivileged_content_receiver) =
        ipc::channel::<UnprivilegedPipelineContent>().unwrap();
    let connection_bootstrap: IpcSender<IpcSender<UnprivilegedPipelineContent>> =
        IpcSender::connect(token).unwrap();
    connection_bootstrap.send(unprivileged_content_sender).unwrap();

    let unprivileged_content = unprivileged_content_receiver.recv().unwrap();
    opts::set_defaults(unprivileged_content.opts());

    // Enter the sandbox if necessary.
    if opts::get().sandbox {
       create_sandbox();
    }

    script::init();

    unprivileged_content.start_all::<layout::layout_thread::LayoutThread,
                                     script::script_thread::ScriptThread>(true);
}

// This is a workaround for https://github.com/rust-lang/rust/pull/30175 until
// https://github.com/lfairy/rust-errno/pull/5 lands, and should be removed once
// we update Servo with the rust-errno crate.
#[cfg(target_os = "android")]
#[no_mangle]
pub unsafe extern fn __errno_location() -> *mut i32 {
    extern { fn __errno() -> *mut i32; }
    __errno()
}

#[cfg(not(target_os = "windows"))]
fn create_sandbox() {
    ChildSandbox::new(sandboxing::content_process_sandbox_profile()).activate().unwrap();
}

#[cfg(target_os = "windows")]
fn create_sandbox() {
    panic!("Sandboxing is not supported on Windows.");
}
<|endoftext|>


<commit_before>use decorum;
use gfx;
use nalgebra::{Matrix4, Point3, Scalar, Vector4};
use num::{One, Zero};
use rand::{self, Rand};
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};

pub use self::pipeline::*;

#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct Color4<T>(Vector4<T>)
where
    T: Scalar;

impl<T> Color4<T>
where
    T: One + Scalar + Zero,
{
    pub fn new(r: T, g: T, b: T, a: T) -> Self {
        Color4(Vector4::new(r, g, b, a))
    }

    pub fn white() -> Self {
        Color4::new(T::one(), T::one(), T::one(), T::one())
    }

    pub fn black() -> Self {
        Color4::new(T::zero(), T::zero(), T::zero(), T::one())
    }
}

impl<T> Color4<T>
where
    T: One + Rand + Scalar + Zero,
{
    pub fn random() -> Self {
        Color4::new(
            rand::random::<T>(),
            rand::random::<T>(),
            rand::random::<T>(),
            T::one(),
        )
    }
}

impl<T> Default for Color4<T>
where
    T: One + Scalar + Zero,
{
    fn default() -> Self {
        Color4::white()
    }
}

impl<T> Deref for Color4<T>
where
    T: Scalar,
{
    type Target = Vector4<T>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T> DerefMut for Color4<T>
where
    T: Scalar,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

gfx_pipeline! {
    pipeline {
        buffer: gfx::VertexBuffer<Vertex> = (),
        transform: gfx::ConstantBuffer<Transform> = "transform",
        camera: gfx::Global<[[f32; 4]; 4]> = "u_camera",
        model: gfx::Global<[[f32; 4]; 4]> = "u_model",
        color: gfx::RenderTarget<gfx::format::Rgba8> = "f_target0",
        depth: gfx::DepthTarget<gfx::format::DepthStencil> = gfx::preset::depth::LESS_EQUAL_WRITE,
    }
}

gfx_constant_struct! {
    Transform {
        camera: [[f32; 4]; 4] = "u_camera",
        model: [[f32; 4]; 4] = "u_model",
    }
}

impl Transform {
    pub fn new(camera: &Matrix4<f32>, model: &Matrix4<f32>) -> Self {
        #[cfg_attr(rustfmt, rustfmt_skip)]
        Transform {
            camera: [
                [camera[0], camera[4], camera[ 8], camera[12]],
                [camera[1], camera[5], camera[ 9], camera[13]],
                [camera[2], camera[6], camera[10], camera[14]],
                [camera[3], camera[7], camera[11], camera[15]],
            ],
            model: [
                [model[0], model[4], model[ 8], model[12]],
                [model[1], model[5], model[ 9], model[13]],
                [model[2], model[6], model[10], model[14]],
                [model[3], model[7], model[11], model[15]],
            ],
        }
    }
}

gfx_vertex_struct! {
    Vertex {
        position: [f32; 3] = "a_position",
        color: [f32; 4] = "a_color",
    }
}

impl Vertex {
    pub fn new(position: &Point3<f32>, color: &Color4<f32>) -> Self {
        Vertex {
            position: [position[0], position[1], position[2]],
            color: [color[0], color[1], color[2], color[3]],
        }
    }
}

impl Default for Vertex {
    fn default() -> Self {
        Vertex {
            position: Default::default(),
            color: Default::default(),
        }
    }
}

impl Eq for Vertex {}

impl Hash for Vertex {
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher,
    {
        decorum::hash_float_array(&self.position, state);
        decorum::hash_float_array(&self.color, state);
    }
}
<commit_msg>Remove unused function.<commit_after>use decorum;
use gfx;
use nalgebra::{Matrix4, Point3, Scalar, Vector4};
use num::One;
use rand::{self, Rand};
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};

pub use self::pipeline::*;

#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
pub struct Color4<T>(Vector4<T>)
where
    T: Scalar;

impl<T> Color4<T>
where
    T: Scalar,
{
    pub fn new(r: T, g: T, b: T, a: T) -> Self {
        Color4(Vector4::new(r, g, b, a))
    }
}

impl<T> Color4<T>
where
    T: One + Scalar,
{
    pub fn white() -> Self {
        Color4::new(T::one(), T::one(), T::one(), T::one())
    }
}

impl<T> Color4<T>
where
    T: One + Rand + Scalar,
{
    pub fn random() -> Self {
        Color4::new(
            rand::random::<T>(),
            rand::random::<T>(),
            rand::random::<T>(),
            T::one(),
        )
    }
}

impl<T> Default for Color4<T>
where
    T: One + Scalar,
{
    fn default() -> Self {
        Color4::white()
    }
}

impl<T> Deref for Color4<T>
where
    T: Scalar,
{
    type Target = Vector4<T>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T> DerefMut for Color4<T>
where
    T: Scalar,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

gfx_pipeline! {
    pipeline {
        buffer: gfx::VertexBuffer<Vertex> = (),
        transform: gfx::ConstantBuffer<Transform> = "transform",
        camera: gfx::Global<[[f32; 4]; 4]> = "u_camera",
        model: gfx::Global<[[f32; 4]; 4]> = "u_model",
        color: gfx::RenderTarget<gfx::format::Rgba8> = "f_target0",
        depth: gfx::DepthTarget<gfx::format::DepthStencil> = gfx::preset::depth::LESS_EQUAL_WRITE,
    }
}

gfx_constant_struct! {
    Transform {
        camera: [[f32; 4]; 4] = "u_camera",
        model: [[f32; 4]; 4] = "u_model",
    }
}

impl Transform {
    pub fn new(camera: &Matrix4<f32>, model: &Matrix4<f32>) -> Self {
        #[cfg_attr(rustfmt, rustfmt_skip)]
        Transform {
            camera: [
                [camera[0], camera[4], camera[ 8], camera[12]],
                [camera[1], camera[5], camera[ 9], camera[13]],
                [camera[2], camera[6], camera[10], camera[14]],
                [camera[3], camera[7], camera[11], camera[15]],
            ],
            model: [
                [model[0], model[4], model[ 8], model[12]],
                [model[1], model[5], model[ 9], model[13]],
                [model[2], model[6], model[10], model[14]],
                [model[3], model[7], model[11], model[15]],
            ],
        }
    }
}

gfx_vertex_struct! {
    Vertex {
        position: [f32; 3] = "a_position",
        color: [f32; 4] = "a_color",
    }
}

impl Vertex {
    pub fn new(position: &Point3<f32>, color: &Color4<f32>) -> Self {
        Vertex {
            position: [position[0], position[1], position[2]],
            color: [color[0], color[1], color[2], color[3]],
        }
    }
}

impl Default for Vertex {
    fn default() -> Self {
        Vertex {
            position: Default::default(),
            color: Default::default(),
        }
    }
}

impl Eq for Vertex {}

impl Hash for Vertex {
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher,
    {
        decorum::hash_float_array(&self.position, state);
        decorum::hash_float_array(&self.color, state);
    }
}
<|endoftext|>


<commit_before>extern crate gcc;
extern crate bindgen;
#[cfg(feature = "static")]
extern crate meson;
extern crate gl_generator;

use std::env;
#[allow(unused_imports)]
use std::path::{Path, PathBuf};
use std::fs::File;
use gl_generator::{Registry, Api, Profile, Fallbacks, StaticGenerator};

fn main() {
    let generated = bindgen::builder()
        .derive_debug(true)
        .derive_default(true)
        .generate_comments(true)
        .header("src/wlroots.h")
        .whitelisted_type(r"^wlr_.*$")
        .whitelisted_type(r"^xkb_.*$")
        .whitelisted_function(r"^_?wlr_.*$")
        .whitelisted_function(r"^xkb_.*$")
        .ctypes_prefix("libc")
        .clang_arg("-Iwlroots/include")
        .clang_arg("-Iwlroots/include/wlr")
        .clang_arg("-Iwlroots/include/xcursor")
        .clang_arg("-I/usr/include/pixman-1")
        // Work around bug https://github.com/rust-lang-nursery/rust-bindgen/issues/687
        .hide_type("FP_NAN")
        .hide_type("FP_INFINITE")
        .hide_type("FP_ZERO")
        .hide_type("FP_SUBNORMAL")
        .hide_type("FP_NORMAL")
        .generate().unwrap();

    println!("cargo:rustc-link-lib=dylib=X11");
    println!("cargo:rustc-link-lib=dylib=X11-xcb");
    println!("cargo:rustc-link-lib=dylib=xkbcommon");
    println!("cargo:rustc-link-lib=dylib=xcb");
    println!("cargo:rustc-link-lib=dylib=cap");
    println!("cargo:rustc-link-lib=dylib=wayland-egl");
    println!("cargo:rustc-link-lib=dylib=wayland-client");
    println!("cargo:rustc-link-lib=dylib=wayland-server");
    println!("cargo:rustc-link-lib=dylib=EGL");
    println!("cargo:rustc-link-lib=dylib=GL");
    println!("cargo:rustc-link-lib=dylib=gbm");
    println!("cargo:rustc-link-lib=dylib=drm");
    println!("cargo:rustc-link-lib=dylib=input");
    println!("cargo:rustc-link-lib=dylib=udev");
    println!("cargo:rustc-link-lib=dylib=systemd");
    println!("cargo:rustc-link-lib=dylib=dbus-1");
    println!("cargo:rustc-link-lib=dylib=pixman-1");

    if !cfg!(feature = "static") {
        println!("cargo:rustc-link-lib=dylib=wlroots");
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    // generate the bindings
    generated.write_to_file("src/gen.rs").unwrap();

    meson();

    if cfg!(feature = "example") {

        // Example Khronos building stuff
        let dest = env::var("OUT_DIR").unwrap();
        let mut file = File::create(&Path::new(&dest).join("bindings.rs")).unwrap();
        Registry::new(Api::Gl, (4, 5), Profile::Core, Fallbacks::All, [])
            .write_bindings(StaticGenerator, &mut file)
            .unwrap();

        // Build share.d for examples
        let example_generated = bindgen::builder()
            .derive_debug(true)
            .derive_default(true)
            .generate_comments(true)
            .header("wlroots/examples/shared.h")
            .clang_arg("-Iwlroots/include")
            .clang_arg("-Iwlroots/include/wlr")
            .clang_arg("-Iwlroots/include/xcursor")
            .clang_arg("-I/usr/include/pixman-1")
            // Work around bug https://github.com/rust-lang-nursery/rust-bindgen/issues/687
            .hide_type("FP_NAN")
            .hide_type("FP_INFINITE")
            .hide_type("FP_ZERO")
            .hide_type("FP_SUBNORMAL")
            .hide_type("FP_NORMAL")
            .generate().unwrap();
        example_generated.write_to_file(format!("{}/shared.rs", dest)).unwrap();

        // Build shared.c for examples
        let mut config = gcc::Build::new();
        config.flag("-Wall");
        config.flag("-Wpedantic");
        config.flag("-Iwlroots/include");
        config.flag("-Iwlroots/include/wlr");
        config.file("wlroots/examples/shared.c");
        config.compile("libshared.a");

        // Link against libpam
        println!("cargo:rustc-flags=-l shared")
    }
}

#[cfg(not(feature = "static"))]
fn meson() {}

#[cfg(feature = "static")]
fn meson() {
    let build_path = PathBuf::from(env::var("OUT_DIR")
        .expect("Could not get OUT_DIR env variable"));
    build_path.join("build");
    let build_path_str = build_path.to_str()
        .expect("Could not turn build path into a string");
    println!("cargo:rustc-link-search=native=wlroots");
    println!("cargo:rustc-link-search=native={}/lib", build_path_str);
    println!("cargo:rustc-link-search=native={}/lib64", build_path_str);
    println!("cargo:rustc-link-search=native={}/build/", build_path_str);
    if cfg!(feature = "static") {
        println!("cargo:rustc-link-search=native={}/util/", build_path_str);
        println!("cargo:rustc-link-search=native={}/types/", build_path_str);
        println!("cargo:rustc-link-search=native={}/protocol/", build_path_str);
        println!("cargo:rustc-link-search=native={}/xcursor/", build_path_str);
        println!("cargo:rustc-link-search=native={}/xwayland/", build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/", build_path_str);
        println!("cargo:rustc-link-search=native={}/render/", build_path_str);

        println!("cargo:rustc-link-lib=static=wlr_util");
        println!("cargo:rustc-link-lib=static=wlr_types");
        println!("cargo:rustc-link-lib=static=wlr_xcursor");
        println!("cargo:rustc-link-lib=static=wlr_xwayland");
        println!("cargo:rustc-link-lib=static=wlr_backend");
        println!("cargo:rustc-link-lib=static=wlr_render");
        // wayland protocols
        println!("cargo:rustc-link-lib=static=wl_protos");
    }

    meson::build("wlroots", build_path_str);
}
<commit_msg>Fixed wlroots-sys build script<commit_after>extern crate gcc;
extern crate bindgen;
#[cfg(feature = "static")]
extern crate meson;
extern crate gl_generator;

use std::env;
#[allow(unused_imports)]
use std::path::{Path, PathBuf};
use std::fs::File;
use gl_generator::{Registry, Api, Profile, Fallbacks, StaticGenerator};

fn main() {
    let generated = bindgen::builder()
        .derive_debug(true)
        .derive_default(true)
        .generate_comments(true)
        .header("src/wlroots.h")
        .whitelisted_type(r"^wlr_.*$")
        .whitelisted_type(r"^xkb_.*$")
        .whitelisted_type(r"^XKB_.*$")
        .whitelisted_function(r"^_?wlr_.*$")
        .whitelisted_function(r"^xkb_.*$")
        .ctypes_prefix("libc")
        .clang_arg("-Iwlroots/include")
        .clang_arg("-Iwlroots/include/wlr")
        .clang_arg("-Iwlroots/include/xcursor")
        .clang_arg("-I/usr/include/pixman-1")
        // Work around bug https://github.com/rust-lang-nursery/rust-bindgen/issues/687
        .hide_type("FP_NAN")
        .hide_type("FP_INFINITE")
        .hide_type("FP_ZERO")
        .hide_type("FP_SUBNORMAL")
        .hide_type("FP_NORMAL")
        .generate().unwrap();

    println!("cargo:rustc-link-lib=dylib=X11");
    println!("cargo:rustc-link-lib=dylib=X11-xcb");
    println!("cargo:rustc-link-lib=dylib=xkbcommon");
    println!("cargo:rustc-link-lib=dylib=xcb");
    println!("cargo:rustc-link-lib=dylib=cap");
    println!("cargo:rustc-link-lib=dylib=wayland-egl");
    println!("cargo:rustc-link-lib=dylib=wayland-client");
    println!("cargo:rustc-link-lib=dylib=wayland-server");
    println!("cargo:rustc-link-lib=dylib=EGL");
    println!("cargo:rustc-link-lib=dylib=GL");
    println!("cargo:rustc-link-lib=dylib=gbm");
    println!("cargo:rustc-link-lib=dylib=drm");
    println!("cargo:rustc-link-lib=dylib=input");
    println!("cargo:rustc-link-lib=dylib=udev");
    println!("cargo:rustc-link-lib=dylib=systemd");
    println!("cargo:rustc-link-lib=dylib=dbus-1");
    println!("cargo:rustc-link-lib=dylib=pixman-1");

    if !cfg!(feature = "static") {
        println!("cargo:rustc-link-lib=dylib=wlroots");
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    // generate the bindings
    generated.write_to_file("src/gen.rs").unwrap();

    meson();

    // Example Khronos building stuff
    let dest = env::var("OUT_DIR").unwrap();
    let mut file = File::create(&Path::new(&dest).join("bindings.rs")).unwrap();
    Registry::new(Api::Gl, (4, 5), Profile::Core, Fallbacks::All, [])
        .write_bindings(StaticGenerator, &mut file)
        .unwrap();
    if cfg!(feature = "example") {
        // Build share.d for examples
        let example_generated = bindgen::builder()
            .derive_debug(true)
            .derive_default(true)
            .generate_comments(true)
            .header("wlroots/examples/shared.h")
            .clang_arg("-Iwlroots/include")
            .clang_arg("-Iwlroots/include/wlr")
            .clang_arg("-Iwlroots/include/xcursor")
            .clang_arg("-I/usr/include/pixman-1")
            // Work around bug https://github.com/rust-lang-nursery/rust-bindgen/issues/687
            .hide_type("FP_NAN")
            .hide_type("FP_INFINITE")
            .hide_type("FP_ZERO")
            .hide_type("FP_SUBNORMAL")
            .hide_type("FP_NORMAL")
            .generate().unwrap();
        example_generated.write_to_file(format!("{}/shared.rs", dest)).unwrap();

        // Build shared.c for examples
        let mut config = gcc::Build::new();
        config.flag("-Wall");
        config.flag("-Wpedantic");
        config.flag("-Iwlroots/include");
        config.flag("-Iwlroots/include/wlr");
        config.file("wlroots/examples/shared.c");
        config.compile("libshared.a");

        // Link against libpam
        println!("cargo:rustc-flags=-l shared")
    }
}

#[cfg(not(feature = "static"))]
fn meson() {}

#[cfg(feature = "static")]
fn meson() {
    let build_path = PathBuf::from(env::var("OUT_DIR")
        .expect("Could not get OUT_DIR env variable"));
    build_path.join("build");
    let build_path_str = build_path.to_str()
        .expect("Could not turn build path into a string");
    println!("cargo:rustc-link-search=native=wlroots");
    println!("cargo:rustc-link-search=native={}/lib", build_path_str);
    println!("cargo:rustc-link-search=native={}/lib64", build_path_str);
    println!("cargo:rustc-link-search=native={}/build/", build_path_str);
    if cfg!(feature = "static") {
        println!("cargo:rustc-link-search=native={}/util/", build_path_str);
        println!("cargo:rustc-link-search=native={}/types/", build_path_str);
        println!("cargo:rustc-link-search=native={}/protocol/", build_path_str);
        println!("cargo:rustc-link-search=native={}/xcursor/", build_path_str);
        println!("cargo:rustc-link-search=native={}/xwayland/", build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/", build_path_str);
        println!("cargo:rustc-link-search=native={}/render/", build_path_str);

        println!("cargo:rustc-link-lib=static=wlr_util");
        println!("cargo:rustc-link-lib=static=wlr_types");
        println!("cargo:rustc-link-lib=static=wlr_xcursor");
        println!("cargo:rustc-link-lib=static=wlr_xwayland");
        println!("cargo:rustc-link-lib=static=wlr_backend");
        println!("cargo:rustc-link-lib=static=wlr_render");
        // wayland protocols
        println!("cargo:rustc-link-lib=static=wl_protos");
    }

    meson::build("wlroots", build_path_str);
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};

use isahc::{
    auth::{Authentication, Credentials},
    config::Configurable,
    http::StatusCode,
    HttpClient, ReadResponseExt, Request,
};
use itertools::Itertools;
use semver::Version;
use serde::{de::IgnoredAny, Deserialize};
use serde_json::json;
use toml::from_str as from_toml_str;
use xshell::{pushd, read_file};

use crate::{cmd, config, util::ask_yes_no, Result};

const CRATESIO_API: &str = "https://crates.io/api/v1/crates";
const GITHUB_API_RUMA: &str = "https://api.github.com/repos/ruma/ruma";

/// Task to create a new release of the given crate.
#[derive(Debug)]
pub struct ReleaseTask {
    /// The crate to release.
    local_crate: LocalCrate,

    /// The root of the workspace.
    project_root: PathBuf,

    /// The http client to use for requests.
    client: HttpClient,
}

impl ReleaseTask {
    /// Create a new `ReleaseTask` with the given `name` and `project_root`.
    pub(crate) fn new(name: String, project_root: PathBuf) -> Result<Self> {
        let local_crate = LocalCrate::new(name, &project_root)?;

        Ok(Self { local_crate, project_root, client: HttpClient::new()? })
    }

    /// Run the task to effectively create a release.
    pub(crate) fn run(self) -> Result<()> {
        let title = &self.title();
        let prerelease = self.local_crate.version.is_prerelease();
        println!(
            "Starting {} for {}…",
            match prerelease {
                true => "pre-release",
                false => "release",
            },
            title
        );

        if self.is_released()? {
            return Err("This crate version is already released".into());
        }

        let remote = Self::git_remote()?;

        println!("Checking status of git repository…");
        if !cmd!("git status -s -uno").read()?.is_empty()
            && !ask_yes_no("This git repository contains untracked files. Continue?")?
        {
            return Ok(());
        }

        if let Some(macros) = self.macros() {
            print!("Found macros crate. ");
            let _dir = pushd(&macros.path)?;
            macros.publish(&self.client)?;
            println!("Resuming release of {}…", self.title());
        }

        let _dir = pushd(&self.local_crate.path)?;

        self.local_crate.publish(&self.client)?;

        if prerelease {
            println!("Pre-release created successfully!");
            return Ok(());
        }

        let changes = &self.local_crate.changes()?;

        let tag = &self.tag_name();

        println!("Creating git tag…");
        if cmd!("git tag -l {tag}").read()?.is_empty() {
            cmd!("git tag -s {tag} -m {title} -m {changes}").read()?;
        } else if !ask_yes_no("This tag already exists. Skip this step and continue?")? {
            return Ok(());
        }

        println!("Pushing tag to remote repository…");
        if cmd!("git ls-remote --tags {remote} {tag}").read()?.is_empty() {
            cmd!("git push {remote} {tag}").run()?;
        } else if !ask_yes_no("This tag has already been pushed. Skip this step and continue?")? {
            return Ok(());
        }

        println!("Creating release on GitHub…");
        let request_body = &json!({
            "tag_name": tag,
            "name": title,
            "body": changes.trim_softbreaks(),
        })
        .to_string();

        self.release(request_body)?;

        println!("Release created successfully!");

        Ok(())
    }

    /// Get the associated `-macros` crate of the current crate, if any.
    fn macros(&self) -> Option<LocalCrate> {
        LocalCrate::new(format!("{}-macros", self.local_crate.name), &self.project_root).ok()
    }

    /// Get the title of this release.
    fn title(&self) -> String {
        format!("{} {}", self.local_crate.name, self.local_crate.version)
    }

    /// Load the GitHub config from the config file.
    fn git_remote() -> Result<String> {
        let branch = cmd!("git rev-parse --abbrev-ref HEAD").read()?;
        let remote = cmd!("git config branch.{branch}.remote").read()?;

        if remote.is_empty() {
            return Err("Could not get current git remote".into());
        }

        Ok(remote)
    }

    /// Get the tag name for this release.
    fn tag_name(&self) -> String {
        format!("{}-{}", self.local_crate.name, self.local_crate.version)
    }

    /// Check if the tag for the current version of the crate has been pushed on GitHub.
    fn is_released(&self) -> Result<bool> {
        let response =
            self.client.get(format!("{}/releases/tags/{}", GITHUB_API_RUMA, self.tag_name()))?;

        Ok(response.status() == StatusCode::OK)
    }

    /// Create the release on GitHub with the given `config` and `credentials`.
    fn release(&self, body: &str) -> Result<()> {
        let config = config()?.github;

        let request = Request::post(format!("{}/releases", GITHUB_API_RUMA))
            .authentication(Authentication::basic())
            .credentials(Credentials::new(config.user, config.token))
            .header("Accept", "application/vnd.github.v3+json")
            .body(body)?;

        let mut response = self.client.send(request)?;

        if response.status() == StatusCode::CREATED {
            Ok(())
        } else {
            Err(format!("{}: {}", response.status(), response.text()?).into())
        }
    }
}

/// A local Rust crate.
#[derive(Debug)]
struct LocalCrate {
    /// The name of the crate.
    name: String,

    /// The version of the crate.
    version: Version,

    /// The local path of the crate.
    path: PathBuf,
}

impl LocalCrate {
    /// Creates a new `Crate` with the given name and project root.
    pub fn new(name: String, project_root: &Path) -> Result<Self> {
        let path = project_root.join(&name);

        let version = Self::version(&path)?;

        Ok(Self { name, version, path })
    }

    /// The current version of the crate at `path` from its manifest.
    fn version(path: &Path) -> Result<Version> {
        let manifest_toml = read_file(path.join("Cargo.toml"))?;
        let manifest: CargoManifest = from_toml_str(&manifest_toml)?;

        Ok(manifest.package.version)
    }

    /// The changes of the given version from the changelog.
    fn changes(&self) -> Result<String> {
        let changelog = read_file(self.path.join("CHANGELOG.md"))?;
        let lines_nb = changelog.lines().count();
        let mut lines = changelog.lines();

        let start = match lines.position(|l| l.starts_with(&format!("# {}", self.version))) {
            Some(p) => p + 1,
            None => {
                return Err("Could not find version title in changelog".into());
            }
        };

        let length = match lines.position(|l| l.starts_with("# ")) {
            Some(p) => p,
            None => lines_nb,
        };

        let changes = changelog.lines().skip(start).take(length).join("\n");

        Ok(changes.trim().to_owned())
    }

    /// Check if the current version of the crate is published on crates.io.
    fn is_published(&self, client: &HttpClient) -> Result<bool> {
        let response: CratesIoCrate =
            client.get(format!("{}/{}/{}", CRATESIO_API, self.name, self.version))?.json()?;

        Ok(response.version.is_some())
    }

    /// Publish this package on crates.io.
    fn publish(&self, client: &HttpClient) -> Result<()> {
        println!("Publishing {} {} on crates.io…", self.name, self.version);
        if self.is_published(client)? {
            if ask_yes_no("This version is already published. Skip this step and continue?")? {
                Ok(())
            } else {
                Err("Release interrupted by user.".into())
            }
        } else {
            Ok(cmd!("cargo publish").run()?)
        }
    }
}

/// The required cargo manifest data of a crate.
#[derive(Debug, Deserialize)]
struct CargoManifest {
    /// The package information.
    package: CargoPackage,
}

/// The required package information from a crate's cargo manifest.
#[derive(Debug, Deserialize)]
struct CargoPackage {
    /// The package version.
    version: Version,
}

/// A crate from the `GET /crates/{crate}` endpoint of crates.io.
#[derive(Deserialize)]
struct CratesIoCrate {
    version: Option<IgnoredAny>,
}

/// A tag from the `GET /repos/{owner}/{repo}/tags` endpoint of GitHub REST API.
#[derive(Debug, Deserialize)]
struct GithubTag {
    /// The name of the tag.
    name: String,
}

/// String manipulations for crate release.
trait StrExt {
    /// Remove soft line breaks as defined in CommonMark spec.
    fn trim_softbreaks(&self) -> String;
}

impl StrExt for str {
    fn trim_softbreaks(&self) -> String {
        let mut string = String::new();
        let mut s = self;

        while let Some(pos) = s.find('\n') {
            string.push_str(&s[..pos]);
            let pos_s = &s[pos..];

            if pos_s.starts_with("\n\n") {
                // Keep new paragraphs (multiple `\n`s).
                let next = pos_s.find(|c: char| c != '\n').unwrap_or(0);
                let (push, next_s) = pos_s.split_at(next);

                string.push_str(push);
                s = next_s;
            } else if s[..pos].ends_with("  ") || s[..pos].ends_with('\\') {
                // Keep hard line breaks (two spaces or a backslash before the line break).
                string.push('\n');
                s = &pos_s[1..];
            } else if let Some(p) = pos_s.find(|c: char| !c.is_ascii_whitespace()) {
                // Keep line break before list items (`\n` + whitespaces + `*` + whitespaces).
                // Remove line break and keep one space otherwise.
                let mut chars = pos_s.char_indices();
                let (_, char) = chars.find(|(i, _)| *i == p).unwrap();

                if char == '*' || char == '-' {
                    match chars.next() {
                        Some((_, next_char)) if next_char.is_ascii_whitespace() => {
                            string.push('\n');
                            s = &pos_s[1..];
                            continue;
                        }
                        _ => {}
                    }
                }

                string.push(' ');
                s = &pos_s[p..];
            }
        }

        string + s
    }
}
<commit_msg>xtask: Add a delay after publishing a macro crate<commit_after>use std::{
    path::{Path, PathBuf},
    thread::sleep,
    time::Duration,
};

use isahc::{
    auth::{Authentication, Credentials},
    config::Configurable,
    http::StatusCode,
    HttpClient, ReadResponseExt, Request,
};
use itertools::Itertools;
use semver::Version;
use serde::{de::IgnoredAny, Deserialize};
use serde_json::json;
use toml::from_str as from_toml_str;
use xshell::{pushd, read_file};

use crate::{cmd, config, util::ask_yes_no, Result};

const CRATESIO_API: &str = "https://crates.io/api/v1/crates";
const GITHUB_API_RUMA: &str = "https://api.github.com/repos/ruma/ruma";

/// Task to create a new release of the given crate.
#[derive(Debug)]
pub struct ReleaseTask {
    /// The crate to release.
    local_crate: LocalCrate,

    /// The root of the workspace.
    project_root: PathBuf,

    /// The http client to use for requests.
    client: HttpClient,
}

impl ReleaseTask {
    /// Create a new `ReleaseTask` with the given `name` and `project_root`.
    pub(crate) fn new(name: String, project_root: PathBuf) -> Result<Self> {
        let local_crate = LocalCrate::new(name, &project_root)?;

        Ok(Self { local_crate, project_root, client: HttpClient::new()? })
    }

    /// Run the task to effectively create a release.
    pub(crate) fn run(self) -> Result<()> {
        let title = &self.title();
        let prerelease = self.local_crate.version.is_prerelease();
        println!(
            "Starting {} for {}…",
            match prerelease {
                true => "pre-release",
                false => "release",
            },
            title
        );

        if self.is_released()? {
            return Err("This crate version is already released".into());
        }

        let remote = Self::git_remote()?;

        println!("Checking status of git repository…");
        if !cmd!("git status -s -uno").read()?.is_empty()
            && !ask_yes_no("This git repository contains untracked files. Continue?")?
        {
            return Ok(());
        }

        if let Some(macros) = self.macros() {
            print!("Found macros crate. ");
            let _dir = pushd(&macros.path)?;
            macros.publish(&self.client)?;

            println!("Waiting 10 seconds for the release to make it into the crates.io index…");
            sleep(Duration::from_secs(10));

            println!("Resuming release of {}…", self.title());
        }

        let _dir = pushd(&self.local_crate.path)?;

        self.local_crate.publish(&self.client)?;

        if prerelease {
            println!("Pre-release created successfully!");
            return Ok(());
        }

        let changes = &self.local_crate.changes()?;

        let tag = &self.tag_name();

        println!("Creating git tag…");
        if cmd!("git tag -l {tag}").read()?.is_empty() {
            cmd!("git tag -s {tag} -m {title} -m {changes}").read()?;
        } else if !ask_yes_no("This tag already exists. Skip this step and continue?")? {
            return Ok(());
        }

        println!("Pushing tag to remote repository…");
        if cmd!("git ls-remote --tags {remote} {tag}").read()?.is_empty() {
            cmd!("git push {remote} {tag}").run()?;
        } else if !ask_yes_no("This tag has already been pushed. Skip this step and continue?")? {
            return Ok(());
        }

        println!("Creating release on GitHub…");
        let request_body = &json!({
            "tag_name": tag,
            "name": title,
            "body": changes.trim_softbreaks(),
        })
        .to_string();

        self.release(request_body)?;

        println!("Release created successfully!");

        Ok(())
    }

    /// Get the associated `-macros` crate of the current crate, if any.
    fn macros(&self) -> Option<LocalCrate> {
        LocalCrate::new(format!("{}-macros", self.local_crate.name), &self.project_root).ok()
    }

    /// Get the title of this release.
    fn title(&self) -> String {
        format!("{} {}", self.local_crate.name, self.local_crate.version)
    }

    /// Load the GitHub config from the config file.
    fn git_remote() -> Result<String> {
        let branch = cmd!("git rev-parse --abbrev-ref HEAD").read()?;
        let remote = cmd!("git config branch.{branch}.remote").read()?;

        if remote.is_empty() {
            return Err("Could not get current git remote".into());
        }

        Ok(remote)
    }

    /// Get the tag name for this release.
    fn tag_name(&self) -> String {
        format!("{}-{}", self.local_crate.name, self.local_crate.version)
    }

    /// Check if the tag for the current version of the crate has been pushed on GitHub.
    fn is_released(&self) -> Result<bool> {
        let response =
            self.client.get(format!("{}/releases/tags/{}", GITHUB_API_RUMA, self.tag_name()))?;

        Ok(response.status() == StatusCode::OK)
    }

    /// Create the release on GitHub with the given `config` and `credentials`.
    fn release(&self, body: &str) -> Result<()> {
        let config = config()?.github;

        let request = Request::post(format!("{}/releases", GITHUB_API_RUMA))
            .authentication(Authentication::basic())
            .credentials(Credentials::new(config.user, config.token))
            .header("Accept", "application/vnd.github.v3+json")
            .body(body)?;

        let mut response = self.client.send(request)?;

        if response.status() == StatusCode::CREATED {
            Ok(())
        } else {
            Err(format!("{}: {}", response.status(), response.text()?).into())
        }
    }
}

/// A local Rust crate.
#[derive(Debug)]
struct LocalCrate {
    /// The name of the crate.
    name: String,

    /// The version of the crate.
    version: Version,

    /// The local path of the crate.
    path: PathBuf,
}

impl LocalCrate {
    /// Creates a new `Crate` with the given name and project root.
    pub fn new(name: String, project_root: &Path) -> Result<Self> {
        let path = project_root.join(&name);

        let version = Self::version(&path)?;

        Ok(Self { name, version, path })
    }

    /// The current version of the crate at `path` from its manifest.
    fn version(path: &Path) -> Result<Version> {
        let manifest_toml = read_file(path.join("Cargo.toml"))?;
        let manifest: CargoManifest = from_toml_str(&manifest_toml)?;

        Ok(manifest.package.version)
    }

    /// The changes of the given version from the changelog.
    fn changes(&self) -> Result<String> {
        let changelog = read_file(self.path.join("CHANGELOG.md"))?;
        let lines_nb = changelog.lines().count();
        let mut lines = changelog.lines();

        let start = match lines.position(|l| l.starts_with(&format!("# {}", self.version))) {
            Some(p) => p + 1,
            None => {
                return Err("Could not find version title in changelog".into());
            }
        };

        let length = match lines.position(|l| l.starts_with("# ")) {
            Some(p) => p,
            None => lines_nb,
        };

        let changes = changelog.lines().skip(start).take(length).join("\n");

        Ok(changes.trim().to_owned())
    }

    /// Check if the current version of the crate is published on crates.io.
    fn is_published(&self, client: &HttpClient) -> Result<bool> {
        let response: CratesIoCrate =
            client.get(format!("{}/{}/{}", CRATESIO_API, self.name, self.version))?.json()?;

        Ok(response.version.is_some())
    }

    /// Publish this package on crates.io.
    fn publish(&self, client: &HttpClient) -> Result<()> {
        println!("Publishing {} {} on crates.io…", self.name, self.version);
        if self.is_published(client)? {
            if ask_yes_no("This version is already published. Skip this step and continue?")? {
                Ok(())
            } else {
                Err("Release interrupted by user.".into())
            }
        } else {
            Ok(cmd!("cargo publish").run()?)
        }
    }
}

/// The required cargo manifest data of a crate.
#[derive(Debug, Deserialize)]
struct CargoManifest {
    /// The package information.
    package: CargoPackage,
}

/// The required package information from a crate's cargo manifest.
#[derive(Debug, Deserialize)]
struct CargoPackage {
    /// The package version.
    version: Version,
}

/// A crate from the `GET /crates/{crate}` endpoint of crates.io.
#[derive(Deserialize)]
struct CratesIoCrate {
    version: Option<IgnoredAny>,
}

/// A tag from the `GET /repos/{owner}/{repo}/tags` endpoint of GitHub REST API.
#[derive(Debug, Deserialize)]
struct GithubTag {
    /// The name of the tag.
    name: String,
}

/// String manipulations for crate release.
trait StrExt {
    /// Remove soft line breaks as defined in CommonMark spec.
    fn trim_softbreaks(&self) -> String;
}

impl StrExt for str {
    fn trim_softbreaks(&self) -> String {
        let mut string = String::new();
        let mut s = self;

        while let Some(pos) = s.find('\n') {
            string.push_str(&s[..pos]);
            let pos_s = &s[pos..];

            if pos_s.starts_with("\n\n") {
                // Keep new paragraphs (multiple `\n`s).
                let next = pos_s.find(|c: char| c != '\n').unwrap_or(0);
                let (push, next_s) = pos_s.split_at(next);

                string.push_str(push);
                s = next_s;
            } else if s[..pos].ends_with("  ") || s[..pos].ends_with('\\') {
                // Keep hard line breaks (two spaces or a backslash before the line break).
                string.push('\n');
                s = &pos_s[1..];
            } else if let Some(p) = pos_s.find(|c: char| !c.is_ascii_whitespace()) {
                // Keep line break before list items (`\n` + whitespaces + `*` + whitespaces).
                // Remove line break and keep one space otherwise.
                let mut chars = pos_s.char_indices();
                let (_, char) = chars.find(|(i, _)| *i == p).unwrap();

                if char == '*' || char == '-' {
                    match chars.next() {
                        Some((_, next_char)) if next_char.is_ascii_whitespace() => {
                            string.push('\n');
                            s = &pos_s[1..];
                            continue;
                        }
                        _ => {}
                    }
                }

                string.push(' ');
                s = &pos_s[p..];
            }
        }

        string + s
    }
}
<|endoftext|>


<commit_before>use client::Client;
use error::{Error, ErrorCode};
use params::{List, Metadata, Timestamp};
use resources::{Address, Currency, CustomerSource, Refund, Source};

#[derive(Debug, Deserialize)]
pub struct ChargeOutcome {
    #[serde(rename = "type")]
    pub outcome_type: String, // (authorized, manual_review, issuer_declined, blocked, invalid)
    pub network_status: String, // (approved_by_network, declined_by_network, not_sent_to_network, reversed_after_approval)
    #[serde(default)] pub reason: Option<String>,
    #[serde(default)] pub risk_level: String, // (normal, elevated, highest, not_assessed, unknown)
    #[serde(default)] pub seller_message: String,
    #[serde(default)] pub rule: Option<String>,
}

#[derive(Debug, Default, Deserialize, Serialize)]
pub struct FraudDetails {
    pub user_report: Option<String>,
    pub stripe_report: Option<String>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct ShippingDetails {
    pub address: Address,
    pub carrier: Option<String>, // eg. Fedex, UPS, USPS
    pub name: String, // TODO: Is this possibly null?
    pub phone: Option<String>,
    pub tracking_number: Option<String>,
}

#[derive(Default, Serialize)]
pub struct CaptureParams<'a> {
    pub amount: Option<u64>,
    pub application_fee: Option<u64>,
    pub receipt_email: Option<&'a str>,
    pub statement_descriptor: Option<&'a str>,
}

#[derive(Serialize)]
pub struct DestinationParams<'a> {
    pub account: &'a str,
    pub amount: u64,
}

#[derive(Default, Serialize)]
pub struct ChargeParams<'a> {
    #[serde(skip_serializing_if = "Option::is_none")] pub amount: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")] pub currency: Option<Currency>,
    #[serde(skip_serializing_if = "Option::is_none")] pub application_fee: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")] pub capture: Option<bool>, // NOTE: if None, Stripe assumes true
    #[serde(skip_serializing_if = "Option::is_none")] pub description: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub destination: Option<DestinationParams<'a>>,
    #[serde(skip_serializing_if = "Option::is_none")] pub fraud_details: Option<FraudDetails>,
    #[serde(skip_serializing_if = "Option::is_none")] pub transfer_group: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub on_behalf_of: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub metadata: Option<Metadata>,
    #[serde(skip_serializing_if = "Option::is_none")] pub receipt_email: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub shipping: Option<ShippingDetails>,
    #[serde(skip_serializing_if = "Option::is_none")] pub source: Option<CustomerSource<'a>>,
    #[serde(skip_serializing_if = "Option::is_none")] pub statement_descriptor: Option<&'a str>,
}

#[derive(Debug, Deserialize)]
pub struct Charge {
    pub id: String,
    pub amount: u64,
    pub amount_refunded: u64,
    pub application: Option<String>,
    pub application_fee: Option<String>,
    pub balance_transaction: String,
    pub captured: bool,
    pub created: Timestamp,
    pub currency: Currency,
    pub customer: Option<String>,
    pub description: Option<String>,
    pub destination: Option<String>,
    pub dispute: Option<String>,
    pub failure_code: Option<ErrorCode>,
    pub failure_message: Option<String>,
    pub fraud_details: FraudDetails,
    pub invoice: Option<String>,
    pub livemode: bool,
    pub metadata: Metadata,
    pub on_behalf_of: Option<String>,
    pub order: Option<String>,
    pub outcome: ChargeOutcome,
    pub paid: bool,
    pub receipt_email: Option<String>,
    pub receipt_number: Option<String>,
    pub refunded: bool,
    pub refunds: List<Refund>,
    pub shipping: Option<ShippingDetails>,
    pub source: Source,
    pub source_transfer: Option<String>,
    pub statement_descriptor: Option<String>,
    pub status: String, // (succeeded, pending, failed)
    pub transfer_group: Option<String>,
}

impl Charge {
    pub fn create(c: &Client, params: ChargeParams) -> Result<Charge, Error> {
        return c.post("/charges", params);
    }

    pub fn get(c: &Client, charge_id: &str) -> Result<Charge, Error> {
        return c.get(&format!("/charges/{}", charge_id));
    }

    pub fn update(c: &Client, charge_id: &str, params: ChargeParams) -> Result<Charge, Error> {
        return c.post(&format!("/charges/{}", charge_id), params);
    }

    pub fn capture(c: &Client, charge_id: &str, params: CaptureParams) -> Result<Charge, Error> {
        return c.post(&format!("/charges/{}/capture", charge_id), params);
    }
}
<commit_msg>Add missing skip_serialize to charge api paramss<commit_after>use client::Client;
use error::{Error, ErrorCode};
use params::{List, Metadata, Timestamp};
use resources::{Address, Currency, CustomerSource, Refund, Source};

#[derive(Debug, Deserialize)]
pub struct ChargeOutcome {
    #[serde(rename = "type")]
    pub outcome_type: String, // (authorized, manual_review, issuer_declined, blocked, invalid)
    pub network_status: String, // (approved_by_network, declined_by_network, not_sent_to_network, reversed_after_approval)
    #[serde(default)] pub reason: Option<String>,
    #[serde(default)] pub risk_level: String, // (normal, elevated, highest, not_assessed, unknown)
    #[serde(default)] pub seller_message: String,
    #[serde(default)] pub rule: Option<String>,
}

#[derive(Debug, Default, Deserialize, Serialize)]
pub struct FraudDetails {
    #[serde(skip_serializing_if = "Option::is_none")] pub user_report: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")] pub stripe_report: Option<String>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct ShippingDetails {
    pub name: String,
    pub address: Address,
    #[serde(skip_serializing_if = "Option::is_none")] pub carrier: Option<String>, // eg. Fedex, UPS, USPS
    #[serde(skip_serializing_if = "Option::is_none")] pub phone: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")] pub tracking_number: Option<String>,
}

#[derive(Default, Serialize)]
pub struct CaptureParams<'a> {
    #[serde(skip_serializing_if = "Option::is_none")] pub amount: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")] pub application_fee: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")] pub receipt_email: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub statement_descriptor: Option<&'a str>,
}

#[derive(Serialize)]
pub struct DestinationParams<'a> {
    pub account: &'a str,
    pub amount: u64,
}

#[derive(Default, Serialize)]
pub struct ChargeParams<'a> {
    #[serde(skip_serializing_if = "Option::is_none")] pub amount: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")] pub currency: Option<Currency>,
    #[serde(skip_serializing_if = "Option::is_none")] pub application_fee: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")] pub capture: Option<bool>, // NOTE: if None, Stripe assumes true
    #[serde(skip_serializing_if = "Option::is_none")] pub description: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub destination: Option<DestinationParams<'a>>,
    #[serde(skip_serializing_if = "Option::is_none")] pub fraud_details: Option<FraudDetails>,
    #[serde(skip_serializing_if = "Option::is_none")] pub transfer_group: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub on_behalf_of: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub metadata: Option<Metadata>,
    #[serde(skip_serializing_if = "Option::is_none")] pub receipt_email: Option<&'a str>,
    #[serde(skip_serializing_if = "Option::is_none")] pub shipping: Option<ShippingDetails>,
    #[serde(skip_serializing_if = "Option::is_none")] pub source: Option<CustomerSource<'a>>,
    #[serde(skip_serializing_if = "Option::is_none")] pub statement_descriptor: Option<&'a str>,
}

#[derive(Debug, Deserialize)]
pub struct Charge {
    pub id: String,
    pub amount: u64,
    pub amount_refunded: u64,
    pub application: Option<String>,
    pub application_fee: Option<String>,
    pub balance_transaction: String,
    pub captured: bool,
    pub created: Timestamp,
    pub currency: Currency,
    pub customer: Option<String>,
    pub description: Option<String>,
    pub destination: Option<String>,
    pub dispute: Option<String>,
    pub failure_code: Option<ErrorCode>,
    pub failure_message: Option<String>,
    pub fraud_details: FraudDetails,
    pub invoice: Option<String>,
    pub livemode: bool,
    pub metadata: Metadata,
    pub on_behalf_of: Option<String>,
    pub order: Option<String>,
    pub outcome: ChargeOutcome,
    pub paid: bool,
    pub receipt_email: Option<String>,
    pub receipt_number: Option<String>,
    pub refunded: bool,
    pub refunds: List<Refund>,
    pub shipping: Option<ShippingDetails>,
    pub source: Source,
    pub source_transfer: Option<String>,
    pub statement_descriptor: Option<String>,
    pub status: String, // (succeeded, pending, failed)
    pub transfer_group: Option<String>,
}

impl Charge {
    pub fn create(c: &Client, params: ChargeParams) -> Result<Charge, Error> {
        return c.post("/charges", params);
    }

    pub fn get(c: &Client, charge_id: &str) -> Result<Charge, Error> {
        return c.get(&format!("/charges/{}", charge_id));
    }

    pub fn update(c: &Client, charge_id: &str, params: ChargeParams) -> Result<Charge, Error> {
        return c.post(&format!("/charges/{}", charge_id), params);
    }

    pub fn capture(c: &Client, charge_id: &str, params: CaptureParams) -> Result<Charge, Error> {
        return c.post(&format!("/charges/{}/capture", charge_id), params);
    }
}
<|endoftext|>