<commit_before>use std::io::{Read, Take};
use std::mem;
use std::vec;
use serde::de;
use serde::de::{DeserializeSeed, SeqVisitor, Visitor};

use super::error::{Error, ResultE};
use super::osc_reader::OscReader;
use super::maybeskipcomma::MaybeSkipComma;

/// Deserializes a single message, within a packet.
pub struct MsgVisitor<'a, R: Read + 'a> {
    read: &'a mut Take<R>,
    state: State,
}

/// Which part of the OSC message is being parsed
enum State {
    /// Deserializing the address pattern.
    Address(String),
    /// Deserializing the typestring.
    Typestring,
    /// Deserializing the argument data.
    /// Each entry in the Vec is the typecode we parsed earlier
    /// We store this as an iterator to avoid tracking the index of the current arg.
    Arguments(MaybeSkipComma<vec::IntoIter<u8>>),
}

/// Struct to deserialize a single element from the OSC message sequence.
/// (e.g. just the address, or the first argument, etc).
enum OscType {
    I32(i32),
    F32(f32),
    String(String),
    Blob(Vec<u8>),
    // TODO: Bundle
}

impl<'a, R> MsgVisitor<'a, R>
    where R: Read + 'a
{
    pub fn new(read: &'a mut Take<R>, address: String) -> Self {
        Self {
            read: read,
            state: State::Address(address),
        }
    }

    fn parse_next(&mut self) -> ResultE<Option<OscType>> {
        let (new_state, osc_type) = match mem::replace(&mut self.state, State::Typestring) {
            State::Address(address) => {
                // yield the address component; advance to the typestring.
                (State::Typestring, Ok(Some(OscType::String(address.clone()))))
            },
            State::Typestring => {
                // parse the type tag
                let tags = self.read.parse_typetag();
                match tags {
                    // Unable to parse type tag
                    Err(err) => (State::Arguments(MaybeSkipComma::new(Vec::with_capacity(0).into_iter())), Err(err)),
                    // Parsed: yield first argument, if it exists, else None.
                    Ok(mut tags) => {
                        let result = match tags.next() {
                            None => Ok(None),
                            Some(tag) => self.parse_arg(tag).map(|arg| Some(arg)),
                        };
                        (State::Arguments(tags), result)
                    }
                }
            },
            State::Arguments(mut tags) => {
                let result = match tags.next() {
                    None => Ok(None),
                    Some(tag) => self.parse_arg(tag).map(|arg| Some(arg)),
                };
                (State::Arguments(tags), result)
            },
        };
        self.state = new_state;
        osc_type
    }
    fn parse_arg(&mut self, typecode: u8) -> ResultE<OscType> {
        match typecode {
            b'i' => self.read.parse_i32().map(|i| { OscType::I32(i) }),
            b'f' => self.read.parse_f32().map(|f| { OscType::F32(f) }),
            b's' => self.read.parse_str().map(|s| { OscType::String(s) }),
            b'b' => self.read.parse_blob().map(|b| { OscType::Blob(b) }),
            c => Err(Error::UnknownType(c)),
        }
    }
}

impl de::Deserializer for OscType {
    type Error = Error;
    // deserializes a single item from the message, consuming self.
    fn deserialize<V>(self, visitor: V) -> ResultE<V::Value>
    where
        V: Visitor
    {
        match self {
            OscType::I32(i) => visitor.visit_i32(i),
            OscType::F32(f) => visitor.visit_f32(f),
            OscType::String(s) => visitor.visit_string(s),
            // TODO: If the user is attempting to deserialize a Vec<u8>, this
            //   will error! We should make use of the deserialize_seq function
            //   in this case.
            OscType::Blob(b) => visitor.visit_byte_buf(b),
        }
    }

    // OSC messages are strongly typed, so we don't make use of any type hints.
    // More info: https://github.com/serde-rs/serde/blob/b7d6c5d9f7b3085a4d40a446eeb95976d2337e07/serde/src/macros.rs#L106
    forward_to_deserialize! {
        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
        seq seq_fixed_size bytes byte_buf map unit_struct newtype_struct
        tuple_struct struct struct_field tuple enum ignored_any
    }
}

impl<'a, R> SeqVisitor for MsgVisitor<'a, R>
    where R: Read + 'a
{
    type Error = Error;
    fn visit_seed<T>(&mut self, seed: T) -> ResultE<Option<T::Value>>
        where T: DeserializeSeed
    {
        // Return None when the message has been fully parsed,
        // else call seed.deserialize to deserialize the next item.
        let value = self.parse_next()?;
        match value {
            // end of sequence
            None => Ok(None),
            Some(osc_arg) => seed.deserialize(osc_arg)
                .map(|value| { Some(value) }),
        }
    }
}
<commit_msg>Make typestrings optional<commit_after>use std::io::{Read, Take};
use std::mem;
use std::vec;
use serde::de;
use serde::de::{DeserializeSeed, SeqVisitor, Visitor};

use super::error::{Error, ResultE};
use super::osc_reader::OscReader;
use super::maybeskipcomma::MaybeSkipComma;

/// Deserializes a single message, within a packet.
pub struct MsgVisitor<'a, R: Read + 'a> {
    read: &'a mut Take<R>,
    state: State,
}

/// Which part of the OSC message is being parsed
enum State {
    /// Deserializing the address pattern.
    Address(String),
    /// Deserializing the typestring.
    Typestring,
    /// Deserializing the argument data.
    /// Each entry in the Vec is the typecode we parsed earlier
    /// We store this as an iterator to avoid tracking the index of the current arg.
    Arguments(MaybeSkipComma<vec::IntoIter<u8>>),
}

/// Struct to deserialize a single element from the OSC message sequence.
/// (e.g. just the address, or the first argument, etc).
enum OscType {
    I32(i32),
    F32(f32),
    String(String),
    Blob(Vec<u8>),
    // TODO: Bundle
}

impl<'a, R> MsgVisitor<'a, R>
    where R: Read + 'a
{
    pub fn new(read: &'a mut Take<R>, address: String) -> Self {
        Self {
            read: read,
            state: State::Address(address),
        }
    }

    fn parse_next(&mut self) -> ResultE<Option<OscType>> {
        let (new_state, osc_type) = match mem::replace(&mut self.state, State::Typestring) {
            State::Address(address) => {
                // yield the address component; advance to the typestring.
                (State::Typestring, Ok(Some(OscType::String(address.clone()))))
            },
            State::Typestring => {
                let empty_typestr = MaybeSkipComma::new(Vec::with_capacity(0).into_iter());
                // If we are at the end of our buffer, then there won't be a typestring
                // and any attempt to parse it would error.
                // But the 1.0 specs recommend typestrings be optional, so return Ok(..)
                if self.read.limit() == 0 {
                    (State::Arguments(empty_typestr), Ok(None))
                } else {
                    // parse the typestring
                    let tags = self.read.parse_typetag();
                    match tags {
                        // Unable to parse type tag
                        Err(err) => (State::Arguments(empty_typestr), Err(err)),
                        // Parsed: yield first argument, if it exists, else None.
                        Ok(mut tags) => {
                            let result = match tags.next() {
                                None => Ok(None),
                                Some(tag) => self.parse_arg(tag).map(|arg| Some(arg)),
                            };
                            (State::Arguments(tags), result)
                        }
                    }
                }
            },
            State::Arguments(mut tags) => {
                let result = match tags.next() {
                    None => Ok(None),
                    Some(tag) => self.parse_arg(tag).map(|arg| Some(arg)),
                };
                (State::Arguments(tags), result)
            },
        };
        self.state = new_state;
        osc_type
    }
    fn parse_arg(&mut self, typecode: u8) -> ResultE<OscType> {
        match typecode {
            b'i' => self.read.parse_i32().map(|i| { OscType::I32(i) }),
            b'f' => self.read.parse_f32().map(|f| { OscType::F32(f) }),
            b's' => self.read.parse_str().map(|s| { OscType::String(s) }),
            b'b' => self.read.parse_blob().map(|b| { OscType::Blob(b) }),
            c => Err(Error::UnknownType(c)),
        }
    }
}

impl de::Deserializer for OscType {
    type Error = Error;
    // deserializes a single item from the message, consuming self.
    fn deserialize<V>(self, visitor: V) -> ResultE<V::Value>
    where
        V: Visitor
    {
        match self {
            OscType::I32(i) => visitor.visit_i32(i),
            OscType::F32(f) => visitor.visit_f32(f),
            OscType::String(s) => visitor.visit_string(s),
            // TODO: If the user is attempting to deserialize a Vec<u8>, this
            //   will error! We should make use of the deserialize_seq function
            //   in this case.
            OscType::Blob(b) => visitor.visit_byte_buf(b),
        }
    }

    // OSC messages are strongly typed, so we don't make use of any type hints.
    // More info: https://github.com/serde-rs/serde/blob/b7d6c5d9f7b3085a4d40a446eeb95976d2337e07/serde/src/macros.rs#L106
    forward_to_deserialize! {
        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit option
        seq seq_fixed_size bytes byte_buf map unit_struct newtype_struct
        tuple_struct struct struct_field tuple enum ignored_any
    }
}

impl<'a, R> SeqVisitor for MsgVisitor<'a, R>
    where R: Read + 'a
{
    type Error = Error;
    fn visit_seed<T>(&mut self, seed: T) -> ResultE<Option<T::Value>>
        where T: DeserializeSeed
    {
        // Return None when the message has been fully parsed,
        // else call seed.deserialize to deserialize the next item.
        let value = self.parse_next()?;
        match value {
            // end of sequence
            None => Ok(None),
            Some(osc_arg) => seed.deserialize(osc_arg)
                .map(|value| { Some(value) }),
        }
    }
}
<|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/. */

use dom::bindings::codegen::BindingDeclarations::HTMLModElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLModElementDerived;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::HTMLModElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLModElement {
    pub htmlelement: HTMLElement
}

impl HTMLModElementDerived for EventTarget {
    fn is_htmlmodelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLModElementTypeId))
    }
}

impl HTMLModElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLModElement {
        HTMLModElement {
            htmlelement: HTMLElement::new_inherited(HTMLModElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLModElement> {
        let element = HTMLModElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLModElementBinding::Wrap)
    }
}

pub trait HTMLModElementMethods {
    fn Cite(&self) -> DOMString;
    fn SetCite(&mut self, _cite: DOMString) -> ErrorResult;
    fn DateTime(&self) -> DOMString;
    fn SetDateTime(&mut self, _datetime: DOMString) -> ErrorResult;
}

impl<'a> HTMLModElementMethods for JSRef<'a, HTMLModElement> {
    fn Cite(&self) -> DOMString {
        "".to_owned()
    }

    fn SetCite(&mut self, _cite: DOMString) -> ErrorResult {
        Ok(())
    }

    fn DateTime(&self) -> DOMString {
        "".to_owned()
    }

    fn SetDateTime(&mut self, _datetime: DOMString) -> ErrorResult {
        Ok(())
    }
}
<commit_msg>Remove needless '&mut self' from HTMLModElementMethods.<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/. */

use dom::bindings::codegen::BindingDeclarations::HTMLModElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLModElementDerived;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::HTMLModElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLModElement {
    pub htmlelement: HTMLElement
}

impl HTMLModElementDerived for EventTarget {
    fn is_htmlmodelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLModElementTypeId))
    }
}

impl HTMLModElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLModElement {
        HTMLModElement {
            htmlelement: HTMLElement::new_inherited(HTMLModElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLModElement> {
        let element = HTMLModElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLModElementBinding::Wrap)
    }
}

pub trait HTMLModElementMethods {
    fn Cite(&self) -> DOMString;
    fn SetCite(&self, _cite: DOMString) -> ErrorResult;
    fn DateTime(&self) -> DOMString;
    fn SetDateTime(&self, _datetime: DOMString) -> ErrorResult;
}

impl<'a> HTMLModElementMethods for JSRef<'a, HTMLModElement> {
    fn Cite(&self) -> DOMString {
        "".to_owned()
    }

    fn SetCite(&self, _cite: DOMString) -> ErrorResult {
        Ok(())
    }

    fn DateTime(&self) -> DOMString {
        "".to_owned()
    }

    fn SetDateTime(&self, _datetime: DOMString) -> ErrorResult {
        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate gcc;

use std::path::Path;
use std::process::Command;

struct Perl {
    bin: String,
}

impl Perl {
    fn new() -> Perl {
        Perl {
            bin: std::env::var("PERL").unwrap_or("perl".to_owned()),
        }
    }

    fn cfg(&self, key: &str) -> String {
        let out = Command::new(&self.bin)
            .arg("-MConfig")
            .arg("-e")
            .arg(format!("print $Config::Config{{{}}}", key))
            .output()
            .unwrap();

        String::from_utf8(out.stdout).unwrap()
    }

    fn run(&self, script: &str) {
        let status = Command::new(&self.bin)
            .arg(script)
            .status()
            .unwrap();
        assert!(status.success());
    }
}

fn build_ouro(perl: &Perl) {
    let mut gcc = gcc::Config::new();

    let ccflags = perl.cfg("ccflags");
    for flag in ccflags.split_whitespace() {
        gcc.flag(flag);
    }

    let archlib = perl.cfg("archlibexp");
    let coreinc = Path::new(&archlib).join("CORE");
    gcc.include(&coreinc);

    gcc.file("ouroboros/libouroboros.c");
    gcc.compile("libouroboros.a");
}

fn main() {
    let perl = Perl::new();

    build_ouro(&perl);

    perl.run("build/regen.pl");

    if perl.cfg("multiplicity") == "true" {
        println!("cargo:rustc-cfg=perl_multiplicity");
    }

    if perl.cfg("useshrplib") == "true" {
        println!("cargo:rustc-cfg=perl_useshrplib");
    }
}
<commit_msg>Add perl libdir to linker search path.<commit_after>extern crate gcc;

use std::path::{ PathBuf, Path };
use std::process::Command;

struct Perl {
    bin: String,
}

impl Perl {
    fn new() -> Perl {
        Perl {
            bin: std::env::var("PERL").unwrap_or("perl".to_owned()),
        }
    }

    fn cfg(&self, key: &str) -> String {
        let out = Command::new(&self.bin)
            .arg("-MConfig")
            .arg("-e")
            .arg(format!("print $Config::Config{{{}}}", key))
            .output()
            .unwrap();

        String::from_utf8(out.stdout).unwrap()
    }

    fn run(&self, script: &str) {
        let status = Command::new(&self.bin)
            .arg(script)
            .status()
            .unwrap();
        assert!(status.success());
    }

    fn path_core(&self) -> PathBuf {
        let archlib = self.cfg("archlibexp");
        Path::new(&archlib).join("CORE")
    }
}

fn build_ouro(perl: &Perl) {
    let mut gcc = gcc::Config::new();

    let ccflags = perl.cfg("ccflags");
    for flag in ccflags.split_whitespace() {
        gcc.flag(flag);
    }

    gcc.include(&perl.path_core());

    gcc.file("ouroboros/libouroboros.c");
    gcc.compile("libouroboros.a");
}

fn main() {
    let perl = Perl::new();

    build_ouro(&perl);

    perl.run("build/regen.pl");

    if perl.cfg("multiplicity") == "true" {
        println!("cargo:rustc-cfg=perl_multiplicity");
    }

    if perl.cfg("useshrplib") == "true" {
        println!("cargo:rustc-cfg=perl_useshrplib");

        // Make sure ld links to libperl that matches current perl interpreter, instead of whatever
        // is libperl version exists in default linker search path. $archlibexp/CORE is hard-coded
        // installation path for default perl so this ought to be enough in most cases.
        println!("cargo:rustc-link-search=native={}", perl.path_core().to_str().unwrap());
    }
}
<|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/. */

use std::path;

use crate::bindgen::bindings::Bindings;
use crate::bindgen::cargo::Cargo;
use crate::bindgen::config::{Braces, Config, Language, Profile, Style};
use crate::bindgen::error::Error;
use crate::bindgen::library::Library;
use crate::bindgen::parser::{self, Parse};

/// A builder for generating a bindings header.
#[derive(Debug, Clone)]
pub struct Builder {
    config: Config,
    srcs: Vec<path::PathBuf>,
    lib: Option<(path::PathBuf, Option<String>)>,
    lib_cargo: Option<Cargo>,
    std_types: bool,
    lockfile: Option<path::PathBuf>,
}

impl Builder {
    #[allow(clippy::new_without_default)]
    pub fn new() -> Builder {
        Builder {
            config: Config::default(),
            srcs: Vec::new(),
            lib: None,
            lib_cargo: None,
            std_types: true,
            lockfile: None,
        }
    }

    #[allow(unused)]
    pub fn with_header<S: AsRef<str>>(mut self, header: S) -> Builder {
        self.config.header = Some(String::from(header.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_no_includes(mut self) -> Builder {
        self.config.no_includes = true;
        self
    }

    #[allow(unused)]
    pub fn with_include<S: AsRef<str>>(mut self, include: S) -> Builder {
        self.config.includes.push(String::from(include.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_sys_include<S: AsRef<str>>(mut self, include: S) -> Builder {
        self.config
            .sys_includes
            .push(String::from(include.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_after_include<S: AsRef<str>>(mut self, line: S) -> Builder {
        self.config.after_includes = Some(String::from(line.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_trailer<S: AsRef<str>>(mut self, trailer: S) -> Builder {
        self.config.trailer = Some(String::from(trailer.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_include_guard<S: AsRef<str>>(mut self, include_guard: S) -> Builder {
        self.config.include_guard = Some(String::from(include_guard.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_pragma_once(mut self, pragma_once: bool) -> Builder {
        self.config.pragma_once = pragma_once;
        self
    }

    #[allow(unused)]
    pub fn with_autogen_warning<S: AsRef<str>>(mut self, autogen_warning: S) -> Builder {
        self.config.autogen_warning = Some(String::from(autogen_warning.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_include_version(mut self, include_version: bool) -> Builder {
        self.config.include_version = include_version;
        self
    }

    #[allow(unused)]
    pub fn with_namespace<S: AsRef<str>>(mut self, namespace: S) -> Builder {
        self.config.namespace = Some(String::from(namespace.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_namespaces<S: AsRef<str>>(mut self, namespaces: &[S]) -> Builder {
        self.config.namespaces = Some(
            namespaces
                .iter()
                .map(|x| String::from(x.as_ref()))
                .collect(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_using_namespaces<S: AsRef<str>>(mut self, namespaces: &[S]) -> Builder {
        self.config.using_namespaces = Some(
            namespaces
                .iter()
                .map(|x| String::from(x.as_ref()))
                .collect(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_braces(mut self, braces: Braces) -> Builder {
        self.config.braces = braces;
        self
    }

    #[allow(unused)]
    pub fn with_line_length(mut self, line_length: usize) -> Builder {
        self.config.line_length = line_length;
        self
    }

    #[allow(unused)]
    pub fn with_tab_width(mut self, tab_width: usize) -> Builder {
        self.config.tab_width = tab_width;
        self
    }

    #[allow(unused)]
    pub fn with_language(mut self, language: Language) -> Builder {
        self.config.language = language;
        self
    }

    #[allow(unused)]
    pub fn with_style(mut self, style: Style) -> Builder {
        self.config.style = style;
        self
    }

    #[allow(unused)]
    pub fn include_item<S: AsRef<str>>(mut self, item_name: S) -> Builder {
        self.config
            .export
            .include
            .push(String::from(item_name.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn exclude_item<S: AsRef<str>>(mut self, item_name: S) -> Builder {
        self.config
            .export
            .exclude
            .push(String::from(item_name.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn rename_item<S: AsRef<str>>(mut self, from: S, to: S) -> Builder {
        self.config
            .export
            .rename
            .insert(String::from(from.as_ref()), String::from(to.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_item_prefix<S: AsRef<str>>(mut self, prefix: S) -> Builder {
        self.config.export.prefix = Some(String::from(prefix.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_parse_deps(mut self, parse_deps: bool) -> Builder {
        self.config.parse.parse_deps = parse_deps;
        self
    }

    #[allow(unused)]
    pub fn with_parse_include<S: AsRef<str>>(mut self, include: &[S]) -> Builder {
        self.config.parse.include =
            Some(include.iter().map(|x| String::from(x.as_ref())).collect());
        self
    }

    #[allow(unused)]
    pub fn with_parse_exclude<S: AsRef<str>>(mut self, exclude: &[S]) -> Builder {
        self.config.parse.exclude = exclude.iter().map(|x| String::from(x.as_ref())).collect();
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand<S: AsRef<str>>(mut self, expand: &[S]) -> Builder {
        self.config.parse.expand.crates = expand.iter().map(|x| String::from(x.as_ref())).collect();
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand_all_features(mut self, expand_all_features: bool) -> Builder {
        self.config.parse.expand.all_features = expand_all_features;
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand_default_features(mut self, expand_default_features: bool) -> Builder {
        self.config.parse.expand.default_features = expand_default_features;
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand_features<S: AsRef<str>>(mut self, expand_features: &[S]) -> Builder {
        self.config.parse.expand.features = Some(
            expand_features
                .iter()
                .map(|x| String::from(x.as_ref()))
                .collect(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand_profile(mut self, profile: Profile) -> Builder {
        self.config.parse.expand.profile = profile;
        self
    }

    #[allow(unused)]
    pub fn with_parse_extra_bindings<S: AsRef<str>>(mut self, extra_bindings: &[S]) -> Builder {
        self.config.parse.extra_bindings = extra_bindings
            .iter()
            .map(|x| String::from(x.as_ref()))
            .collect();
        self
    }

    #[allow(unused)]
    pub fn with_only_target_dependencies(mut self, only_target_dependencies: bool) -> Builder {
        self.config.only_target_dependencies = only_target_dependencies;
        self
    }

    #[allow(unused)]
    pub fn with_documentation(mut self, documentation: bool) -> Builder {
        self.config.documentation = documentation;
        self
    }

    #[allow(unused)]
    pub fn with_target_os_define(mut self, platform: &str, preprocessor_define: &str) -> Builder {
        self.config.defines.insert(
            format!("target_os = {}", platform),
            preprocessor_define.to_owned(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_define(mut self, key: &str, value: &str, preprocessor_define: &str) -> Builder {
        self.config.defines.insert(
            format!("{} = {}", key, value),
            preprocessor_define.to_owned(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_config(mut self, config: Config) -> Builder {
        self.config = config;
        self
    }

    #[allow(unused)]
    pub fn with_std_types(mut self, std_types: bool) -> Builder {
        self.std_types = std_types;
        self
    }

    #[allow(unused)]
    pub fn with_src<P: AsRef<path::Path>>(mut self, src: P) -> Builder {
        self.srcs.push(src.as_ref().to_owned());
        self
    }

    #[allow(unused)]
    pub fn with_crate<P: AsRef<path::Path>>(mut self, lib_dir: P) -> Builder {
        debug_assert!(self.lib.is_none());
        debug_assert!(self.lib_cargo.is_none());
        self.lib = Some((path::PathBuf::from(lib_dir.as_ref()), None));
        self
    }

    #[allow(unused)]
    pub fn with_crate_and_name<P: AsRef<path::Path>, S: AsRef<str>>(
        mut self,
        lib_dir: P,
        binding_lib_name: S,
    ) -> Builder {
        debug_assert!(self.lib.is_none());
        debug_assert!(self.lib_cargo.is_none());
        self.lib = Some((
            path::PathBuf::from(lib_dir.as_ref()),
            Some(String::from(binding_lib_name.as_ref())),
        ));
        self
    }

    #[allow(unused)]
    pub(crate) fn with_cargo(mut self, lib: Cargo) -> Builder {
        debug_assert!(self.lib.is_none());
        debug_assert!(self.lib_cargo.is_none());
        self.lib_cargo = Some(lib);
        self
    }

    #[allow(unused)]
    pub fn with_lockfile<P: AsRef<path::Path>>(mut self, lockfile: P) -> Builder {
        debug_assert!(self.lockfile.is_none());
        debug_assert!(self.lib_cargo.is_none());
        self.lockfile = Some(path::PathBuf::from(lockfile.as_ref()));
        self
    }

    pub fn generate(self) -> Result<Bindings, Error> {
        let mut result = Parse::new();

        if self.std_types {
            result.add_std_types();
        }

        for x in &self.srcs {
            result.extend_with(&parser::parse_src(x, &self.config)?);
        }

        if let Some((lib_dir, binding_lib_name)) = self.lib.clone() {
            let lockfile = self.lockfile.as_ref().and_then(|p| p.to_str());

            let cargo = Cargo::load(
                &lib_dir,
                lockfile,
                binding_lib_name.as_deref(),
                self.config.parse.parse_deps,
                self.config.parse.clean,
                self.config.only_target_dependencies,
                /* existing_metadata = */ None,
            )?;

            result.extend_with(&parser::parse_lib(cargo, &self.config)?);
        } else if let Some(cargo) = self.lib_cargo.clone() {
            result.extend_with(&parser::parse_lib(cargo, &self.config)?);
        }

        Library::new(
            self.config,
            result.constants,
            result.globals,
            result.enums,
            result.structs,
            result.unions,
            result.opaque_items,
            result.typedefs,
            result.functions,
        )
        .generate()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn with_style() {
        assert_eq!(
            Style::Tag,
            Builder::new().with_style(Style::Tag).config.style
        );
    }
}
<commit_msg>Add with_cpp_compat to the builder<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/. */

use std::path;

use crate::bindgen::bindings::Bindings;
use crate::bindgen::cargo::Cargo;
use crate::bindgen::config::{Braces, Config, Language, Profile, Style};
use crate::bindgen::error::Error;
use crate::bindgen::library::Library;
use crate::bindgen::parser::{self, Parse};

/// A builder for generating a bindings header.
#[derive(Debug, Clone)]
pub struct Builder {
    config: Config,
    srcs: Vec<path::PathBuf>,
    lib: Option<(path::PathBuf, Option<String>)>,
    lib_cargo: Option<Cargo>,
    std_types: bool,
    lockfile: Option<path::PathBuf>,
}

impl Builder {
    #[allow(clippy::new_without_default)]
    pub fn new() -> Builder {
        Builder {
            config: Config::default(),
            srcs: Vec::new(),
            lib: None,
            lib_cargo: None,
            std_types: true,
            lockfile: None,
        }
    }

    #[allow(unused)]
    pub fn with_header<S: AsRef<str>>(mut self, header: S) -> Builder {
        self.config.header = Some(String::from(header.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_no_includes(mut self) -> Builder {
        self.config.no_includes = true;
        self
    }

    #[allow(unused)]
    pub fn with_include<S: AsRef<str>>(mut self, include: S) -> Builder {
        self.config.includes.push(String::from(include.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_sys_include<S: AsRef<str>>(mut self, include: S) -> Builder {
        self.config
            .sys_includes
            .push(String::from(include.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_after_include<S: AsRef<str>>(mut self, line: S) -> Builder {
        self.config.after_includes = Some(String::from(line.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_trailer<S: AsRef<str>>(mut self, trailer: S) -> Builder {
        self.config.trailer = Some(String::from(trailer.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_include_guard<S: AsRef<str>>(mut self, include_guard: S) -> Builder {
        self.config.include_guard = Some(String::from(include_guard.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_pragma_once(mut self, pragma_once: bool) -> Builder {
        self.config.pragma_once = pragma_once;
        self
    }

    #[allow(unused)]
    pub fn with_autogen_warning<S: AsRef<str>>(mut self, autogen_warning: S) -> Builder {
        self.config.autogen_warning = Some(String::from(autogen_warning.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_include_version(mut self, include_version: bool) -> Builder {
        self.config.include_version = include_version;
        self
    }

    #[allow(unused)]
    pub fn with_namespace<S: AsRef<str>>(mut self, namespace: S) -> Builder {
        self.config.namespace = Some(String::from(namespace.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_namespaces<S: AsRef<str>>(mut self, namespaces: &[S]) -> Builder {
        self.config.namespaces = Some(
            namespaces
                .iter()
                .map(|x| String::from(x.as_ref()))
                .collect(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_using_namespaces<S: AsRef<str>>(mut self, namespaces: &[S]) -> Builder {
        self.config.using_namespaces = Some(
            namespaces
                .iter()
                .map(|x| String::from(x.as_ref()))
                .collect(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_braces(mut self, braces: Braces) -> Builder {
        self.config.braces = braces;
        self
    }

    #[allow(unused)]
    pub fn with_line_length(mut self, line_length: usize) -> Builder {
        self.config.line_length = line_length;
        self
    }

    #[allow(unused)]
    pub fn with_tab_width(mut self, tab_width: usize) -> Builder {
        self.config.tab_width = tab_width;
        self
    }

    #[allow(unused)]
    pub fn with_language(mut self, language: Language) -> Builder {
        self.config.language = language;
        self
    }

    #[allow(unused)]
    pub fn with_cpp_compat(mut self, cpp_compat: bool) -> Builder {
        self.config.cpp_compat = cpp_compat;
        self
    }

    #[allow(unused)]
    pub fn with_style(mut self, style: Style) -> Builder {
        self.config.style = style;
        self
    }

    #[allow(unused)]
    pub fn include_item<S: AsRef<str>>(mut self, item_name: S) -> Builder {
        self.config
            .export
            .include
            .push(String::from(item_name.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn exclude_item<S: AsRef<str>>(mut self, item_name: S) -> Builder {
        self.config
            .export
            .exclude
            .push(String::from(item_name.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn rename_item<S: AsRef<str>>(mut self, from: S, to: S) -> Builder {
        self.config
            .export
            .rename
            .insert(String::from(from.as_ref()), String::from(to.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_item_prefix<S: AsRef<str>>(mut self, prefix: S) -> Builder {
        self.config.export.prefix = Some(String::from(prefix.as_ref()));
        self
    }

    #[allow(unused)]
    pub fn with_parse_deps(mut self, parse_deps: bool) -> Builder {
        self.config.parse.parse_deps = parse_deps;
        self
    }

    #[allow(unused)]
    pub fn with_parse_include<S: AsRef<str>>(mut self, include: &[S]) -> Builder {
        self.config.parse.include =
            Some(include.iter().map(|x| String::from(x.as_ref())).collect());
        self
    }

    #[allow(unused)]
    pub fn with_parse_exclude<S: AsRef<str>>(mut self, exclude: &[S]) -> Builder {
        self.config.parse.exclude = exclude.iter().map(|x| String::from(x.as_ref())).collect();
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand<S: AsRef<str>>(mut self, expand: &[S]) -> Builder {
        self.config.parse.expand.crates = expand.iter().map(|x| String::from(x.as_ref())).collect();
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand_all_features(mut self, expand_all_features: bool) -> Builder {
        self.config.parse.expand.all_features = expand_all_features;
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand_default_features(mut self, expand_default_features: bool) -> Builder {
        self.config.parse.expand.default_features = expand_default_features;
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand_features<S: AsRef<str>>(mut self, expand_features: &[S]) -> Builder {
        self.config.parse.expand.features = Some(
            expand_features
                .iter()
                .map(|x| String::from(x.as_ref()))
                .collect(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_parse_expand_profile(mut self, profile: Profile) -> Builder {
        self.config.parse.expand.profile = profile;
        self
    }

    #[allow(unused)]
    pub fn with_parse_extra_bindings<S: AsRef<str>>(mut self, extra_bindings: &[S]) -> Builder {
        self.config.parse.extra_bindings = extra_bindings
            .iter()
            .map(|x| String::from(x.as_ref()))
            .collect();
        self
    }

    #[allow(unused)]
    pub fn with_only_target_dependencies(mut self, only_target_dependencies: bool) -> Builder {
        self.config.only_target_dependencies = only_target_dependencies;
        self
    }

    #[allow(unused)]
    pub fn with_documentation(mut self, documentation: bool) -> Builder {
        self.config.documentation = documentation;
        self
    }

    #[allow(unused)]
    pub fn with_target_os_define(mut self, platform: &str, preprocessor_define: &str) -> Builder {
        self.config.defines.insert(
            format!("target_os = {}", platform),
            preprocessor_define.to_owned(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_define(mut self, key: &str, value: &str, preprocessor_define: &str) -> Builder {
        self.config.defines.insert(
            format!("{} = {}", key, value),
            preprocessor_define.to_owned(),
        );
        self
    }

    #[allow(unused)]
    pub fn with_config(mut self, config: Config) -> Builder {
        self.config = config;
        self
    }

    #[allow(unused)]
    pub fn with_std_types(mut self, std_types: bool) -> Builder {
        self.std_types = std_types;
        self
    }

    #[allow(unused)]
    pub fn with_src<P: AsRef<path::Path>>(mut self, src: P) -> Builder {
        self.srcs.push(src.as_ref().to_owned());
        self
    }

    #[allow(unused)]
    pub fn with_crate<P: AsRef<path::Path>>(mut self, lib_dir: P) -> Builder {
        debug_assert!(self.lib.is_none());
        debug_assert!(self.lib_cargo.is_none());
        self.lib = Some((path::PathBuf::from(lib_dir.as_ref()), None));
        self
    }

    #[allow(unused)]
    pub fn with_crate_and_name<P: AsRef<path::Path>, S: AsRef<str>>(
        mut self,
        lib_dir: P,
        binding_lib_name: S,
    ) -> Builder {
        debug_assert!(self.lib.is_none());
        debug_assert!(self.lib_cargo.is_none());
        self.lib = Some((
            path::PathBuf::from(lib_dir.as_ref()),
            Some(String::from(binding_lib_name.as_ref())),
        ));
        self
    }

    #[allow(unused)]
    pub(crate) fn with_cargo(mut self, lib: Cargo) -> Builder {
        debug_assert!(self.lib.is_none());
        debug_assert!(self.lib_cargo.is_none());
        self.lib_cargo = Some(lib);
        self
    }

    #[allow(unused)]
    pub fn with_lockfile<P: AsRef<path::Path>>(mut self, lockfile: P) -> Builder {
        debug_assert!(self.lockfile.is_none());
        debug_assert!(self.lib_cargo.is_none());
        self.lockfile = Some(path::PathBuf::from(lockfile.as_ref()));
        self
    }

    pub fn generate(self) -> Result<Bindings, Error> {
        let mut result = Parse::new();

        if self.std_types {
            result.add_std_types();
        }

        for x in &self.srcs {
            result.extend_with(&parser::parse_src(x, &self.config)?);
        }

        if let Some((lib_dir, binding_lib_name)) = self.lib.clone() {
            let lockfile = self.lockfile.as_ref().and_then(|p| p.to_str());

            let cargo = Cargo::load(
                &lib_dir,
                lockfile,
                binding_lib_name.as_deref(),
                self.config.parse.parse_deps,
                self.config.parse.clean,
                self.config.only_target_dependencies,
                /* existing_metadata = */ None,
            )?;

            result.extend_with(&parser::parse_lib(cargo, &self.config)?);
        } else if let Some(cargo) = self.lib_cargo.clone() {
            result.extend_with(&parser::parse_lib(cargo, &self.config)?);
        }

        Library::new(
            self.config,
            result.constants,
            result.globals,
            result.enums,
            result.structs,
            result.unions,
            result.opaque_items,
            result.typedefs,
            result.functions,
        )
        .generate()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn with_style() {
        assert_eq!(
            Style::Tag,
            Builder::new().with_style(Style::Tag).config.style
        );
    }
}
<|endoftext|>


<commit_before>// TODO: Make this non public
pub mod file_naming;

use std::collections::HashMap;
use self::file_naming::{FileName, FileType, FileNameParser};

pub struct BackupSet {
    pub file_type : FileType,
    pub time : String,
    pub start_time : String,
    pub end_time : String,
    pub compressed : bool,
    pub encrypted : bool,
    pub partial : bool,
    pub manifest_path : String,
    volumes_paths : HashMap<i32, String>,
    info_set : bool,    // true if informations are set
}

impl BackupSet {
    pub fn new() -> Self {
        BackupSet{
            file_type : FileType::Full,
            time : String::new(),
            start_time : String::new(),
            end_time : String::new(),
            compressed : false,
            encrypted : false,
            partial : false,
            manifest_path : String::new(),
            volumes_paths : HashMap::new(),
            info_set : false
        }
    }

    /// Add a filename to given set. Return true if it fits.
    ///
    /// The filename will match the given set if it has the right
    /// times and is of the right type. The information will be set
    /// from the first filename given.
    pub fn add_filename(&mut self, fname : &str, pr : &FileName) -> bool {
        if !self.info_set {
            self.set_info(pr);
        }
        else {
            // check if the file is from the same backup set
            if self.file_type != pr.file_type ||
                self.time != pr.time ||
                self.start_time != pr.start_time ||
                self.end_time != pr.end_time {
                    return false;
            }
            else {
                // fix encrypted flag
                if self.encrypted != pr.encrypted &&
                    self.partial && pr.encrypted {
                        self.encrypted = pr.encrypted;
                    }
            }
        }
        // set manifest or volume number
        if pr.manifest {
            self.manifest_path = fname.to_owned();
        }
        else {
            self.volumes_paths.insert(pr.volume_number, fname.to_owned());
        }
        true
    }

    pub fn is_complete(&self) -> bool {
        !self.manifest_path.is_empty()
    }

    pub fn get_time(&self) -> &str {
        if self.time.is_empty() {
            self.end_time.as_ref()
        }
        else {
            self.time.as_ref()
        }
    }

    fn set_info(&mut self, fname : &FileName) {
        self.file_type = fname.file_type;
        self.time = fname.time.clone();
        self.start_time = fname.start_time.clone();
        self.end_time = fname.end_time.clone();
        self.compressed = fname.compressed;
        self.encrypted = fname.encrypted;
        self.partial = fname.partial;
        self.info_set = true;
    }
}

pub struct BackupChain {
    fullset : BackupSet,
    incset_list : Vec<BackupSet>,
    start_time : String,
    end_time : String
}

impl BackupChain {
    /// Create a new BackupChain starting from a full backup set.
    pub fn new(fullset : BackupSet) -> Self {
        assert_eq!(fullset.file_type, FileType::Full);
        let time = fullset.time.clone();

        BackupChain{
            fullset : fullset,
            incset_list : Vec::new(),
            start_time : time.clone(),
            end_time : time
        }
    }

    /// Adds the given incremental backkup element to the backup chain if possible,
    /// returns it back otherwise.
    pub fn add_inc(&mut self, incset : BackupSet) -> Option<BackupSet> {
        if self.end_time == incset.start_time {
            self.end_time = incset.time.clone();
            self.incset_list.push(incset);
            None
        }
        else {
            // replace the last element if the end time comes before
            let replace_last = self.incset_list.last().map_or(false,
                |last| incset.start_time == last.start_time && incset.end_time > last.end_time);
            if replace_last {
                self.end_time = incset.time.clone();
                self.incset_list.pop();
                self.incset_list.push(incset);
                None
            }
            else {
                // ignore the given incremental backup set
                Some(incset)
            }
        }
    }
}

pub type FileNameList = Vec<String>;
type BackupSetList = Vec<BackupSet>;
type BackupChains = Vec<BackupChain>;

pub struct CollectionsStatus;

impl CollectionsStatus {
    pub fn compute_backup_chains(&mut self, filename_list : &FileNameList) {
        let mut sets = self.compute_backup_sets(filename_list);
        self.sort_backup_sets(&mut sets);
        self.add_to_chains(sets);
    }

    fn compute_backup_sets(&self, filename_list : &FileNameList) -> BackupSetList {
        let mut sets = BackupSetList::new();
        let parser = FileNameParser::new();
        for filename in filename_list.iter() {
            if let Some(filename_info) = parser.parse(filename.as_ref()) {
                let mut inserted = false;
                for set in sets.iter_mut() {
                    if set.add_filename(filename.as_ref(), &filename_info) {
                        inserted = true;
                        break;
                    }
                }
                if !inserted {
                    let mut new_set = BackupSet::new();
                    new_set.add_filename(filename.as_ref(), &filename_info);
                    sets.push(new_set);
                }
            }
        }
        sets
    }

    fn sort_backup_sets(&self, set_list : &mut BackupSetList) {
        set_list.sort_by(|a, b| a.get_time().cmp(b.get_time()));
    }

    fn add_to_chains(&self, set_list : BackupSetList) {
        let mut chains = BackupChains::new();
        for set in set_list.into_iter() {
            match set.file_type {
                FileType::Full => {
                    let new_chain = BackupChain::new(set);
                    chains.push(new_chain);
                }
                FileType::Inc => {
                    let mut rejected_set = Some(set);
                    for chain in chains.iter_mut() {
                        rejected_set = chain.add_inc(rejected_set.unwrap());
                        if rejected_set.is_none() {
                            break;
                        }
                    }
                    if let Some(_) = rejected_set {
                        // TODO: add to orphaned sets
                    }
                }
                _ => { continue; }
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::BackupSet;
    use super::file_naming::{FileType, FileNameParser};

    #[test]
    fn parse_and_add() {
        let full1_name = "duplicity-full.20150617T182545Z.vol1.difftar.gz";
        let manifest1_name = "duplicity-full.20150617T182545Z.manifest";
        let inc1_name = "duplicity-inc.20150617T182629Z.to.20150617T182650Z.vol1.difftar.gz";

        let parser = FileNameParser::new();
        let full1 = parser.parse(full1_name).unwrap();
        let manifest1 = parser.parse(manifest1_name).unwrap();
        let inc1 = parser.parse(inc1_name).unwrap();

        let mut set = BackupSet::new();
        // add to set
        assert!(set.add_filename(full1_name, &full1));
        assert!(set.add_filename(manifest1_name, &manifest1));
        assert!(!set.add_filename(inc1_name, &inc1));
        // test results
        assert_eq!(set.file_type, FileType::Full);
        assert_eq!(set.time, "20150617t182545z");
        assert_eq!(set.start_time, "");
        assert_eq!(set.end_time, "");
        assert!(set.compressed);
        assert!(!set.encrypted);
        assert!(!set.partial);
        assert_eq!(set.manifest_path, manifest1_name);
    }
}
<commit_msg>Completed first draft of CollectionStatus<commit_after>// TODO: Make this non public
pub mod file_naming;

use std::collections::HashMap;
use self::file_naming::{FileName, FileType, FileNameParser};

pub struct BackupSet {
    pub file_type : FileType,
    pub time : String,
    pub start_time : String,
    pub end_time : String,
    pub compressed : bool,
    pub encrypted : bool,
    pub partial : bool,
    pub manifest_path : String,
    volumes_paths : HashMap<i32, String>,
    info_set : bool,    // true if informations are set
}

impl BackupSet {
    pub fn new() -> Self {
        BackupSet{
            file_type : FileType::Full,
            time : String::new(),
            start_time : String::new(),
            end_time : String::new(),
            compressed : false,
            encrypted : false,
            partial : false,
            manifest_path : String::new(),
            volumes_paths : HashMap::new(),
            info_set : false
        }
    }

    /// Add a filename to given set. Return true if it fits.
    ///
    /// The filename will match the given set if it has the right
    /// times and is of the right type. The information will be set
    /// from the first filename given.
    pub fn add_filename(&mut self, fname : &str, pr : &FileName) -> bool {
        if !self.info_set {
            self.set_info(pr);
        }
        else {
            // check if the file is from the same backup set
            if self.file_type != pr.file_type ||
                self.time != pr.time ||
                self.start_time != pr.start_time ||
                self.end_time != pr.end_time {
                    return false;
            }
            else {
                // fix encrypted flag
                if self.encrypted != pr.encrypted &&
                    self.partial && pr.encrypted {
                        self.encrypted = pr.encrypted;
                    }
            }
        }
        // set manifest or volume number
        if pr.manifest {
            self.manifest_path = fname.to_owned();
        }
        else {
            self.volumes_paths.insert(pr.volume_number, fname.to_owned());
        }
        true
    }

    pub fn is_complete(&self) -> bool {
        !self.manifest_path.is_empty()
    }

    pub fn get_time(&self) -> &str {
        if self.time.is_empty() {
            self.end_time.as_ref()
        }
        else {
            self.time.as_ref()
        }
    }

    fn set_info(&mut self, fname : &FileName) {
        self.file_type = fname.file_type;
        self.time = fname.time.clone();
        self.start_time = fname.start_time.clone();
        self.end_time = fname.end_time.clone();
        self.compressed = fname.compressed;
        self.encrypted = fname.encrypted;
        self.partial = fname.partial;
        self.info_set = true;
    }
}

pub struct BackupChain {
    fullset : BackupSet,
    incset_list : Vec<BackupSet>,
    start_time : String,
    end_time : String
}

impl BackupChain {
    /// Create a new BackupChain starting from a full backup set.
    pub fn new(fullset : BackupSet) -> Self {
        assert_eq!(fullset.file_type, FileType::Full);
        let time = fullset.time.clone();

        BackupChain{
            fullset : fullset,
            incset_list : Vec::new(),
            start_time : time.clone(),
            end_time : time
        }
    }

    /// Adds the given incremental backkup element to the backup chain if possible,
    /// returns it back otherwise.
    pub fn add_inc(&mut self, incset : BackupSet) -> Option<BackupSet> {
        if self.end_time == incset.start_time {
            self.end_time = incset.time.clone();
            self.incset_list.push(incset);
            None
        }
        else {
            // replace the last element if the end time comes before
            let replace_last = self.incset_list.last().map_or(false,
                |last| incset.start_time == last.start_time && incset.end_time > last.end_time);
            if replace_last {
                self.end_time = incset.time.clone();
                self.incset_list.pop();
                self.incset_list.push(incset);
                None
            }
            else {
                // ignore the given incremental backup set
                Some(incset)
            }
        }
    }
}

pub type FileNameList = Vec<String>;
type BackupSetList = Vec<BackupSet>;
type BackupChains = Vec<BackupChain>;

pub struct CollectionsStatus {
    backup_chains : BackupChains,
}

impl CollectionsStatus {
    pub fn new() -> Self {
        CollectionsStatus {
            backup_chains : Vec::new()
        }
    }

    pub fn compute_backup_chains(&mut self, filename_list : &FileNameList) {
        let mut sets = self.compute_backup_sets(filename_list);
        self.sort_backup_sets(&mut sets);
        let mut chains = self.add_to_chains(sets);
        self.get_sorted_chains(&mut chains);
        self.backup_chains = chains;
    }

    fn compute_backup_sets(&self, filename_list : &FileNameList) -> BackupSetList {
        let mut sets = BackupSetList::new();
        let parser = FileNameParser::new();
        for filename in filename_list.iter() {
            if let Some(filename_info) = parser.parse(filename.as_ref()) {
                let mut inserted = false;
                for set in sets.iter_mut() {
                    if set.add_filename(filename.as_ref(), &filename_info) {
                        inserted = true;
                        break;
                    }
                }
                if !inserted {
                    let mut new_set = BackupSet::new();
                    new_set.add_filename(filename.as_ref(), &filename_info);
                    sets.push(new_set);
                }
            }
        }
        sets
    }

    fn sort_backup_sets(&self, set_list : &mut BackupSetList) {
        set_list.sort_by(|a, b| a.get_time().cmp(b.get_time()));
    }

    fn add_to_chains(&self, set_list : BackupSetList) -> BackupChains {
        let mut chains = BackupChains::new();
        for set in set_list.into_iter() {
            match set.file_type {
                FileType::Full => {
                    let new_chain = BackupChain::new(set);
                    chains.push(new_chain);
                }
                FileType::Inc => {
                    let mut rejected_set = Some(set);
                    for chain in chains.iter_mut() {
                        rejected_set = chain.add_inc(rejected_set.unwrap());
                        if rejected_set.is_none() {
                            break;
                        }
                    }
                    if let Some(_) = rejected_set {
                        // TODO: add to orphaned sets
                    }
                }
                _ => { continue; }
            }
        }
        chains
    }

    fn get_sorted_chains(&self, chains : &mut BackupChains) {
        chains.sort_by(|a, b| a.end_time.cmp(&b.end_time));
    }
}

#[cfg(test)]
mod test {
    use super::BackupSet;
    use super::file_naming::{FileType, FileNameParser};

    #[test]
    fn parse_and_add() {
        let full1_name = "duplicity-full.20150617T182545Z.vol1.difftar.gz";
        let manifest1_name = "duplicity-full.20150617T182545Z.manifest";
        let inc1_name = "duplicity-inc.20150617T182629Z.to.20150617T182650Z.vol1.difftar.gz";

        let parser = FileNameParser::new();
        let full1 = parser.parse(full1_name).unwrap();
        let manifest1 = parser.parse(manifest1_name).unwrap();
        let inc1 = parser.parse(inc1_name).unwrap();

        let mut set = BackupSet::new();
        // add to set
        assert!(set.add_filename(full1_name, &full1));
        assert!(set.add_filename(manifest1_name, &manifest1));
        assert!(!set.add_filename(inc1_name, &inc1));
        // test results
        assert_eq!(set.file_type, FileType::Full);
        assert_eq!(set.time, "20150617t182545z");
        assert_eq!(set.start_time, "");
        assert_eq!(set.end_time, "");
        assert!(set.compressed);
        assert!(!set.encrypted);
        assert!(!set.partial);
        assert_eq!(set.manifest_path, manifest1_name);
    }
}
<|endoftext|>


<commit_before>use std::vec;
use std::iter::FromIterator;
use std::io::Read;
use hyper::client::response::Response as HyperResponse;
use hyper::status::StatusCode;
use rustc_serialize::json;
use super::{FromJson};
use error::{self, TwitterErrors};
use error::Error::*;

header! { (XRateLimitLimit, "X-Rate-Limit-Limit") => [i32] }
header! { (XRateLimitRemaining, "X-Rate-Limit-Remaining") => [i32] }
header! { (XRateLimitReset, "X-Rate-Limit-Reset") => [i32] }

///A helper struct to wrap response data with accompanying rate limit information.
#[derive(Debug)]
pub struct Response<T> {
    ///The rate limit ceiling for the given request.
    pub rate_limit: i32,
    ///The number of requests left for the 15-minute window.
    pub rate_limit_remaining: i32,
    ///The UTC Unix timestamp at which the rate window resets.
    pub rate_limit_reset: i32,
    ///The decoded response from the request.
    pub response: T,
}

///Iterator returned by calling `.into_iter()` on a `Response<Vec<T>>`.
pub struct ResponseIter<T> {
    rate_limit: i32,
    rate_limit_remaining: i32,
    rate_limit_reset: i32,
    resp_iter: vec::IntoIter<T>,
}

impl<T> ResponseIter<T> {
    pub fn len(&self) -> usize {
        self.resp_iter.len()
    }
}

impl<T> Iterator for ResponseIter<T> {
    type Item = Response<T>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(resp) = self.resp_iter.next() {
            Some(Response {
                rate_limit: self.rate_limit,
                rate_limit_remaining: self.rate_limit_remaining,
                rate_limit_reset: self.rate_limit_reset,
                response: resp,
            })
        }
        else {
            None
        }
    }
}

impl<T> IntoIterator for Response<Vec<T>> {
    type Item = Response<T>;
    type IntoIter = ResponseIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        ResponseIter {
            rate_limit: self.rate_limit,
            rate_limit_remaining: self.rate_limit_remaining,
            rate_limit_reset: self.rate_limit_reset,
            resp_iter: self.response.into_iter(),
        }
    }
}

impl<T> FromIterator<Response<T>> for Response<Vec<T>> {
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item=Response<T>>
    {
        let mut resp = Response {
            rate_limit: -1,
            rate_limit_remaining: -1,
            rate_limit_reset: -1,
            response: Vec::new(),
        };

        for item in iter {
            resp.rate_limit = item.rate_limit;
            resp.rate_limit_remaining = item.rate_limit_remaining;
            resp.rate_limit_reset = item.rate_limit_reset;
            resp.response.push(item.response);
        }

        resp
    }
}

///With the given response struct, parse it into a String.
pub fn response_raw(resp: &mut HyperResponse) -> Result<String, error::Error> {
    let mut full_resp = String::new();
    try!(resp.read_to_string(&mut full_resp));

    if let Ok(err) = json::decode::<TwitterErrors>(&full_resp) {
        return Err(TwitterError(err));
    }

    match resp.status {
        StatusCode::Ok | StatusCode::NotModified => (),
        _ => return Err(BadStatus(resp.status)),
    }

    Ok(full_resp)
}

///With the given response struct, parse it into the desired format and
///return it along with rate limit information.
pub fn parse_response<T: FromJson>(resp: &mut HyperResponse) -> Result<Response<T>, error::Error> {
    let resp_str = try!(response_raw(resp));

    Ok(Response {
        rate_limit: resp.headers.get::<XRateLimitLimit>().map_or(-1, |h| h.0),
        rate_limit_remaining: resp.headers.get::<XRateLimitRemaining>().map_or(-1, |h| h.0),
        rate_limit_reset: resp.headers.get::<XRateLimitReset>().map_or(-1, |h| h.0),
        response: try!(T::from_str(&resp_str)),
    })
}
<commit_msg>ResponseIter gains some extra iterator traits from vec::IntoIter<commit_after>use std::vec;
use std::iter::FromIterator;
use std::io::Read;
use hyper::client::response::Response as HyperResponse;
use hyper::status::StatusCode;
use rustc_serialize::json;
use super::{FromJson};
use error::{self, TwitterErrors};
use error::Error::*;

header! { (XRateLimitLimit, "X-Rate-Limit-Limit") => [i32] }
header! { (XRateLimitRemaining, "X-Rate-Limit-Remaining") => [i32] }
header! { (XRateLimitReset, "X-Rate-Limit-Reset") => [i32] }

///A helper struct to wrap response data with accompanying rate limit information.
#[derive(Debug)]
pub struct Response<T> {
    ///The rate limit ceiling for the given request.
    pub rate_limit: i32,
    ///The number of requests left for the 15-minute window.
    pub rate_limit_remaining: i32,
    ///The UTC Unix timestamp at which the rate window resets.
    pub rate_limit_reset: i32,
    ///The decoded response from the request.
    pub response: T,
}

///Iterator returned by calling `.into_iter()` on a `Response<Vec<T>>`.
pub struct ResponseIter<T> {
    rate_limit: i32,
    rate_limit_remaining: i32,
    rate_limit_reset: i32,
    resp_iter: vec::IntoIter<T>,
}

impl<T> Iterator for ResponseIter<T> {
    type Item = Response<T>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(resp) = self.resp_iter.next() {
            Some(Response {
                rate_limit: self.rate_limit,
                rate_limit_remaining: self.rate_limit_remaining,
                rate_limit_reset: self.rate_limit_reset,
                response: resp,
            })
        }
        else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.resp_iter.size_hint()
    }
}

impl<T> DoubleEndedIterator for ResponseIter<T> {
    fn next_back(&mut self) -> Option<Self::Item> {
        if let Some(resp) = self.resp_iter.next_back() {
            Some(Response {
                rate_limit: self.rate_limit,
                rate_limit_remaining: self.rate_limit_remaining,
                rate_limit_reset: self.rate_limit_reset,
                response: resp,
            })
        }
        else {
            None
        }
    }
}

impl<T> ExactSizeIterator for ResponseIter<T> {
    fn len(&self) -> usize {
        self.resp_iter.len()
    }
}

impl<T> IntoIterator for Response<Vec<T>> {
    type Item = Response<T>;
    type IntoIter = ResponseIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        ResponseIter {
            rate_limit: self.rate_limit,
            rate_limit_remaining: self.rate_limit_remaining,
            rate_limit_reset: self.rate_limit_reset,
            resp_iter: self.response.into_iter(),
        }
    }
}

impl<T> FromIterator<Response<T>> for Response<Vec<T>> {
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item=Response<T>>
    {
        let mut resp = Response {
            rate_limit: -1,
            rate_limit_remaining: -1,
            rate_limit_reset: -1,
            response: Vec::new(),
        };

        for item in iter {
            resp.rate_limit = item.rate_limit;
            resp.rate_limit_remaining = item.rate_limit_remaining;
            resp.rate_limit_reset = item.rate_limit_reset;
            resp.response.push(item.response);
        }

        resp
    }
}

///With the given response struct, parse it into a String.
pub fn response_raw(resp: &mut HyperResponse) -> Result<String, error::Error> {
    let mut full_resp = String::new();
    try!(resp.read_to_string(&mut full_resp));

    if let Ok(err) = json::decode::<TwitterErrors>(&full_resp) {
        return Err(TwitterError(err));
    }

    match resp.status {
        StatusCode::Ok | StatusCode::NotModified => (),
        _ => return Err(BadStatus(resp.status)),
    }

    Ok(full_resp)
}

///With the given response struct, parse it into the desired format and
///return it along with rate limit information.
pub fn parse_response<T: FromJson>(resp: &mut HyperResponse) -> Result<Response<T>, error::Error> {
    let resp_str = try!(response_raw(resp));

    Ok(Response {
        rate_limit: resp.headers.get::<XRateLimitLimit>().map_or(-1, |h| h.0),
        rate_limit_remaining: resp.headers.get::<XRateLimitRemaining>().map_or(-1, |h| h.0),
        rate_limit_reset: resp.headers.get::<XRateLimitReset>().map_or(-1, |h| h.0),
        response: try!(T::from_str(&resp_str)),
    })
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! "Object safety" refers to the ability for a trait to be converted
//! to an object. In general, traits may only be converted to an
//! object if all of their methods meet certain criteria. In particular,
//! they must:
//!
//!   - have a suitable receiver from which we can extract a vtable;
//!   - not reference the erased type `Self` except for in this receiver;
//!   - not have generic type parameters

use super::supertraits;
use super::elaborate_predicates;

use middle::def_id::DefId;
use middle::subst::{self, SelfSpace, TypeSpace};
use middle::traits;
use middle::ty::{self, ToPolyTraitRef, Ty};
use std::rc::Rc;
use syntax::ast;

#[derive(Debug)]
pub enum ObjectSafetyViolation<'tcx> {
    /// Self : Sized declared on the trait
    SizedSelf,

    /// Supertrait reference references `Self` an in illegal location
    /// (e.g. `trait Foo : Bar<Self>`)
    SupertraitSelf,

    /// Method has something illegal
    Method(Rc<ty::Method<'tcx>>, MethodViolationCode),
}

/// Reasons a method might not be object-safe.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum MethodViolationCode {
    /// e.g., `fn foo()`
    StaticMethod,

    /// e.g., `fn foo(&self, x: Self)` or `fn foo(&self) -> Self`
    ReferencesSelf,

    /// e.g., `fn foo<A>()`
    Generic,
}

pub fn is_object_safe<'tcx>(tcx: &ty::ctxt<'tcx>,
                            trait_def_id: DefId)
                            -> bool
{
    // Because we query yes/no results frequently, we keep a cache:
    let def = tcx.lookup_trait_def(trait_def_id);

    let result = def.object_safety().unwrap_or_else(|| {
        let result = object_safety_violations(tcx, trait_def_id).is_empty();

        // Record just a yes/no result in the cache; this is what is
        // queried most frequently. Note that this may overwrite a
        // previous result, but always with the same thing.
        def.set_object_safety(result);

        result
    });

    debug!("is_object_safe({:?}) = {}", trait_def_id, result);

    result
}

pub fn object_safety_violations<'tcx>(tcx: &ty::ctxt<'tcx>,
                                      trait_def_id: DefId)
                                      -> Vec<ObjectSafetyViolation<'tcx>>
{
    traits::supertrait_def_ids(tcx, trait_def_id)
        .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id))
        .collect()
}

fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
                                            trait_def_id: DefId)
                                            -> Vec<ObjectSafetyViolation<'tcx>>
{
    // Check methods for violations.
    let mut violations: Vec<_> =
        tcx.trait_items(trait_def_id).iter()
        .flat_map(|item| {
            match *item {
                ty::MethodTraitItem(ref m) => {
                    object_safety_violation_for_method(tcx, trait_def_id, &**m)
                        .map(|code| ObjectSafetyViolation::Method(m.clone(), code))
                        .into_iter()
                }
                _ => None.into_iter(),
            }
        })
        .collect();

    // Check the trait itself.
    if trait_has_sized_self(tcx, trait_def_id) {
        violations.push(ObjectSafetyViolation::SizedSelf);
    }
    if supertraits_reference_self(tcx, trait_def_id) {
        violations.push(ObjectSafetyViolation::SupertraitSelf);
    }

    debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
           trait_def_id,
           violations);

    violations
}

fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>,
                                    trait_def_id: DefId)
                                    -> bool
{
    let trait_def = tcx.lookup_trait_def(trait_def_id);
    let trait_ref = trait_def.trait_ref.clone();
    let trait_ref = trait_ref.to_poly_trait_ref();
    let predicates = tcx.lookup_super_predicates(trait_def_id);
    predicates
        .predicates
        .into_iter()
        .map(|predicate| predicate.subst_supertrait(tcx, &trait_ref))
        .any(|predicate| {
            match predicate {
                ty::Predicate::Trait(ref data) => {
                    // In the case of a trait predicate, we can skip the "self" type.
                    data.0.trait_ref.substs.types.get_slice(TypeSpace)
                                                 .iter()
                                                 .cloned()
                                                 .any(is_self)
                }
                ty::Predicate::Projection(..) |
                ty::Predicate::WellFormed(..) |
                ty::Predicate::ObjectSafe(..) |
                ty::Predicate::TypeOutlives(..) |
                ty::Predicate::RegionOutlives(..) |
                ty::Predicate::Equate(..) => {
                    false
                }
            }
        })
}

fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
                              trait_def_id: DefId)
                              -> bool
{
    let trait_def = tcx.lookup_trait_def(trait_def_id);
    let trait_predicates = tcx.lookup_predicates(trait_def_id);
    generics_require_sized_self(tcx, &trait_def.generics, &trait_predicates)
}

fn generics_require_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
                                     generics: &ty::Generics<'tcx>,
                                     predicates: &ty::GenericPredicates<'tcx>)
                                     -> bool
{
    let sized_def_id = match tcx.lang_items.sized_trait() {
        Some(def_id) => def_id,
        None => { return false; /* No Sized trait, can't require it! */ }
    };

    // Search for a predicate like `Self : Sized` amongst the trait bounds.
    let free_substs = tcx.construct_free_substs(generics, ast::DUMMY_NODE_ID);
    let predicates = predicates.instantiate(tcx, &free_substs).predicates.into_vec();
    elaborate_predicates(tcx, predicates)
        .any(|predicate| {
            match predicate {
                ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
                    is_self(trait_pred.0.self_ty())
                }
                ty::Predicate::Projection(..) |
                ty::Predicate::Trait(..) |
                ty::Predicate::Equate(..) |
                ty::Predicate::RegionOutlives(..) |
                ty::Predicate::WellFormed(..) |
                ty::Predicate::ObjectSafe(..) |
                ty::Predicate::TypeOutlives(..) => {
                    false
                }
            }
        })
}

/// Returns `Some(_)` if this method makes the containing trait not object safe.
fn object_safety_violation_for_method<'tcx>(tcx: &ty::ctxt<'tcx>,
                                            trait_def_id: DefId,
                                            method: &ty::Method<'tcx>)
                                            -> Option<MethodViolationCode>
{
    // Any method that has a `Self : Sized` requisite is otherwise
    // exempt from the regulations.
    if generics_require_sized_self(tcx, &method.generics, &method.predicates) {
        return None;
    }

    virtual_call_violation_for_method(tcx, trait_def_id, method)
}

/// We say a method is *vtable safe* if it can be invoked on a trait
/// object.  Note that object-safe traits can have some
/// non-vtable-safe methods, so long as they require `Self:Sized` or
/// otherwise ensure that they cannot be used when `Self=Trait`.
pub fn is_vtable_safe_method<'tcx>(tcx: &ty::ctxt<'tcx>,
                                   trait_def_id: DefId,
                                   method: &ty::Method<'tcx>)
                                   -> bool
{
    virtual_call_violation_for_method(tcx, trait_def_id, method).is_none()
}

/// Returns `Some(_)` if this method cannot be called on a trait
/// object; this does not necessarily imply that the enclosing trait
/// is not object safe, because the method might have a where clause
/// `Self:Sized`.
fn virtual_call_violation_for_method<'tcx>(tcx: &ty::ctxt<'tcx>,
                                           trait_def_id: DefId,
                                           method: &ty::Method<'tcx>)
                                           -> Option<MethodViolationCode>
{
    // The method's first parameter must be something that derefs (or
    // autorefs) to `&self`. For now, we only accept `self`, `&self`
    // and `Box<Self>`.
    match method.explicit_self {
        ty::StaticExplicitSelfCategory => {
            return Some(MethodViolationCode::StaticMethod);
        }

        ty::ByValueExplicitSelfCategory |
        ty::ByReferenceExplicitSelfCategory(..) |
        ty::ByBoxExplicitSelfCategory => {
        }
    }

    // The `Self` type is erased, so it should not appear in list of
    // arguments or return type apart from the receiver.
    let ref sig = method.fty.sig;
    for &input_ty in &sig.0.inputs[1..] {
        if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) {
            return Some(MethodViolationCode::ReferencesSelf);
        }
    }
    if let ty::FnConverging(result_type) = sig.0.output {
        if contains_illegal_self_type_reference(tcx, trait_def_id, result_type) {
            return Some(MethodViolationCode::ReferencesSelf);
        }
    }

    // We can't monomorphize things like `fn foo<A>(...)`.
    if !method.generics.types.is_empty_in(subst::FnSpace) {
        return Some(MethodViolationCode::Generic);
    }

    None
}

fn contains_illegal_self_type_reference<'tcx>(tcx: &ty::ctxt<'tcx>,
                                              trait_def_id: DefId,
                                              ty: Ty<'tcx>)
                                              -> bool
{
    // This is somewhat subtle. In general, we want to forbid
    // references to `Self` in the argument and return types,
    // since the value of `Self` is erased. However, there is one
    // exception: it is ok to reference `Self` in order to access
    // an associated type of the current trait, since we retain
    // the value of those associated types in the object type
    // itself.
    //
    // ```rust
    // trait SuperTrait {
    //     type X;
    // }
    //
    // trait Trait : SuperTrait {
    //     type Y;
    //     fn foo(&self, x: Self) // bad
    //     fn foo(&self) -> Self // bad
    //     fn foo(&self) -> Option<Self> // bad
    //     fn foo(&self) -> Self::Y // OK, desugars to next example
    //     fn foo(&self) -> <Self as Trait>::Y // OK
    //     fn foo(&self) -> Self::X // OK, desugars to next example
    //     fn foo(&self) -> <Self as SuperTrait>::X // OK
    // }
    // ```
    //
    // However, it is not as simple as allowing `Self` in a projected
    // type, because there are illegal ways to use `Self` as well:
    //
    // ```rust
    // trait Trait : SuperTrait {
    //     ...
    //     fn foo(&self) -> <Self as SomeOtherTrait>::X;
    // }
    // ```
    //
    // Here we will not have the type of `X` recorded in the
    // object type, and we cannot resolve `Self as SomeOtherTrait`
    // without knowing what `Self` is.

    let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
    let mut error = false;
    ty.maybe_walk(|ty| {
        match ty.sty {
            ty::TyParam(ref param_ty) => {
                if param_ty.space == SelfSpace {
                    error = true;
                }

                false // no contained types to walk
            }

            ty::TyProjection(ref data) => {
                // This is a projected type `<Foo as SomeTrait>::X`.

                // Compute supertraits of current trait lazily.
                if supertraits.is_none() {
                    let trait_def = tcx.lookup_trait_def(trait_def_id);
                    let trait_ref = ty::Binder(trait_def.trait_ref.clone());
                    supertraits = Some(traits::supertraits(tcx, trait_ref).collect());
                }

                // Determine whether the trait reference `Foo as
                // SomeTrait` is in fact a supertrait of the
                // current trait. In that case, this type is
                // legal, because the type `X` will be specified
                // in the object type.  Note that we can just use
                // direct equality here because all of these types
                // are part of the formal parameter listing, and
                // hence there should be no inference variables.
                let projection_trait_ref = ty::Binder(data.trait_ref.clone());
                let is_supertrait_of_current_trait =
                    supertraits.as_ref().unwrap().contains(&projection_trait_ref);

                if is_supertrait_of_current_trait {
                    false // do not walk contained types, do not report error, do collect $200
                } else {
                    true // DO walk contained types, POSSIBLY reporting an error
                }
            }

            _ => true, // walk contained types, if any
        }
    });

    error
}

fn is_self<'tcx>(ty: Ty<'tcx>) -> bool {
    match ty.sty {
        ty::TyParam(ref data) => data.space == subst::SelfSpace,
        _ => false,
    }
}
<commit_msg>middle: use filter_map instead of flat_map with Option iters<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! "Object safety" refers to the ability for a trait to be converted
//! to an object. In general, traits may only be converted to an
//! object if all of their methods meet certain criteria. In particular,
//! they must:
//!
//!   - have a suitable receiver from which we can extract a vtable;
//!   - not reference the erased type `Self` except for in this receiver;
//!   - not have generic type parameters

use super::supertraits;
use super::elaborate_predicates;

use middle::def_id::DefId;
use middle::subst::{self, SelfSpace, TypeSpace};
use middle::traits;
use middle::ty::{self, ToPolyTraitRef, Ty};
use std::rc::Rc;
use syntax::ast;

#[derive(Debug)]
pub enum ObjectSafetyViolation<'tcx> {
    /// Self : Sized declared on the trait
    SizedSelf,

    /// Supertrait reference references `Self` an in illegal location
    /// (e.g. `trait Foo : Bar<Self>`)
    SupertraitSelf,

    /// Method has something illegal
    Method(Rc<ty::Method<'tcx>>, MethodViolationCode),
}

/// Reasons a method might not be object-safe.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum MethodViolationCode {
    /// e.g., `fn foo()`
    StaticMethod,

    /// e.g., `fn foo(&self, x: Self)` or `fn foo(&self) -> Self`
    ReferencesSelf,

    /// e.g., `fn foo<A>()`
    Generic,
}

pub fn is_object_safe<'tcx>(tcx: &ty::ctxt<'tcx>,
                            trait_def_id: DefId)
                            -> bool
{
    // Because we query yes/no results frequently, we keep a cache:
    let def = tcx.lookup_trait_def(trait_def_id);

    let result = def.object_safety().unwrap_or_else(|| {
        let result = object_safety_violations(tcx, trait_def_id).is_empty();

        // Record just a yes/no result in the cache; this is what is
        // queried most frequently. Note that this may overwrite a
        // previous result, but always with the same thing.
        def.set_object_safety(result);

        result
    });

    debug!("is_object_safe({:?}) = {}", trait_def_id, result);

    result
}

pub fn object_safety_violations<'tcx>(tcx: &ty::ctxt<'tcx>,
                                      trait_def_id: DefId)
                                      -> Vec<ObjectSafetyViolation<'tcx>>
{
    traits::supertrait_def_ids(tcx, trait_def_id)
        .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id))
        .collect()
}

fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
                                            trait_def_id: DefId)
                                            -> Vec<ObjectSafetyViolation<'tcx>>
{
    // Check methods for violations.
    let mut violations: Vec<_> =
        tcx.trait_items(trait_def_id).iter()
        .filter_map(|item| {
            match *item {
                ty::MethodTraitItem(ref m) => {
                    object_safety_violation_for_method(tcx, trait_def_id, &**m)
                        .map(|code| ObjectSafetyViolation::Method(m.clone(), code))
                }
                _ => None,
            }
        })
        .collect();

    // Check the trait itself.
    if trait_has_sized_self(tcx, trait_def_id) {
        violations.push(ObjectSafetyViolation::SizedSelf);
    }
    if supertraits_reference_self(tcx, trait_def_id) {
        violations.push(ObjectSafetyViolation::SupertraitSelf);
    }

    debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
           trait_def_id,
           violations);

    violations
}

fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>,
                                    trait_def_id: DefId)
                                    -> bool
{
    let trait_def = tcx.lookup_trait_def(trait_def_id);
    let trait_ref = trait_def.trait_ref.clone();
    let trait_ref = trait_ref.to_poly_trait_ref();
    let predicates = tcx.lookup_super_predicates(trait_def_id);
    predicates
        .predicates
        .into_iter()
        .map(|predicate| predicate.subst_supertrait(tcx, &trait_ref))
        .any(|predicate| {
            match predicate {
                ty::Predicate::Trait(ref data) => {
                    // In the case of a trait predicate, we can skip the "self" type.
                    data.0.trait_ref.substs.types.get_slice(TypeSpace)
                                                 .iter()
                                                 .cloned()
                                                 .any(is_self)
                }
                ty::Predicate::Projection(..) |
                ty::Predicate::WellFormed(..) |
                ty::Predicate::ObjectSafe(..) |
                ty::Predicate::TypeOutlives(..) |
                ty::Predicate::RegionOutlives(..) |
                ty::Predicate::Equate(..) => {
                    false
                }
            }
        })
}

fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
                              trait_def_id: DefId)
                              -> bool
{
    let trait_def = tcx.lookup_trait_def(trait_def_id);
    let trait_predicates = tcx.lookup_predicates(trait_def_id);
    generics_require_sized_self(tcx, &trait_def.generics, &trait_predicates)
}

fn generics_require_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
                                     generics: &ty::Generics<'tcx>,
                                     predicates: &ty::GenericPredicates<'tcx>)
                                     -> bool
{
    let sized_def_id = match tcx.lang_items.sized_trait() {
        Some(def_id) => def_id,
        None => { return false; /* No Sized trait, can't require it! */ }
    };

    // Search for a predicate like `Self : Sized` amongst the trait bounds.
    let free_substs = tcx.construct_free_substs(generics, ast::DUMMY_NODE_ID);
    let predicates = predicates.instantiate(tcx, &free_substs).predicates.into_vec();
    elaborate_predicates(tcx, predicates)
        .any(|predicate| {
            match predicate {
                ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
                    is_self(trait_pred.0.self_ty())
                }
                ty::Predicate::Projection(..) |
                ty::Predicate::Trait(..) |
                ty::Predicate::Equate(..) |
                ty::Predicate::RegionOutlives(..) |
                ty::Predicate::WellFormed(..) |
                ty::Predicate::ObjectSafe(..) |
                ty::Predicate::TypeOutlives(..) => {
                    false
                }
            }
        })
}

/// Returns `Some(_)` if this method makes the containing trait not object safe.
fn object_safety_violation_for_method<'tcx>(tcx: &ty::ctxt<'tcx>,
                                            trait_def_id: DefId,
                                            method: &ty::Method<'tcx>)
                                            -> Option<MethodViolationCode>
{
    // Any method that has a `Self : Sized` requisite is otherwise
    // exempt from the regulations.
    if generics_require_sized_self(tcx, &method.generics, &method.predicates) {
        return None;
    }

    virtual_call_violation_for_method(tcx, trait_def_id, method)
}

/// We say a method is *vtable safe* if it can be invoked on a trait
/// object.  Note that object-safe traits can have some
/// non-vtable-safe methods, so long as they require `Self:Sized` or
/// otherwise ensure that they cannot be used when `Self=Trait`.
pub fn is_vtable_safe_method<'tcx>(tcx: &ty::ctxt<'tcx>,
                                   trait_def_id: DefId,
                                   method: &ty::Method<'tcx>)
                                   -> bool
{
    virtual_call_violation_for_method(tcx, trait_def_id, method).is_none()
}

/// Returns `Some(_)` if this method cannot be called on a trait
/// object; this does not necessarily imply that the enclosing trait
/// is not object safe, because the method might have a where clause
/// `Self:Sized`.
fn virtual_call_violation_for_method<'tcx>(tcx: &ty::ctxt<'tcx>,
                                           trait_def_id: DefId,
                                           method: &ty::Method<'tcx>)
                                           -> Option<MethodViolationCode>
{
    // The method's first parameter must be something that derefs (or
    // autorefs) to `&self`. For now, we only accept `self`, `&self`
    // and `Box<Self>`.
    match method.explicit_self {
        ty::StaticExplicitSelfCategory => {
            return Some(MethodViolationCode::StaticMethod);
        }

        ty::ByValueExplicitSelfCategory |
        ty::ByReferenceExplicitSelfCategory(..) |
        ty::ByBoxExplicitSelfCategory => {
        }
    }

    // The `Self` type is erased, so it should not appear in list of
    // arguments or return type apart from the receiver.
    let ref sig = method.fty.sig;
    for &input_ty in &sig.0.inputs[1..] {
        if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) {
            return Some(MethodViolationCode::ReferencesSelf);
        }
    }
    if let ty::FnConverging(result_type) = sig.0.output {
        if contains_illegal_self_type_reference(tcx, trait_def_id, result_type) {
            return Some(MethodViolationCode::ReferencesSelf);
        }
    }

    // We can't monomorphize things like `fn foo<A>(...)`.
    if !method.generics.types.is_empty_in(subst::FnSpace) {
        return Some(MethodViolationCode::Generic);
    }

    None
}

fn contains_illegal_self_type_reference<'tcx>(tcx: &ty::ctxt<'tcx>,
                                              trait_def_id: DefId,
                                              ty: Ty<'tcx>)
                                              -> bool
{
    // This is somewhat subtle. In general, we want to forbid
    // references to `Self` in the argument and return types,
    // since the value of `Self` is erased. However, there is one
    // exception: it is ok to reference `Self` in order to access
    // an associated type of the current trait, since we retain
    // the value of those associated types in the object type
    // itself.
    //
    // ```rust
    // trait SuperTrait {
    //     type X;
    // }
    //
    // trait Trait : SuperTrait {
    //     type Y;
    //     fn foo(&self, x: Self) // bad
    //     fn foo(&self) -> Self // bad
    //     fn foo(&self) -> Option<Self> // bad
    //     fn foo(&self) -> Self::Y // OK, desugars to next example
    //     fn foo(&self) -> <Self as Trait>::Y // OK
    //     fn foo(&self) -> Self::X // OK, desugars to next example
    //     fn foo(&self) -> <Self as SuperTrait>::X // OK
    // }
    // ```
    //
    // However, it is not as simple as allowing `Self` in a projected
    // type, because there are illegal ways to use `Self` as well:
    //
    // ```rust
    // trait Trait : SuperTrait {
    //     ...
    //     fn foo(&self) -> <Self as SomeOtherTrait>::X;
    // }
    // ```
    //
    // Here we will not have the type of `X` recorded in the
    // object type, and we cannot resolve `Self as SomeOtherTrait`
    // without knowing what `Self` is.

    let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
    let mut error = false;
    ty.maybe_walk(|ty| {
        match ty.sty {
            ty::TyParam(ref param_ty) => {
                if param_ty.space == SelfSpace {
                    error = true;
                }

                false // no contained types to walk
            }

            ty::TyProjection(ref data) => {
                // This is a projected type `<Foo as SomeTrait>::X`.

                // Compute supertraits of current trait lazily.
                if supertraits.is_none() {
                    let trait_def = tcx.lookup_trait_def(trait_def_id);
                    let trait_ref = ty::Binder(trait_def.trait_ref.clone());
                    supertraits = Some(traits::supertraits(tcx, trait_ref).collect());
                }

                // Determine whether the trait reference `Foo as
                // SomeTrait` is in fact a supertrait of the
                // current trait. In that case, this type is
                // legal, because the type `X` will be specified
                // in the object type.  Note that we can just use
                // direct equality here because all of these types
                // are part of the formal parameter listing, and
                // hence there should be no inference variables.
                let projection_trait_ref = ty::Binder(data.trait_ref.clone());
                let is_supertrait_of_current_trait =
                    supertraits.as_ref().unwrap().contains(&projection_trait_ref);

                if is_supertrait_of_current_trait {
                    false // do not walk contained types, do not report error, do collect $200
                } else {
                    true // DO walk contained types, POSSIBLY reporting an error
                }
            }

            _ => true, // walk contained types, if any
        }
    });

    error
}

fn is_self<'tcx>(ty: Ty<'tcx>) -> bool {
    match ty.sty {
        ty::TyParam(ref data) => data.space == subst::SelfSpace,
        _ => false,
    }
}
<|endoftext|>