<commit_before>use syn;
use quote;

// struct IdentPipes  {
//    field1: Pipeline<Ty, Ident>,
//    field2  ...
// }

pub fn generate_pipeline_struct(ast: &syn::MacroInput) -> quote::Tokens {
    let ident = &ast.ident;
    let pipes_ident = syn::Ident::from(format!("{}Pipes", ident).to_string());

    let declarations = generate_declarations(ast);
    let variant_data = if let syn::Body::Struct(ref variant_data) = ast.body {
        variant_data
    } else {
        panic!("derive(PerlinDocument) only implemented for Structs!");
    };
    let fields = variant_data.fields().iter().map(|f| f.ident.clone());
    quote!(
        struct #pipes_ident {
            #(#declarations)*
        }

        impl Default for #pipes_ident {
            fn default() -> Self {
                #pipes_ident {
                    #(#fields: None,)*
                }
            }
        }
    )
}

fn generate_declarations(ast: &syn::MacroInput) -> Vec<quote::Tokens> {
    let ident = &ast.ident;
    let mut result = Vec::new();
    let variant_data = if let syn::Body::Struct(ref variant_data) = ast.body {
        variant_data
    } else {
        panic!("derive(PerlinDocument) only implemented for Structs!");
    };

    for field in variant_data.fields() {
        let field_ident = &field.ident;
        let ty = get_generics_from_field(&field.ty);
        result.push(quote!{
            #field_ident: Option<Pipeline<#ty, #ident>>,
        });
    }
    result
}

fn get_generics_from_field(field: &syn::Ty) -> quote::Tokens {
    if let &syn::Ty::Path(_, ref path) = field {
        for segment in &path.segments {
            if segment.ident == "Field" {
                if let syn::PathParameters::AngleBracketed(ref params) = segment.parameters {
                    let params = &params.types.first();
                    return quote!(#params);
                }
            }
        }
    }
    panic!("NO FIELD FOUND!");
}
<commit_msg>dont generate unnecessary pipes<commit_after>use syn;
use quote;

// struct IdentPipes  {
//    field1: Pipeline<Ty, Ident>,
//    field2  ...
// }

pub fn generate_pipeline_struct(ast: &syn::MacroInput) -> quote::Tokens {
    let ident = &ast.ident;
    let pipes_ident = syn::Ident::from(format!("{}Pipes", ident).to_string());

    let declarations = generate_declarations(ast);
    let variant_data = if let syn::Body::Struct(ref variant_data) = ast.body {
        variant_data
    } else {
        panic!("derive(PerlinDocument) only implemented for Structs!");
    };
    let fields = variant_data.fields().iter().map(|f| f.ident.clone());
    quote!(
        struct #pipes_ident {
            #(#declarations)*
        }

        impl Default for #pipes_ident {
            fn default() -> Self {
                #pipes_ident {
                    #(#fields: None,)*
                }
            }
        }
    )
}

fn generate_declarations(ast: &syn::MacroInput) -> Vec<quote::Tokens> {
    let ident = &ast.ident;
    let mut result = Vec::new();
    let variant_data = if let syn::Body::Struct(ref variant_data) = ast.body {
        variant_data
    } else {
        panic!("derive(PerlinDocument) only implemented for Structs!");
    };

    for field in variant_data.fields() {
        if field.attrs.iter().any(|attr| attr.name() == "no_pipe") {
            continue;
        }
        let field_ident = &field.ident;
        let ty = get_generics_from_field(&field.ty);
        result.push(quote!{
            #field_ident: Option<Pipeline<#ty, #ident>>,
        });
    }
    result
}

fn get_generics_from_field(field: &syn::Ty) -> quote::Tokens {
    if let &syn::Ty::Path(_, ref path) = field {
        for segment in &path.segments {
            if segment.ident == "Field" {
                if let syn::PathParameters::AngleBracketed(ref params) = segment.parameters {
                    let params = &params.types.first();
                    return quote!(#params);
                }
            }
        }
    }
    panic!("NO FIELD FOUND!");
}
<|endoftext|>


<commit_before>use core::{ErrorPos, Loc, Merge, Pos, RpDecl, RpField, RpFieldInit, RpFile, RpInstance,
           RpModifier, RpName, RpPackage, RpRegistered, RpRequiredPackage, RpType, RpTypeId,
           RpUseDecl, RpVersionedPackage, Version};
use errors::*;
use linked_hash_map::LinkedHashMap;
use reproto_core::object::{Object, PathObject};
use reproto_parser as parser;
use reproto_parser::ast::IntoModel;
use reproto_repository::Resolver;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::path::Path;
use std::rc::Rc;
use std::sync::{Arc, Mutex};

pub type InitFields = HashMap<String, Loc<RpFieldInit>>;

pub struct Environment {
    package_prefix: Option<RpPackage>,
    resolver: Box<Resolver>,
    visited: HashSet<RpVersionedPackage>,
    pub types: LinkedHashMap<RpTypeId, Loc<RpRegistered>>,
    pub decls: LinkedHashMap<RpTypeId, Rc<Loc<RpDecl>>>,
    pub used: LinkedHashMap<(RpVersionedPackage, String), RpVersionedPackage>,
}

/// Environment containing all loaded declarations.
impl Environment {
    pub fn new(package_prefix: Option<RpPackage>, resolver: Box<Resolver>) -> Environment {
        Environment {
            package_prefix: package_prefix,
            resolver: resolver,
            visited: HashSet::new(),
            types: LinkedHashMap::new(),
            decls: LinkedHashMap::new(),
            used: LinkedHashMap::new(),
        }
    }

    /// Registered an alias.
    fn register_alias(&mut self,
                      source_package: &RpVersionedPackage,
                      use_decl: Loc<RpUseDecl>,
                      use_package: &RpVersionedPackage)
                      -> Result<()> {
        use linked_hash_map::Entry::*;

        if let Some(used) = use_decl.package.parts.iter().last() {
            let alias = use_decl.alias.as_ref().unwrap_or(used);
            let key = (source_package.clone(), alias.clone());

            debug!("add alias {} ({})", alias, source_package);

            match self.used.entry(key) {
                Vacant(entry) => {
                    entry.insert(use_package.clone());
                }
                Occupied(_) => return Err(format!("alias {} already in use", alias).into()),
            };
        }

        Ok(())
    }

    /// Check if source is assignable to target.
    pub fn is_assignable_from(&self,
                              package: &RpVersionedPackage,
                              target: &RpType,
                              source: &RpType)
                              -> Result<bool> {
        match (target, source) {
            (&RpType::Double, &RpType::Double) => Ok(true),
            (&RpType::Float, &RpType::Float) => Ok(true),
            (&RpType::Signed { size: Some(ref target) },
             &RpType::Signed { size: Some(ref source) }) => Ok(target <= source),
            // unknown size matches known
            (&RpType::Signed { size: _ }, &RpType::Signed { size: None }) => Ok(true),
            (&RpType::Unsigned { size: Some(ref target) },
             &RpType::Unsigned { size: Some(ref source) }) => Ok(target <= source),
            // unknown size matches known
            (&RpType::Unsigned { size: _ }, &RpType::Unsigned { size: None }) => Ok(true),
            (&RpType::Boolean, &RpType::Boolean) => return Ok(true),
            (&RpType::String, &RpType::String) => return Ok(true),
            (&RpType::Bytes, &RpType::Bytes) => return Ok(true),
            // everything assignable to any type
            (&RpType::Any, _) => Ok(true),
            (&RpType::Name { name: ref target }, &RpType::Name { name: ref source }) => {
                let (_, target) = self.lookup(package, target)?;
                let (_, source) = self.lookup(package, source)?;
                return Ok(target.is_assignable_from(source));
            }
            // arrays match if inner type matches
            (&RpType::Array { inner: ref target }, &RpType::Array { inner: ref source }) => {
                return self.is_assignable_from(package, target, source);
            }
            (&RpType::Map { key: ref target_key, value: ref target_value },
             &RpType::Map { key: ref source_key, value: ref source_value }) => {
                let key_assignable = self.is_assignable_from(package, target_key, source_key)?;
                let value_assignable =
                    self.is_assignable_from(package, target_value, source_value)?;

                return Ok(key_assignable && value_assignable);
            }
            _ => Ok(false),
        }
    }

    /// Lookup registered constant.
    pub fn constant<'a>(&'a self,
                        pos: &Pos,
                        package: &'a RpVersionedPackage,
                        constant: &RpName,
                        target: &RpName)
                        -> Result<&'a RpRegistered> {
        let (_, reg_constant) = self.lookup(package, constant)
            .map_err(|e| Error::pos(e.description().to_owned(), pos.into()))?;

        let (_, reg_target) = self.lookup(package, target)
            .map_err(|e| Error::pos(e.description().to_owned(), pos.into()))?;

        if !reg_target.is_assignable_from(reg_constant) {
            return Err(Error::pos(format!("expected instance of `{}` but found `{}`",
                                          reg_target.display(),
                                          reg_constant.display()),
                                  pos.into()));
        }

        Ok(reg_constant)
    }

    /// Convert instance arguments to the known registered type of the instance, and a map
    /// containing the arguments being instantiated.
    pub fn instance<'a>(&'a self,
                        pos: &Pos,
                        package: &'a RpVersionedPackage,
                        instance: &RpInstance,
                        target: &RpName)
                        -> Result<(&'a RpRegistered, InitFields)> {
        let (_, reg_instance) = self.lookup(package, &instance.name)
            .map_err(|e| Error::pos(e.description().to_owned(), pos.into()))?;

        let (_, reg_target) = self.lookup(package, target)
            .map_err(|e| Error::pos(e.description().to_owned(), pos.into()))?;

        if !reg_target.is_assignable_from(reg_instance) {
            return Err(Error::pos(format!("expected instance of `{}` but found `{}`",
                                          reg_target.display(),
                                          reg_instance.display()),
                                  pos.into()));
        }

        let required_fields = match *reg_instance {
            RpRegistered::Type(ref ty) => ty.fields(),
            RpRegistered::SubType { ref parent, ref sub_type } => {
                Box::new(parent.fields().chain(sub_type.fields()))
            }
            RpRegistered::Tuple(ref tuple) => tuple.fields(),
            _ => return Err(Error::pos("expected instantiable type".into(), pos.into())),
        };

        // pick required fields.
        let required_fields = required_fields.filter(|f| f.modifier == RpModifier::Required);

        let mut known: HashMap<String, Loc<RpFieldInit>> = HashMap::new();

        // check that all required fields are set.
        let mut required: BTreeMap<String, Loc<RpField>> = required_fields.map(Clone::clone)
            .map(|f| (f.name().to_owned(), f))
            .collect();

        for init in &*instance.arguments {
            if let Some(ref field) = reg_instance.field_by_ident(&init.name)? {
                // TODO: map out init position, and check that required variables are set.
                known.insert(field.ident().to_owned(), init.clone());
                required.remove(field.name());
            } else {
                return Err(Error::pos("no such field".to_owned(), init.pos().into()));
            }
        }

        if !required.is_empty() {
            let required: Vec<(String, Loc<RpField>)> = required.into_iter()
                .collect();

            let names: Vec<String> =
                required.iter().map(|&(ref name, _)| name.to_owned()).collect();

            let positions: Vec<ErrorPos> =
                required.iter().map(|&(_, ref t)| t.pos().into()).collect();

            return Err(ErrorKind::MissingRequired(names,
                                                  instance.arguments.pos().into(),
                                                  positions)
                .into());
        }

        Ok((reg_instance, known))
    }

    /// Lookup the package declaration a used alias refers to.
    fn lookup_used(&self, package: &RpVersionedPackage, used: &str) -> Result<&RpVersionedPackage> {
        // resolve alias
        self.used
            .get(&(package.clone(), used.to_owned()))
            .ok_or_else(|| format!("not import for alias ({})", used).into())
    }

    /// Lookup the declaration matching the custom type.
    pub fn lookup<'a>(&'a self,
                      package: &'a RpVersionedPackage,
                      lookup_name: &RpName)
                      -> Result<(&'a RpVersionedPackage, &'a RpRegistered)> {
        let (package, name) = if let Some(ref prefix) = lookup_name.prefix {
            (self.lookup_used(package, prefix)?, lookup_name.without_prefix())
        } else {
            (package, lookup_name.clone())
        };

        let types_key = RpTypeId::new(package.clone(), name);

        if let Some(ty) = self.types.get(&types_key) {
            return Ok((package, ty));
        }

        return Err(format!("no such type: {}", lookup_name).into());
    }

    /// Load the provided Object into a `RpFile`.
    pub fn load_object<O: Into<Box<Object>>>(&mut self,
                                             object: O,
                                             version: Option<Version>,
                                             package: Option<RpPackage>)
                                             -> Result<Option<(RpVersionedPackage, RpFile)>> {
        let package = RpVersionedPackage::new(package, version);
        let object = object.into();
        let content = parser::read_reader(object.read()?)?;
        let object = Arc::new(Mutex::new(object));
        let file = parser::parse_string(object, content.as_str())?.into_model()?;
        Ok(Some((package, file)))
    }

    /// Process use declarations.
    pub fn process_uses(&mut self,
                        package: &RpVersionedPackage,
                        uses: Vec<Loc<RpUseDecl>>)
                        -> Result<()> {
        for use_decl in uses {
            let version_req = use_decl.version_req.as_ref().map(AsRef::as_ref).map(Clone::clone);
            let required = RpRequiredPackage::new(use_decl.package.as_ref().clone(), version_req);

            let use_package = self.import(&required)?;

            if let Some(use_package) = use_package {
                self.register_alias(package, use_decl, &use_package)?;
                continue;
            }

            let error = "no matching package found".to_owned();
            return Err(ErrorKind::Pos(error, use_decl.pos().into()).into());
        }

        Ok(())
    }

    /// Process and merge declarations.
    ///
    /// Declarations are considered the same if they have the same type_id.
    /// The same declarations are merged using `Merge`.
    pub fn process_decls<I>(package: &RpVersionedPackage,
                            input: I)
                            -> Result<LinkedHashMap<RpTypeId, Rc<Loc<RpDecl>>>>
        where I: IntoIterator<Item = Loc<RpDecl>>
    {
        use linked_hash_map::Entry::*;

        let mut decls = LinkedHashMap::new();

        for decl in input {
            let key = package.into_type_id(RpName::with_parts(vec![decl.name().to_owned()]));

            match decls.entry(key) {
                Vacant(entry) => {
                    entry.insert(Rc::new(decl));
                }
                Occupied(entry) => {
                    entry.into_mut().merge(Rc::new(decl))?;
                }
            }
        }

        Ok(decls)
    }

    pub fn process_types(&mut self,
                         package: &RpVersionedPackage,
                         decls: &LinkedHashMap<RpTypeId, Rc<Loc<RpDecl>>>)
                         -> Result<LinkedHashMap<RpTypeId, Loc<RpRegistered>>> {
        // apply package prefix, if needed
        let package = self.package_prefix
            .as_ref()
            .map(|prefix| prefix.join_versioned(package))
            .unwrap_or_else(|| package.clone());

        let mut types = LinkedHashMap::new();

        for (key, t) in decls.values().flat_map(|d| d.into_registered_type(&package, d.pos())) {
            if types.insert(key.clone(), t).is_some() {
                return Err(ErrorKind::RegisteredTypeConflict(key.clone()).into());
            }
        }

        Ok(types)
    }

    pub fn process_file(&mut self, package: &RpVersionedPackage, file: RpFile) -> Result<()> {
        self.process_uses(&package, file.uses)?;
        let decls = Self::process_decls(&package, file.decls)?;
        let types = self.process_types(&package, &decls)?;
        self.decls.extend(decls);
        self.types.extend(types);
        Ok(())
    }

    pub fn find_visited_by_required(&self,
                                    required: &RpRequiredPackage)
                                    -> Option<RpVersionedPackage> {
        for visited in &self.visited {
            if let Some(ref visited_package) = visited.package {
                if *visited_package == required.package {
                    if let Some(ref version_req) = required.version_req {
                        if let Some(ref actual_version) = visited.version {
                            if version_req.matches(actual_version) {
                                return Some(visited.clone());
                            }
                        }
                    } else {
                        return Some(visited.clone());
                    }
                }
            }
        }

        None
    }

    pub fn import_file<P: AsRef<Path>>(&mut self, path: P) -> Result<Option<RpVersionedPackage>> {
        let object = PathObject::new(path);

        if let Some((package, file)) = self.load_object(object, None, None)? {
            if !self.visited.contains(&package) {
                self.process_file(&package, file)?;
                self.visited.insert(package.clone());
            }

            return Ok(Some(package));
        }

        Ok(None)
    }

    pub fn import(&mut self, required: &RpRequiredPackage) -> Result<Option<RpVersionedPackage>> {
        debug!("import: {}", required);

        if let Some(existing) = self.find_visited_by_required(required) {
            debug!("already loaded: {} ({})", existing, required);
            return Ok(Some(existing));
        }

        let files = self.resolver.resolve(required)?;

        let mut candidates: BTreeMap<RpVersionedPackage, Vec<_>> = BTreeMap::new();

        if let Some((version, object)) = files.into_iter().last() {
            debug!("loading: {}", object);

            let loaded = self.load_object(object, version, Some(required.package.clone()))?;

            if let Some((package, file)) = loaded {
                candidates.entry(package)
                    .or_insert_with(Vec::new)
                    .push(file);
            }
        }

        if let Some((versioned, files)) = candidates.into_iter().last() {
            debug!("found: {} ({})", versioned, required);

            for file in files.into_iter() {
                self.process_file(&versioned, file)?;
            }

            self.visited.insert(versioned.clone());
            return Ok(Some(versioned));
        }

        Ok(None)
    }

    pub fn verify(&mut self) -> Result<()> {
        for (_, ref ty) in &self.decls {
            match ****ty {
                RpDecl::Type(ref ty) => {
                    ty.verify()?;
                }
                _ => {}
            }
        }

        Ok(())
    }
}
<commit_msg>backend: apply package prefix correctly<commit_after>use core::{ErrorPos, Loc, Merge, Pos, RpDecl, RpField, RpFieldInit, RpFile, RpInstance,
           RpModifier, RpName, RpPackage, RpRegistered, RpRequiredPackage, RpType, RpTypeId,
           RpUseDecl, RpVersionedPackage, Version};
use errors::*;
use linked_hash_map::LinkedHashMap;
use reproto_core::object::{Object, PathObject};
use reproto_parser as parser;
use reproto_parser::ast::IntoModel;
use reproto_repository::Resolver;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::path::Path;
use std::rc::Rc;
use std::sync::{Arc, Mutex};

pub type InitFields = HashMap<String, Loc<RpFieldInit>>;

pub struct Environment {
    package_prefix: Option<RpPackage>,
    resolver: Box<Resolver>,
    visited: HashSet<RpVersionedPackage>,
    pub types: LinkedHashMap<RpTypeId, Loc<RpRegistered>>,
    pub decls: LinkedHashMap<RpTypeId, Rc<Loc<RpDecl>>>,
    pub used: LinkedHashMap<(RpVersionedPackage, String), RpVersionedPackage>,
}

/// Environment containing all loaded declarations.
impl Environment {
    pub fn new(package_prefix: Option<RpPackage>, resolver: Box<Resolver>) -> Environment {
        Environment {
            package_prefix: package_prefix,
            resolver: resolver,
            visited: HashSet::new(),
            types: LinkedHashMap::new(),
            decls: LinkedHashMap::new(),
            used: LinkedHashMap::new(),
        }
    }

    /// Registered an alias.
    fn register_alias(&mut self,
                      source_package: &RpVersionedPackage,
                      use_decl: Loc<RpUseDecl>,
                      use_package: &RpVersionedPackage)
                      -> Result<()> {
        use linked_hash_map::Entry::*;

        if let Some(used) = use_decl.package.parts.iter().last() {
            let alias = use_decl.alias.as_ref().unwrap_or(used);
            let key = (source_package.clone(), alias.clone());

            debug!("add alias {} ({})", alias, source_package);

            match self.used.entry(key) {
                Vacant(entry) => {
                    entry.insert(use_package.clone());
                }
                Occupied(_) => return Err(format!("alias {} already in use", alias).into()),
            };
        }

        Ok(())
    }

    /// Check if source is assignable to target.
    pub fn is_assignable_from(&self,
                              package: &RpVersionedPackage,
                              target: &RpType,
                              source: &RpType)
                              -> Result<bool> {
        match (target, source) {
            (&RpType::Double, &RpType::Double) => Ok(true),
            (&RpType::Float, &RpType::Float) => Ok(true),
            (&RpType::Signed { size: Some(ref target) },
             &RpType::Signed { size: Some(ref source) }) => Ok(target <= source),
            // unknown size matches known
            (&RpType::Signed { size: _ }, &RpType::Signed { size: None }) => Ok(true),
            (&RpType::Unsigned { size: Some(ref target) },
             &RpType::Unsigned { size: Some(ref source) }) => Ok(target <= source),
            // unknown size matches known
            (&RpType::Unsigned { size: _ }, &RpType::Unsigned { size: None }) => Ok(true),
            (&RpType::Boolean, &RpType::Boolean) => return Ok(true),
            (&RpType::String, &RpType::String) => return Ok(true),
            (&RpType::Bytes, &RpType::Bytes) => return Ok(true),
            // everything assignable to any type
            (&RpType::Any, _) => Ok(true),
            (&RpType::Name { name: ref target }, &RpType::Name { name: ref source }) => {
                let (_, target) = self.lookup(package, target)?;
                let (_, source) = self.lookup(package, source)?;
                return Ok(target.is_assignable_from(source));
            }
            // arrays match if inner type matches
            (&RpType::Array { inner: ref target }, &RpType::Array { inner: ref source }) => {
                return self.is_assignable_from(package, target, source);
            }
            (&RpType::Map { key: ref target_key, value: ref target_value },
             &RpType::Map { key: ref source_key, value: ref source_value }) => {
                let key_assignable = self.is_assignable_from(package, target_key, source_key)?;
                let value_assignable =
                    self.is_assignable_from(package, target_value, source_value)?;

                return Ok(key_assignable && value_assignable);
            }
            _ => Ok(false),
        }
    }

    /// Lookup registered constant.
    pub fn constant<'a>(&'a self,
                        pos: &Pos,
                        package: &'a RpVersionedPackage,
                        constant: &RpName,
                        target: &RpName)
                        -> Result<&'a RpRegistered> {
        let (_, reg_constant) = self.lookup(package, constant)
            .map_err(|e| Error::pos(e.description().to_owned(), pos.into()))?;

        let (_, reg_target) = self.lookup(package, target)
            .map_err(|e| Error::pos(e.description().to_owned(), pos.into()))?;

        if !reg_target.is_assignable_from(reg_constant) {
            return Err(Error::pos(format!("expected instance of `{}` but found `{}`",
                                          reg_target.display(),
                                          reg_constant.display()),
                                  pos.into()));
        }

        Ok(reg_constant)
    }

    /// Convert instance arguments to the known registered type of the instance, and a map
    /// containing the arguments being instantiated.
    pub fn instance<'a>(&'a self,
                        pos: &Pos,
                        package: &'a RpVersionedPackage,
                        instance: &RpInstance,
                        target: &RpName)
                        -> Result<(&'a RpRegistered, InitFields)> {
        let (_, reg_instance) = self.lookup(package, &instance.name)
            .map_err(|e| Error::pos(e.description().to_owned(), pos.into()))?;

        let (_, reg_target) = self.lookup(package, target)
            .map_err(|e| Error::pos(e.description().to_owned(), pos.into()))?;

        if !reg_target.is_assignable_from(reg_instance) {
            return Err(Error::pos(format!("expected instance of `{}` but found `{}`",
                                          reg_target.display(),
                                          reg_instance.display()),
                                  pos.into()));
        }

        let required_fields = match *reg_instance {
            RpRegistered::Type(ref ty) => ty.fields(),
            RpRegistered::SubType { ref parent, ref sub_type } => {
                Box::new(parent.fields().chain(sub_type.fields()))
            }
            RpRegistered::Tuple(ref tuple) => tuple.fields(),
            _ => return Err(Error::pos("expected instantiable type".into(), pos.into())),
        };

        // pick required fields.
        let required_fields = required_fields.filter(|f| f.modifier == RpModifier::Required);

        let mut known: HashMap<String, Loc<RpFieldInit>> = HashMap::new();

        // check that all required fields are set.
        let mut required: BTreeMap<String, Loc<RpField>> = required_fields.map(Clone::clone)
            .map(|f| (f.name().to_owned(), f))
            .collect();

        for init in &*instance.arguments {
            if let Some(ref field) = reg_instance.field_by_ident(&init.name)? {
                // TODO: map out init position, and check that required variables are set.
                known.insert(field.ident().to_owned(), init.clone());
                required.remove(field.name());
            } else {
                return Err(Error::pos("no such field".to_owned(), init.pos().into()));
            }
        }

        if !required.is_empty() {
            let required: Vec<(String, Loc<RpField>)> = required.into_iter()
                .collect();

            let names: Vec<String> =
                required.iter().map(|&(ref name, _)| name.to_owned()).collect();

            let positions: Vec<ErrorPos> =
                required.iter().map(|&(_, ref t)| t.pos().into()).collect();

            return Err(ErrorKind::MissingRequired(names,
                                                  instance.arguments.pos().into(),
                                                  positions)
                .into());
        }

        Ok((reg_instance, known))
    }

    /// Lookup the package declaration a used alias refers to.
    fn lookup_used(&self, package: &RpVersionedPackage, used: &str) -> Result<&RpVersionedPackage> {
        // resolve alias
        self.used
            .get(&(package.clone(), used.to_owned()))
            .ok_or_else(|| format!("not import for alias ({})", used).into())
    }

    /// Lookup the declaration matching the custom type.
    pub fn lookup<'a>(&'a self,
                      package: &'a RpVersionedPackage,
                      lookup_name: &RpName)
                      -> Result<(&RpVersionedPackage, &'a RpRegistered)> {
        let (package, name) = if let Some(ref prefix) = lookup_name.prefix {
            (self.lookup_used(package, prefix)?, lookup_name.without_prefix())
        } else {
            (package, lookup_name.clone())
        };

        let types_key = RpTypeId::new(package.clone(), name);

        if let Some(ty) = self.types.get(&types_key) {
            return Ok((package, ty));
        }

        return Err(format!("no such type: {}", lookup_name).into());
    }

    /// Load the provided Object into a `RpFile`.
    pub fn load_object<O: Into<Box<Object>>>(&mut self,
                                             object: O,
                                             version: Option<Version>,
                                             package: Option<RpPackage>)
                                             -> Result<Option<(RpVersionedPackage, RpFile)>> {
        let package = RpVersionedPackage::new(package, version);
        let object = object.into();
        let content = parser::read_reader(object.read()?)?;
        let object = Arc::new(Mutex::new(object));
        let file = parser::parse_string(object, content.as_str())?.into_model()?;
        Ok(Some((package, file)))
    }

    /// Process use declarations.
    pub fn process_uses(&mut self,
                        package: &RpVersionedPackage,
                        uses: Vec<Loc<RpUseDecl>>)
                        -> Result<()> {
        for use_decl in uses {
            let version_req = use_decl.version_req.as_ref().map(AsRef::as_ref).map(Clone::clone);
            let required = RpRequiredPackage::new(use_decl.package.as_ref().clone(), version_req);

            let use_package = self.import(&required)?;

            if let Some(use_package) = use_package {
                let use_package = self.package_prefix(&use_package);
                self.register_alias(&package, use_decl, &use_package)?;
                continue;
            }

            let error = "no matching package found".to_owned();
            return Err(ErrorKind::Pos(error, use_decl.pos().into()).into());
        }

        Ok(())
    }

    /// Apply package prefix
    fn package_prefix(&self, package: &RpVersionedPackage) -> RpVersionedPackage {
        self.package_prefix
            .as_ref()
            .map(|prefix| prefix.join_versioned(package))
            .unwrap_or_else(|| package.clone())
    }

    /// Process and merge declarations.
    ///
    /// Declarations are considered the same if they have the same type_id.
    /// The same declarations are merged using `Merge`.
    pub fn process_decls<I>(&self,
                            package: &RpVersionedPackage,
                            input: I)
                            -> Result<LinkedHashMap<RpTypeId, Rc<Loc<RpDecl>>>>
        where I: IntoIterator<Item = Loc<RpDecl>>
    {
        use linked_hash_map::Entry::*;

        let mut decls = LinkedHashMap::new();

        for decl in input {
            let key = package.into_type_id(RpName::with_parts(vec![decl.name().to_owned()]));

            match decls.entry(key) {
                Vacant(entry) => {
                    entry.insert(Rc::new(decl));
                }
                Occupied(entry) => {
                    entry.into_mut().merge(Rc::new(decl))?;
                }
            }
        }

        Ok(decls)
    }

    pub fn process_types(&mut self,
                         package: &RpVersionedPackage,
                         decls: &LinkedHashMap<RpTypeId, Rc<Loc<RpDecl>>>)
                         -> Result<LinkedHashMap<RpTypeId, Loc<RpRegistered>>> {
        let mut types = LinkedHashMap::new();

        for (key, t) in decls.values().flat_map(|d| d.into_registered_type(&package, d.pos())) {
            if types.insert(key.clone(), t).is_some() {
                return Err(ErrorKind::RegisteredTypeConflict(key.clone()).into());
            }
        }

        Ok(types)
    }

    pub fn process_file(&mut self, package: &RpVersionedPackage, file: RpFile) -> Result<()> {
        let package = self.package_prefix(package);
        self.process_uses(&package, file.uses)?;
        let decls = self.process_decls(&package, file.decls)?;
        let types = self.process_types(&package, &decls)?;
        self.decls.extend(decls);
        self.types.extend(types);
        Ok(())
    }

    pub fn find_visited_by_required(&self,
                                    required: &RpRequiredPackage)
                                    -> Option<RpVersionedPackage> {
        for visited in &self.visited {
            if let Some(ref visited_package) = visited.package {
                if *visited_package == required.package {
                    if let Some(ref version_req) = required.version_req {
                        if let Some(ref actual_version) = visited.version {
                            if version_req.matches(actual_version) {
                                return Some(visited.clone());
                            }
                        }
                    } else {
                        return Some(visited.clone());
                    }
                }
            }
        }

        None
    }

    pub fn import_file<P: AsRef<Path>>(&mut self, path: P) -> Result<Option<RpVersionedPackage>> {
        let object = PathObject::new(path);

        if let Some((package, file)) = self.load_object(object, None, None)? {
            if !self.visited.contains(&package) {
                self.process_file(&package, file)?;
                self.visited.insert(package.clone());
            }

            return Ok(Some(package));
        }

        Ok(None)
    }

    pub fn import(&mut self, required: &RpRequiredPackage) -> Result<Option<RpVersionedPackage>> {
        debug!("import: {}", required);

        if let Some(existing) = self.find_visited_by_required(required) {
            debug!("already loaded: {} ({})", existing, required);
            return Ok(Some(existing));
        }

        let files = self.resolver.resolve(required)?;

        let mut candidates: BTreeMap<RpVersionedPackage, Vec<_>> = BTreeMap::new();

        if let Some((version, object)) = files.into_iter().last() {
            debug!("loading: {}", object);

            let loaded = self.load_object(object, version, Some(required.package.clone()))?;

            if let Some((package, file)) = loaded {
                candidates.entry(package)
                    .or_insert_with(Vec::new)
                    .push(file);
            }
        }

        if let Some((versioned, files)) = candidates.into_iter().last() {
            debug!("found: {} ({})", versioned, required);

            for file in files.into_iter() {
                self.process_file(&versioned, file)?;
            }

            self.visited.insert(versioned.clone());
            return Ok(Some(versioned));
        }

        Ok(None)
    }

    pub fn verify(&mut self) -> Result<()> {
        for (_, ref ty) in &self.decls {
            match ****ty {
                RpDecl::Type(ref ty) => {
                    ty.verify()?;
                }
                _ => {}
            }
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::fmt::{self, Formatter};
use std::hash;
use std::hash::Hash;
use std::path::Path;
use std::sync::Mutex;

use semver;
use serde::de;
use serde::ser;

use core::interning::InternedString;
use core::source::SourceId;
use util::{CargoResult, ToSemver};

lazy_static! {
    static ref PACKAGE_ID_CACHE: Mutex<HashSet<&'static PackageIdInner>> = Mutex::new(HashSet::new());
}

/// Identifier for a specific version of a package in a specific source.
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct PackageId {
    inner: &'static PackageIdInner,
}

#[derive(PartialOrd, Eq, Ord)]
struct PackageIdInner {
    name: InternedString,
    version: semver::Version,
    source_id: SourceId,
}

// Custom equality that uses full equality of SourceId, rather than its custom equality.
impl PartialEq for PackageIdInner {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name
            && self.version == other.version
            && self.source_id.full_eq(&other.source_id)
    }
}

// Custom hash that is coherent with the custom equality above.
impl Hash for PackageIdInner {
    fn hash<S: hash::Hasher>(&self, into: &mut S) {
        self.name.hash(into);
        self.version.hash(into);
        self.source_id.full_hash(into);
    }
}

impl ser::Serialize for PackageId {
    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        s.collect_str(&format_args!(
            "{} {} ({})",
            self.inner.name,
            self.inner.version,
            self.inner.source_id.to_url()
        ))
    }
}

impl<'de> de::Deserialize<'de> for PackageId {
    fn deserialize<D>(d: D) -> Result<PackageId, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        let string = String::deserialize(d)?;
        let mut s = string.splitn(3, ' ');
        let name = s.next().unwrap();
        let version = match s.next() {
            Some(s) => s,
            None => return Err(de::Error::custom("invalid serialized PackageId")),
        };
        let version = semver::Version::parse(version).map_err(de::Error::custom)?;
        let url = match s.next() {
            Some(s) => s,
            None => return Err(de::Error::custom("invalid serialized PackageId")),
        };
        let url = if url.starts_with('(') && url.ends_with(')') {
            &url[1..url.len() - 1]
        } else {
            return Err(de::Error::custom("invalid serialized PackageId"));
        };
        let source_id = SourceId::from_url(url).map_err(de::Error::custom)?;

        Ok(PackageId::wrap(
            PackageIdInner {
                name: InternedString::new(name),
                version,
                source_id,
            }
        ))
    }
}

impl PackageId {
    pub fn new<T: ToSemver>(name: &str, version: T, sid: SourceId) -> CargoResult<PackageId> {
        let v = version.to_semver()?;

        Ok(PackageId::wrap(
            PackageIdInner {
                name: InternedString::new(name),
                version: v,
                source_id: sid,
            }
        ))
    }

    fn wrap(inner: PackageIdInner) -> PackageId {
        let mut cache = PACKAGE_ID_CACHE.lock().unwrap();
        let inner = cache.get(&inner).map(|&x| x).unwrap_or_else(|| {
            let inner = Box::leak(Box::new(inner));
            cache.insert(inner);
            inner
        });
        PackageId { inner }
    }

    pub fn name(&self) -> InternedString {
        self.inner.name
    }
    pub fn version(&self) -> &semver::Version {
        &self.inner.version
    }
    pub fn source_id(&self) -> SourceId {
        self.inner.source_id
    }

    pub fn with_precise(&self, precise: Option<String>) -> PackageId {
        PackageId::wrap(
            PackageIdInner {
                name: self.inner.name,
                version: self.inner.version.clone(),
                source_id: self.inner.source_id.with_precise(precise),
            }
        )
    }

    pub fn with_source_id(&self, source: SourceId) -> PackageId {
        PackageId::wrap(
            PackageIdInner {
                name: self.inner.name,
                version: self.inner.version.clone(),
                source_id: source,
            }
        )
    }

    pub fn stable_hash<'a>(&'a self, workspace: &'a Path) -> PackageIdStableHash<'a> {
        PackageIdStableHash(self, workspace)
    }
}

pub struct PackageIdStableHash<'a>(&'a PackageId, &'a Path);

impl<'a> Hash for PackageIdStableHash<'a> {
    fn hash<S: hash::Hasher>(&self, state: &mut S) {
        self.0.inner.name.hash(state);
        self.0.inner.version.hash(state);
        self.0.inner.source_id.stable_hash(self.1, state);
    }
}

impl fmt::Display for PackageId {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{} v{}", self.inner.name, self.inner.version)?;

        if !self.inner.source_id.is_default_registry() {
            write!(f, " ({})", self.inner.source_id)?;
        }

        Ok(())
    }
}

impl fmt::Debug for PackageId {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("PackageId")
            .field("name", &self.inner.name)
            .field("version", &self.inner.version.to_string())
            .field("source", &self.inner.source_id.to_string())
            .finish()
    }
}

#[cfg(test)]
mod tests {
    use super::PackageId;
    use core::source::SourceId;
    use sources::CRATES_IO_INDEX;
    use util::ToUrl;

    #[test]
    fn invalid_version_handled_nicely() {
        let loc = CRATES_IO_INDEX.to_url().unwrap();
        let repo = SourceId::for_registry(&loc).unwrap();

        assert!(PackageId::new("foo", "1.0", repo).is_err());
        assert!(PackageId::new("foo", "1", repo).is_err());
        assert!(PackageId::new("foo", "bar", repo).is_err());
        assert!(PackageId::new("foo", "", repo).is_err());
    }

    #[test]
    fn debug() {
        let loc = CRATES_IO_INDEX.to_url().unwrap();
        let pkg_id = PackageId::new("foo", "1.0.0", SourceId::for_registry(&loc).unwrap()).unwrap();
        assert_eq!(r#"PackageId { name: "foo", version: "1.0.0", source: "registry `https://github.com/rust-lang/crates.io-index`" }"#, format!("{:?}", pkg_id));

        let pretty = r#"
PackageId {
    name: "foo",
    version: "1.0.0",
    source: "registry `https://github.com/rust-lang/crates.io-index`"
}
"#.trim();
        assert_eq!(pretty, format!("{:#?}", pkg_id));
    }

    #[test]
    fn display() {
        let loc = CRATES_IO_INDEX.to_url().unwrap();
        let pkg_id = PackageId::new("foo", "1.0.0", SourceId::for_registry(&loc).unwrap()).unwrap();
        assert_eq!("foo v1.0.0", pkg_id.to_string());
    }
}
<commit_msg>Add pointer equality to PartialEq for PackageId<commit_after>use std::collections::HashSet;
use std::fmt::{self, Formatter};
use std::hash;
use std::hash::Hash;
use std::path::Path;
use std::ptr;
use std::sync::Mutex;

use semver;
use serde::de;
use serde::ser;

use core::interning::InternedString;
use core::source::SourceId;
use util::{CargoResult, ToSemver};

lazy_static! {
    static ref PACKAGE_ID_CACHE: Mutex<HashSet<&'static PackageIdInner>> = Mutex::new(HashSet::new());
}

/// Identifier for a specific version of a package in a specific source.
#[derive(Clone, Copy, Eq, Hash, PartialOrd, Ord)]
pub struct PackageId {
    inner: &'static PackageIdInner,
}

#[derive(PartialOrd, Eq, Ord)]
struct PackageIdInner {
    name: InternedString,
    version: semver::Version,
    source_id: SourceId,
}

// Custom equality that uses full equality of SourceId, rather than its custom equality.
impl PartialEq for PackageIdInner {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name
            && self.version == other.version
            && self.source_id.full_eq(&other.source_id)
    }
}

// Custom hash that is coherent with the custom equality above.
impl Hash for PackageIdInner {
    fn hash<S: hash::Hasher>(&self, into: &mut S) {
        self.name.hash(into);
        self.version.hash(into);
        self.source_id.full_hash(into);
    }
}

impl ser::Serialize for PackageId {
    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        s.collect_str(&format_args!(
            "{} {} ({})",
            self.inner.name,
            self.inner.version,
            self.inner.source_id.to_url()
        ))
    }
}

impl<'de> de::Deserialize<'de> for PackageId {
    fn deserialize<D>(d: D) -> Result<PackageId, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        let string = String::deserialize(d)?;
        let mut s = string.splitn(3, ' ');
        let name = s.next().unwrap();
        let version = match s.next() {
            Some(s) => s,
            None => return Err(de::Error::custom("invalid serialized PackageId")),
        };
        let version = semver::Version::parse(version).map_err(de::Error::custom)?;
        let url = match s.next() {
            Some(s) => s,
            None => return Err(de::Error::custom("invalid serialized PackageId")),
        };
        let url = if url.starts_with('(') && url.ends_with(')') {
            &url[1..url.len() - 1]
        } else {
            return Err(de::Error::custom("invalid serialized PackageId"));
        };
        let source_id = SourceId::from_url(url).map_err(de::Error::custom)?;

        Ok(PackageId::wrap(
            PackageIdInner {
                name: InternedString::new(name),
                version,
                source_id,
            }
        ))
    }
}

impl PartialEq for PackageId {
    fn eq(&self, other: &PackageId) -> bool {
        if ptr::eq(self.inner, other.inner) {
            return true;
        }
        (*self.inner).eq(&*other.inner)
    }
}

impl PackageId {
    pub fn new<T: ToSemver>(name: &str, version: T, sid: SourceId) -> CargoResult<PackageId> {
        let v = version.to_semver()?;

        Ok(PackageId::wrap(
            PackageIdInner {
                name: InternedString::new(name),
                version: v,
                source_id: sid,
            }
        ))
    }

    fn wrap(inner: PackageIdInner) -> PackageId {
        let mut cache = PACKAGE_ID_CACHE.lock().unwrap();
        let inner = cache.get(&inner).map(|&x| x).unwrap_or_else(|| {
            let inner = Box::leak(Box::new(inner));
            cache.insert(inner);
            inner
        });
        PackageId { inner }
    }

    pub fn name(&self) -> InternedString {
        self.inner.name
    }
    pub fn version(&self) -> &semver::Version {
        &self.inner.version
    }
    pub fn source_id(&self) -> SourceId {
        self.inner.source_id
    }

    pub fn with_precise(&self, precise: Option<String>) -> PackageId {
        PackageId::wrap(
            PackageIdInner {
                name: self.inner.name,
                version: self.inner.version.clone(),
                source_id: self.inner.source_id.with_precise(precise),
            }
        )
    }

    pub fn with_source_id(&self, source: SourceId) -> PackageId {
        PackageId::wrap(
            PackageIdInner {
                name: self.inner.name,
                version: self.inner.version.clone(),
                source_id: source,
            }
        )
    }

    pub fn stable_hash<'a>(&'a self, workspace: &'a Path) -> PackageIdStableHash<'a> {
        PackageIdStableHash(self, workspace)
    }
}

pub struct PackageIdStableHash<'a>(&'a PackageId, &'a Path);

impl<'a> Hash for PackageIdStableHash<'a> {
    fn hash<S: hash::Hasher>(&self, state: &mut S) {
        self.0.inner.name.hash(state);
        self.0.inner.version.hash(state);
        self.0.inner.source_id.stable_hash(self.1, state);
    }
}

impl fmt::Display for PackageId {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "{} v{}", self.inner.name, self.inner.version)?;

        if !self.inner.source_id.is_default_registry() {
            write!(f, " ({})", self.inner.source_id)?;
        }

        Ok(())
    }
}

impl fmt::Debug for PackageId {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("PackageId")
            .field("name", &self.inner.name)
            .field("version", &self.inner.version.to_string())
            .field("source", &self.inner.source_id.to_string())
            .finish()
    }
}

#[cfg(test)]
mod tests {
    use super::PackageId;
    use core::source::SourceId;
    use sources::CRATES_IO_INDEX;
    use util::ToUrl;

    #[test]
    fn invalid_version_handled_nicely() {
        let loc = CRATES_IO_INDEX.to_url().unwrap();
        let repo = SourceId::for_registry(&loc).unwrap();

        assert!(PackageId::new("foo", "1.0", repo).is_err());
        assert!(PackageId::new("foo", "1", repo).is_err());
        assert!(PackageId::new("foo", "bar", repo).is_err());
        assert!(PackageId::new("foo", "", repo).is_err());
    }

    #[test]
    fn debug() {
        let loc = CRATES_IO_INDEX.to_url().unwrap();
        let pkg_id = PackageId::new("foo", "1.0.0", SourceId::for_registry(&loc).unwrap()).unwrap();
        assert_eq!(r#"PackageId { name: "foo", version: "1.0.0", source: "registry `https://github.com/rust-lang/crates.io-index`" }"#, format!("{:?}", pkg_id));

        let pretty = r#"
PackageId {
    name: "foo",
    version: "1.0.0",
    source: "registry `https://github.com/rust-lang/crates.io-index`"
}
"#.trim();
        assert_eq!(pretty, format!("{:#?}", pkg_id));
    }

    #[test]
    fn display() {
        let loc = CRATES_IO_INDEX.to_url().unwrap();
        let pkg_id = PackageId::new("foo", "1.0.0", SourceId::for_registry(&loc).unwrap()).unwrap();
        assert_eq!("foo v1.0.0", pkg_id.to_string());
    }
}
<|endoftext|>


<commit_before>use std::ops::Deref;
use std::path::Path;
use std::path::PathBuf;

use std::fmt::{Display, Debug, Formatter};
use std::fmt::Error as FmtError;
use std::result::Result as RResult;
use std::path::Components;

use libimagerror::into::IntoError;

use error::StoreErrorKind as SEK;
use error::MapErrInto;
use store::Result;

/// The Index into the Store
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct StoreId {
    base: Option<PathBuf>,
    id:   PathBuf,
}

impl StoreId {

    pub fn new(base: Option<PathBuf>, id: PathBuf) -> Result<StoreId> {
        StoreId::new_baseless(id).map(|mut sid| { sid.base = base; sid })
    }

    /// Try to create a StoreId object from a filesystem-absolute path.
    ///
    /// Automatically creates a StoreId object which has a `base` set to `store_part` if stripping
    /// the `store_part` from the `full_path` succeeded.
    ///
    /// Returns a `StoreErrorKind::StoreIdBuildFromFullPathError` if stripping failes.
    pub fn from_full_path<D>(store_part: &PathBuf, full_path: D) -> Result<StoreId>
        where D: Deref<Target = Path>
    {
        let p = try!(
            full_path.strip_prefix(store_part).map_err_into(SEK::StoreIdBuildFromFullPathError)
        );
        StoreId::new(Some(store_part.clone()), PathBuf::from(p))
    }

    pub fn new_baseless(id: PathBuf) -> Result<StoreId> {
        if id.is_absolute() {
            Err(SEK::StoreIdLocalPartAbsoluteError.into_error())
        } else {
            Ok(StoreId {
                base: None,
                id: id
            })
        }
    }

    pub fn without_base(mut self) -> StoreId {
        self.base = None;
        self
    }

    pub fn with_base(mut self, base: PathBuf) -> Self {
        self.base = Some(base);
        self
    }

    /// Transform the StoreId object into a PathBuf, error if the base of the StoreId is not
    /// specified.
    pub fn into_pathbuf(self) -> Result<PathBuf> {
        let mut base = try!(self.base.ok_or(SEK::StoreIdHasNoBaseError.into_error()));
        base.push(self.id);
        Ok(base)
    }

    pub fn exists(&self) -> bool {
        // TODO: hiding error here.
        self.clone().into_pathbuf().map(|pb| pb.exists()).unwrap_or(false)
    }

    pub fn is_file(&self) -> bool {
        true
    }

    pub fn is_dir(&self) -> bool {
        false
    }

    pub fn to_str(&self) -> Result<String> {
        if self.base.is_some() {
            let mut base = self.base.as_ref().cloned().unwrap();
            base.push(self.id.clone());
            base
        } else {
            self.id.clone()
        }
        .to_str()
        .map(String::from)
        .ok_or(SEK::StoreIdHandlingError.into_error())
    }

    /// Returns the components of the `id` part of the StoreId object.
    ///
    /// Can be used to check whether a StoreId points to an entry in a specific collection of
    /// StoreIds.
    pub fn components(&self) -> Components {
        self.id.components()
    }

    /// Get the _local_ part of a StoreId object, as in "the part from the store root to the entry".
    pub fn local(&self) -> &PathBuf {
        &self.id
    }

}

impl Display for StoreId {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        match self.id.to_str() {
            Some(s) => write!(fmt, "{}", s),
            None    => write!(fmt, "{}", self.id.to_string_lossy()),
        }
    }

}

/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
pub trait IntoStoreId {
    fn into_storeid(self) -> Result<StoreId>;
}

impl IntoStoreId for StoreId {
    fn into_storeid(self) -> Result<StoreId> {
        Ok(self)
    }
}

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> Result<StoreId> {
        StoreId::new_baseless(self)
    }
}

#[macro_export]
macro_rules! module_entry_path_mod {
    ($name:expr) => (
        #[deny(missing_docs,
                missing_copy_implementations,
                trivial_casts, trivial_numeric_casts,
                unsafe_code,
                unstable_features,
                unused_import_braces, unused_qualifications,
                unused_imports)]
        /// A helper module to create valid module entry paths
        pub mod module_path {
            use std::convert::AsRef;
            use std::path::Path;
            use std::path::PathBuf;

            use $crate::storeid::StoreId;
            use $crate::store::Result;

            /// A Struct giving you the ability to choose store entries assigned
            /// to it.
            ///
            /// It is created through a call to `new`.
            pub struct ModuleEntryPath(PathBuf);

            impl ModuleEntryPath {
                /// Path has to be a valid UTF-8 string or this will panic!
                pub fn new<P: AsRef<Path>>(pa: P) -> ModuleEntryPath {
                    let mut path = PathBuf::new();
                    path.push(format!("{}", $name));
                    path.push(pa.as_ref().clone());
                    let name = pa.as_ref().file_name().unwrap()
                        .to_str().unwrap();
                    path.set_file_name(name);
                    ModuleEntryPath(path)
                }
            }

            impl $crate::storeid::IntoStoreId for ModuleEntryPath {
                fn into_storeid(self) -> Result<$crate::storeid::StoreId> {
                    StoreId::new(None, self.0)
                }
            }
        }
    )
}

pub struct StoreIdIterator {
    iter: Box<Iterator<Item = StoreId>>,
}

impl Debug for StoreIdIterator {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "StoreIdIterator")
    }

}

impl StoreIdIterator {

    pub fn new(iter: Box<Iterator<Item = StoreId>>) -> StoreIdIterator {
        StoreIdIterator {
            iter: iter,
        }
    }

}

impl Iterator for StoreIdIterator {
    type Item = StoreId;

    fn next(&mut self) -> Option<StoreId> {
        self.iter.next()
    }

}

#[cfg(test)]
mod test {

    use storeid::IntoStoreId;

    module_entry_path_mod!("test");

    #[test]
    fn correct_path() {
        let p = module_path::ModuleEntryPath::new("test");

        assert_eq!(p.into_storeid().unwrap().to_str().unwrap(), "test/test");
    }

}
<commit_msg>Remove StoreId::is_dir()<commit_after>use std::ops::Deref;
use std::path::Path;
use std::path::PathBuf;

use std::fmt::{Display, Debug, Formatter};
use std::fmt::Error as FmtError;
use std::result::Result as RResult;
use std::path::Components;

use libimagerror::into::IntoError;

use error::StoreErrorKind as SEK;
use error::MapErrInto;
use store::Result;

/// The Index into the Store
#[derive(Debug, Clone, PartialEq, Hash, Eq, PartialOrd, Ord)]
pub struct StoreId {
    base: Option<PathBuf>,
    id:   PathBuf,
}

impl StoreId {

    pub fn new(base: Option<PathBuf>, id: PathBuf) -> Result<StoreId> {
        StoreId::new_baseless(id).map(|mut sid| { sid.base = base; sid })
    }

    /// Try to create a StoreId object from a filesystem-absolute path.
    ///
    /// Automatically creates a StoreId object which has a `base` set to `store_part` if stripping
    /// the `store_part` from the `full_path` succeeded.
    ///
    /// Returns a `StoreErrorKind::StoreIdBuildFromFullPathError` if stripping failes.
    pub fn from_full_path<D>(store_part: &PathBuf, full_path: D) -> Result<StoreId>
        where D: Deref<Target = Path>
    {
        let p = try!(
            full_path.strip_prefix(store_part).map_err_into(SEK::StoreIdBuildFromFullPathError)
        );
        StoreId::new(Some(store_part.clone()), PathBuf::from(p))
    }

    pub fn new_baseless(id: PathBuf) -> Result<StoreId> {
        if id.is_absolute() {
            Err(SEK::StoreIdLocalPartAbsoluteError.into_error())
        } else {
            Ok(StoreId {
                base: None,
                id: id
            })
        }
    }

    pub fn without_base(mut self) -> StoreId {
        self.base = None;
        self
    }

    pub fn with_base(mut self, base: PathBuf) -> Self {
        self.base = Some(base);
        self
    }

    /// Transform the StoreId object into a PathBuf, error if the base of the StoreId is not
    /// specified.
    pub fn into_pathbuf(self) -> Result<PathBuf> {
        let mut base = try!(self.base.ok_or(SEK::StoreIdHasNoBaseError.into_error()));
        base.push(self.id);
        Ok(base)
    }

    pub fn exists(&self) -> bool {
        // TODO: hiding error here.
        self.clone().into_pathbuf().map(|pb| pb.exists()).unwrap_or(false)
    }

    pub fn is_file(&self) -> bool {
        true
    }

    pub fn to_str(&self) -> Result<String> {
        if self.base.is_some() {
            let mut base = self.base.as_ref().cloned().unwrap();
            base.push(self.id.clone());
            base
        } else {
            self.id.clone()
        }
        .to_str()
        .map(String::from)
        .ok_or(SEK::StoreIdHandlingError.into_error())
    }

    /// Returns the components of the `id` part of the StoreId object.
    ///
    /// Can be used to check whether a StoreId points to an entry in a specific collection of
    /// StoreIds.
    pub fn components(&self) -> Components {
        self.id.components()
    }

    /// Get the _local_ part of a StoreId object, as in "the part from the store root to the entry".
    pub fn local(&self) -> &PathBuf {
        &self.id
    }

}

impl Display for StoreId {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        match self.id.to_str() {
            Some(s) => write!(fmt, "{}", s),
            None    => write!(fmt, "{}", self.id.to_string_lossy()),
        }
    }

}

/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
pub trait IntoStoreId {
    fn into_storeid(self) -> Result<StoreId>;
}

impl IntoStoreId for StoreId {
    fn into_storeid(self) -> Result<StoreId> {
        Ok(self)
    }
}

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> Result<StoreId> {
        StoreId::new_baseless(self)
    }
}

#[macro_export]
macro_rules! module_entry_path_mod {
    ($name:expr) => (
        #[deny(missing_docs,
                missing_copy_implementations,
                trivial_casts, trivial_numeric_casts,
                unsafe_code,
                unstable_features,
                unused_import_braces, unused_qualifications,
                unused_imports)]
        /// A helper module to create valid module entry paths
        pub mod module_path {
            use std::convert::AsRef;
            use std::path::Path;
            use std::path::PathBuf;

            use $crate::storeid::StoreId;
            use $crate::store::Result;

            /// A Struct giving you the ability to choose store entries assigned
            /// to it.
            ///
            /// It is created through a call to `new`.
            pub struct ModuleEntryPath(PathBuf);

            impl ModuleEntryPath {
                /// Path has to be a valid UTF-8 string or this will panic!
                pub fn new<P: AsRef<Path>>(pa: P) -> ModuleEntryPath {
                    let mut path = PathBuf::new();
                    path.push(format!("{}", $name));
                    path.push(pa.as_ref().clone());
                    let name = pa.as_ref().file_name().unwrap()
                        .to_str().unwrap();
                    path.set_file_name(name);
                    ModuleEntryPath(path)
                }
            }

            impl $crate::storeid::IntoStoreId for ModuleEntryPath {
                fn into_storeid(self) -> Result<$crate::storeid::StoreId> {
                    StoreId::new(None, self.0)
                }
            }
        }
    )
}

pub struct StoreIdIterator {
    iter: Box<Iterator<Item = StoreId>>,
}

impl Debug for StoreIdIterator {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "StoreIdIterator")
    }

}

impl StoreIdIterator {

    pub fn new(iter: Box<Iterator<Item = StoreId>>) -> StoreIdIterator {
        StoreIdIterator {
            iter: iter,
        }
    }

}

impl Iterator for StoreIdIterator {
    type Item = StoreId;

    fn next(&mut self) -> Option<StoreId> {
        self.iter.next()
    }

}

#[cfg(test)]
mod test {

    use storeid::IntoStoreId;

    module_entry_path_mod!("test");

    #[test]
    fn correct_path() {
        let p = module_path::ModuleEntryPath::new("test");

        assert_eq!(p.into_storeid().unwrap().to_str().unwrap(), "test/test");
    }

}
<|endoftext|>


<commit_before>use chrono::offset::{TimeZone, Utc};
use data_encoding::HEXLOWER;
use serde_derive::Deserialize;
use std::collections::{BTreeMap, HashMap};
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use tuf::crypto::{Ed25519PrivateKey, HashAlgorithm, KeyType, PrivateKey, SignatureScheme};
use tuf::interchange::JsonPretty;
use tuf::metadata::{
    MetadataPath, MetadataVersion, Role, RootMetadataBuilder, SnapshotMetadataBuilder, TargetPath,
    TargetsMetadataBuilder, TimestampMetadataBuilder, VirtualTargetPath,
};
use tuf::repository::{FileSystemRepository, FileSystemRepositoryBuilder, RepositoryStorage};
use walkdir::WalkDir;

// These structs and functions are necessary to parse keys.json, which contains the keys
// used by go-tuf to generate the equivalent metadata. We use the same keys to facilitate
// compatibility testing.

#[derive(Clone, Deserialize)]
struct KeyValue {
    #[serde(rename = "public")]
    _public: String,
    private: String,
}

#[derive(Clone, Deserialize)]
struct TestKeyPair {
    #[serde(rename = "keytype")]
    _keytype: KeyType,
    #[serde(rename = "scheme")]
    _scheme: SignatureScheme,
    keyval: KeyValue,
}

impl TestKeyPair {
    fn to_private_key(&self) -> Ed25519PrivateKey {
        let priv_bytes = HEXLOWER.decode(self.keyval.private.as_bytes()).unwrap();
        Ed25519PrivateKey::from_ed25519(&priv_bytes[..]).unwrap()
    }
}

#[derive(Deserialize)]
struct TestKeys {
    root: Vec<Vec<TestKeyPair>>,
    targets: Vec<Vec<TestKeyPair>>,
    snapshot: Vec<Vec<TestKeyPair>>,
    timestamp: Vec<Vec<TestKeyPair>>,
}

fn init_json_keys(path: &Path) -> TestKeys {
    let f = File::open(path).expect("failed to open keys file");
    serde_json::from_reader(f).expect("serde failed")
}

// Map each role to its current key.
type RoleKeys = HashMap<&'static str, Ed25519PrivateKey>;

fn init_role_keys(json_keys: &TestKeys) -> RoleKeys {
    let mut keys = HashMap::new();
    keys.insert("root", json_keys.root[0][0].to_private_key());
    keys.insert("snapshot", json_keys.snapshot[0][0].to_private_key());
    keys.insert("targets", json_keys.targets[0][0].to_private_key());
    keys.insert("timestamp", json_keys.timestamp[0][0].to_private_key());
    keys
}

fn copy_repo(dir: &Path, step: u8) {
    let src = Path::new(dir)
        .join((step - 1).to_string())
        .join("repository");
    let dst = Path::new(dir).join(step.to_string()).join("repository");

    for (path, f) in read_dir_files(&src) {
        let path = dst.join(path);
        if let Some(parent) = path.parent() {
            if !parent.exists() {
                fs::create_dir_all(parent).unwrap();
            }
        }
        fs::write(path, &f).unwrap();
    }
}

pub fn read_dir_files(path: &Path) -> BTreeMap<PathBuf, String> {
    let mut entries = BTreeMap::<PathBuf, _>::new();
    for entry in WalkDir::new(path) {
        let entry = entry.unwrap();
        if entry.metadata().unwrap().is_file() {
            let f = fs::read_to_string(entry.path()).unwrap();

            // Strip off the path prefix.
            let path = entry.into_path().strip_prefix(&path).unwrap().to_path_buf();

            entries.insert(path, f);
        }
    }

    entries
}

// updates the root metadata. If root_signer is Some, use that to sign the
// metadata, otherwise use keys["root"].
async fn update_root(
    repo: &FileSystemRepository<JsonPretty>,
    keys: &RoleKeys,
    root_signer: Option<&dyn PrivateKey>,
    version: u32,
    consistent_snapshot: bool,
) {
    let signer = match root_signer {
        Some(k) => k,
        None => keys.get("root").unwrap(),
    };

    // Same expiration as go-tuf metadata generator.
    let expiration = Utc.ymd(2100, 1, 1).and_hms(0, 0, 0);

    let mut root = RootMetadataBuilder::new()
        .root_key(keys.get("root").unwrap().public().clone())
        .expires(expiration)
        .version(version)
        .snapshot_key(keys.get("snapshot").unwrap().public().clone())
        .targets_key(keys.get("targets").unwrap().public().clone())
        .timestamp_key(keys.get("timestamp").unwrap().public().clone())
        .consistent_snapshot(consistent_snapshot)
        .signed::<JsonPretty>(signer)
        .unwrap();

    // If we rotated the root, sign it again with the new key.
    if root_signer.is_some() {
        root.add_signature(keys.get("root").unwrap()).unwrap()
    };

    // Insert both the versioned and unversioned root metadata. Most clients won't read the
    // unversioned root, but most libraries produce both to make it easier to understand what is
    // the latest root metadata.
    let root_path = MetadataPath::from_role(&Role::Root);
    repo.store_metadata(
        &root_path,
        &MetadataVersion::Number(version),
        &mut root.to_raw().unwrap().as_bytes(),
    )
    .await
    .unwrap();

    repo.store_metadata(
        &root_path,
        &MetadataVersion::None,
        &mut root.to_raw().unwrap().as_bytes(),
    )
    .await
    .unwrap();
}

// adds a target and updates the non-root metadata files.
async fn add_target(
    repo: &FileSystemRepository<JsonPretty>,
    keys: &RoleKeys,
    step: u8,
    consistent_snapshot: bool,
) {
    // Same expiration as go-tuf metadata generator.
    let expiration = Utc.ymd(2100, 1, 1).and_hms(0, 0, 0);
    let version: u32 = (step + 1).into();

    let mut targets_builder = TargetsMetadataBuilder::new()
        .expires(expiration)
        .version(version);

    let targets_path = MetadataPath::from_role(&Role::Targets);
    for i in 0..step + 1 {
        let step_str = format!("{}", i);
        let target_data = step_str.as_bytes();
        targets_builder = targets_builder
            .insert_target_from_reader(
                VirtualTargetPath::new(i.to_string()).unwrap(),
                target_data,
                &[HashAlgorithm::Sha256],
            )
            .unwrap();
    }
    let step_str = format!("{}", step);
    let target_data = step_str.as_bytes();

    let signed_targets = targets_builder
        .signed::<JsonPretty>(keys.get("targets").unwrap())
        .unwrap();
    let targets = signed_targets.assume_valid().unwrap();

    let hash = targets
        .targets()
        .get(&VirtualTargetPath::new(step.to_string()).unwrap())
        .unwrap()
        .hashes()
        .get(&HashAlgorithm::Sha256)
        .unwrap();

    let target_str = if consistent_snapshot {
        format!("{}.{}", hash, step.to_string())
    } else {
        step.to_string()
    };
    let target_path = TargetPath::new(target_str).unwrap();
    repo.store_target(&mut &*target_data, &target_path)
        .await
        .unwrap();

    let version_prefix = if consistent_snapshot {
        MetadataVersion::Number(version)
    } else {
        MetadataVersion::None
    };

    repo.store_metadata(
        &targets_path,
        &version_prefix,
        &mut signed_targets.to_raw().unwrap().as_bytes(),
    )
    .await
    .unwrap();

    let snapshot_path = MetadataPath::from_role(&Role::Snapshot);
    let snapshot = SnapshotMetadataBuilder::new()
        .expires(expiration)
        .version(version)
        .insert_metadata(&signed_targets, &[HashAlgorithm::Sha256])
        .unwrap()
        .signed::<JsonPretty>(keys.get("snapshot").unwrap())
        .unwrap();

    repo.store_metadata(
        &snapshot_path,
        &version_prefix,
        &mut snapshot.to_raw().unwrap().as_bytes(),
    )
    .await
    .unwrap();

    let timestamp_path = MetadataPath::from_role(&Role::Timestamp);
    let timestamp = TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
        .unwrap()
        .expires(expiration)
        .version(version)
        .signed::<JsonPretty>(keys.get("timestamp").unwrap())
        .unwrap();

    // Timestamp doesn't require a version prefix even in consistent_snapshot.
    repo.store_metadata(
        &timestamp_path,
        &MetadataVersion::None,
        &mut timestamp.to_raw().unwrap().as_bytes(),
    )
    .await
    .unwrap();
}

/// Generate a series of repositories in the `dir` path, using the keys in the `keys_path`. Each
/// repository corresponds to a key rotation. This allows clients to test they can update through
/// key transitions.
pub async fn generate_repos(
    keys_path: &Path,
    dir: &Path,
    consistent_snapshot: bool,
) -> tuf::Result<()> {
    // Create initial repo.
    let json_keys = init_json_keys(keys_path);
    let mut keys = init_role_keys(&json_keys);
    let dir0 = Path::new(dir).join("0");
    let repo = FileSystemRepositoryBuilder::new(dir0)
        .metadata_prefix(Path::new("repository"))
        .targets_prefix(Path::new("repository").join("targets"))
        .build()?;

    update_root(&repo, &keys, None, 1, consistent_snapshot).await;
    add_target(&repo, &keys, 0, consistent_snapshot).await;

    // Queue up a series of key rotations
    let mut i: u8 = 1;
    let rotations = vec![
        Some(Role::Root),
        Some(Role::Targets),
        Some(Role::Snapshot),
        Some(Role::Timestamp),
        None,
    ];
    for r in rotations.iter() {
        // Initialize new repo and copy the files from the previous step.
        let dir_i = Path::new(dir).join(i.to_string());
        let repo = FileSystemRepositoryBuilder::new(dir_i)
            .metadata_prefix(Path::new("repository"))
            .targets_prefix(Path::new("repository").join("targets"))
            .build()
            .unwrap();
        copy_repo(dir, i);

        let root_signer = match r {
            Some(Role::Root) => keys.insert("root", json_keys.root[1][0].to_private_key()),
            Some(Role::Targets) => {
                keys.insert("targets", json_keys.targets[1][0].to_private_key());
                None
            }
            Some(Role::Snapshot) => {
                keys.insert("snapshot", json_keys.snapshot[1][0].to_private_key());
                None
            }
            Some(Role::Timestamp) => {
                keys.insert("timestamp", json_keys.timestamp[1][0].to_private_key());
                None
            }
            None => None,
        };
        update_root(
            &repo,
            &keys,
            root_signer.as_ref().map(|x| x as &dyn PrivateKey),
            (i + 1).into(),
            consistent_snapshot,
        )
        .await;
        add_target(&repo, &keys, i, consistent_snapshot).await;
        i += 1;
    }
    Ok(())
}
<commit_msg>Fix clippy lints<commit_after>use chrono::offset::{TimeZone, Utc};
use data_encoding::HEXLOWER;
use serde_derive::Deserialize;
use std::collections::{BTreeMap, HashMap};
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use tuf::crypto::{Ed25519PrivateKey, HashAlgorithm, KeyType, PrivateKey, SignatureScheme};
use tuf::interchange::JsonPretty;
use tuf::metadata::{
    MetadataPath, MetadataVersion, Role, RootMetadataBuilder, SnapshotMetadataBuilder, TargetPath,
    TargetsMetadataBuilder, TimestampMetadataBuilder, VirtualTargetPath,
};
use tuf::repository::{FileSystemRepository, FileSystemRepositoryBuilder, RepositoryStorage};
use walkdir::WalkDir;

// These structs and functions are necessary to parse keys.json, which contains the keys
// used by go-tuf to generate the equivalent metadata. We use the same keys to facilitate
// compatibility testing.

#[derive(Clone, Deserialize)]
struct KeyValue {
    #[serde(rename = "public")]
    _public: String,
    private: String,
}

#[derive(Clone, Deserialize)]
struct TestKeyPair {
    #[serde(rename = "keytype")]
    _keytype: KeyType,
    #[serde(rename = "scheme")]
    _scheme: SignatureScheme,
    keyval: KeyValue,
}

impl TestKeyPair {
    fn to_private_key(&self) -> Ed25519PrivateKey {
        let priv_bytes = HEXLOWER.decode(self.keyval.private.as_bytes()).unwrap();
        Ed25519PrivateKey::from_ed25519(&priv_bytes[..]).unwrap()
    }
}

#[derive(Deserialize)]
struct TestKeys {
    root: Vec<Vec<TestKeyPair>>,
    targets: Vec<Vec<TestKeyPair>>,
    snapshot: Vec<Vec<TestKeyPair>>,
    timestamp: Vec<Vec<TestKeyPair>>,
}

fn init_json_keys(path: &Path) -> TestKeys {
    let f = File::open(path).expect("failed to open keys file");
    serde_json::from_reader(f).expect("serde failed")
}

// Map each role to its current key.
type RoleKeys = HashMap<&'static str, Ed25519PrivateKey>;

fn init_role_keys(json_keys: &TestKeys) -> RoleKeys {
    let mut keys = HashMap::new();
    keys.insert("root", json_keys.root[0][0].to_private_key());
    keys.insert("snapshot", json_keys.snapshot[0][0].to_private_key());
    keys.insert("targets", json_keys.targets[0][0].to_private_key());
    keys.insert("timestamp", json_keys.timestamp[0][0].to_private_key());
    keys
}

fn copy_repo(dir: &Path, step: u8) {
    let src = Path::new(dir)
        .join((step - 1).to_string())
        .join("repository");
    let dst = Path::new(dir).join(step.to_string()).join("repository");

    for (path, f) in read_dir_files(&src) {
        let path = dst.join(path);
        if let Some(parent) = path.parent() {
            if !parent.exists() {
                fs::create_dir_all(parent).unwrap();
            }
        }
        fs::write(path, &f).unwrap();
    }
}

pub fn read_dir_files(path: &Path) -> BTreeMap<PathBuf, String> {
    let mut entries = BTreeMap::<PathBuf, _>::new();
    for entry in WalkDir::new(path) {
        let entry = entry.unwrap();
        if entry.metadata().unwrap().is_file() {
            let f = fs::read_to_string(entry.path()).unwrap();

            // Strip off the path prefix.
            let path = entry.into_path().strip_prefix(&path).unwrap().to_path_buf();

            entries.insert(path, f);
        }
    }

    entries
}

// updates the root metadata. If root_signer is Some, use that to sign the
// metadata, otherwise use keys["root"].
async fn update_root(
    repo: &FileSystemRepository<JsonPretty>,
    keys: &RoleKeys,
    root_signer: Option<&dyn PrivateKey>,
    version: u32,
    consistent_snapshot: bool,
) {
    let signer = match root_signer {
        Some(k) => k,
        None => keys.get("root").unwrap(),
    };

    // Same expiration as go-tuf metadata generator.
    let expiration = Utc.ymd(2100, 1, 1).and_hms(0, 0, 0);

    let mut root = RootMetadataBuilder::new()
        .root_key(keys.get("root").unwrap().public().clone())
        .expires(expiration)
        .version(version)
        .snapshot_key(keys.get("snapshot").unwrap().public().clone())
        .targets_key(keys.get("targets").unwrap().public().clone())
        .timestamp_key(keys.get("timestamp").unwrap().public().clone())
        .consistent_snapshot(consistent_snapshot)
        .signed::<JsonPretty>(signer)
        .unwrap();

    // If we rotated the root, sign it again with the new key.
    if root_signer.is_some() {
        root.add_signature(keys.get("root").unwrap()).unwrap()
    };

    // Insert both the versioned and unversioned root metadata. Most clients won't read the
    // unversioned root, but most libraries produce both to make it easier to understand what is
    // the latest root metadata.
    let root_path = MetadataPath::from_role(&Role::Root);
    repo.store_metadata(
        &root_path,
        &MetadataVersion::Number(version),
        &mut root.to_raw().unwrap().as_bytes(),
    )
    .await
    .unwrap();

    repo.store_metadata(
        &root_path,
        &MetadataVersion::None,
        &mut root.to_raw().unwrap().as_bytes(),
    )
    .await
    .unwrap();
}

// adds a target and updates the non-root metadata files.
async fn add_target(
    repo: &FileSystemRepository<JsonPretty>,
    keys: &RoleKeys,
    step: u8,
    consistent_snapshot: bool,
) {
    // Same expiration as go-tuf metadata generator.
    let expiration = Utc.ymd(2100, 1, 1).and_hms(0, 0, 0);
    let version: u32 = (step + 1).into();

    let mut targets_builder = TargetsMetadataBuilder::new()
        .expires(expiration)
        .version(version);

    let targets_path = MetadataPath::from_role(&Role::Targets);
    for i in 0..step + 1 {
        let step_str = format!("{}", i);
        let target_data = step_str.as_bytes();
        targets_builder = targets_builder
            .insert_target_from_reader(
                VirtualTargetPath::new(i.to_string()).unwrap(),
                target_data,
                &[HashAlgorithm::Sha256],
            )
            .unwrap();
    }
    let step_str = format!("{}", step);
    let target_data = step_str.as_bytes();

    let signed_targets = targets_builder
        .signed::<JsonPretty>(keys.get("targets").unwrap())
        .unwrap();
    let targets = signed_targets.assume_valid().unwrap();

    let hash = targets
        .targets()
        .get(&VirtualTargetPath::new(step.to_string()).unwrap())
        .unwrap()
        .hashes()
        .get(&HashAlgorithm::Sha256)
        .unwrap();

    let target_str = if consistent_snapshot {
        format!("{}.{}", hash, step)
    } else {
        step.to_string()
    };
    let target_path = TargetPath::new(target_str).unwrap();
    repo.store_target(&mut &*target_data, &target_path)
        .await
        .unwrap();

    let version_prefix = if consistent_snapshot {
        MetadataVersion::Number(version)
    } else {
        MetadataVersion::None
    };

    repo.store_metadata(
        &targets_path,
        &version_prefix,
        &mut signed_targets.to_raw().unwrap().as_bytes(),
    )
    .await
    .unwrap();

    let snapshot_path = MetadataPath::from_role(&Role::Snapshot);
    let snapshot = SnapshotMetadataBuilder::new()
        .expires(expiration)
        .version(version)
        .insert_metadata(&signed_targets, &[HashAlgorithm::Sha256])
        .unwrap()
        .signed::<JsonPretty>(keys.get("snapshot").unwrap())
        .unwrap();

    repo.store_metadata(
        &snapshot_path,
        &version_prefix,
        &mut snapshot.to_raw().unwrap().as_bytes(),
    )
    .await
    .unwrap();

    let timestamp_path = MetadataPath::from_role(&Role::Timestamp);
    let timestamp = TimestampMetadataBuilder::from_snapshot(&snapshot, &[HashAlgorithm::Sha256])
        .unwrap()
        .expires(expiration)
        .version(version)
        .signed::<JsonPretty>(keys.get("timestamp").unwrap())
        .unwrap();

    // Timestamp doesn't require a version prefix even in consistent_snapshot.
    repo.store_metadata(
        &timestamp_path,
        &MetadataVersion::None,
        &mut timestamp.to_raw().unwrap().as_bytes(),
    )
    .await
    .unwrap();
}

/// Generate a series of repositories in the `dir` path, using the keys in the `keys_path`. Each
/// repository corresponds to a key rotation. This allows clients to test they can update through
/// key transitions.
pub async fn generate_repos(
    keys_path: &Path,
    dir: &Path,
    consistent_snapshot: bool,
) -> tuf::Result<()> {
    // Create initial repo.
    let json_keys = init_json_keys(keys_path);
    let mut keys = init_role_keys(&json_keys);
    let dir0 = Path::new(dir).join("0");
    let repo = FileSystemRepositoryBuilder::new(dir0)
        .metadata_prefix(Path::new("repository"))
        .targets_prefix(Path::new("repository").join("targets"))
        .build()?;

    update_root(&repo, &keys, None, 1, consistent_snapshot).await;
    add_target(&repo, &keys, 0, consistent_snapshot).await;

    // Queue up a series of key rotations
    let mut i: u8 = 1;
    let rotations = vec![
        Some(Role::Root),
        Some(Role::Targets),
        Some(Role::Snapshot),
        Some(Role::Timestamp),
        None,
    ];
    for r in rotations.iter() {
        // Initialize new repo and copy the files from the previous step.
        let dir_i = Path::new(dir).join(i.to_string());
        let repo = FileSystemRepositoryBuilder::new(dir_i)
            .metadata_prefix(Path::new("repository"))
            .targets_prefix(Path::new("repository").join("targets"))
            .build()
            .unwrap();
        copy_repo(dir, i);

        let root_signer = match r {
            Some(Role::Root) => keys.insert("root", json_keys.root[1][0].to_private_key()),
            Some(Role::Targets) => {
                keys.insert("targets", json_keys.targets[1][0].to_private_key());
                None
            }
            Some(Role::Snapshot) => {
                keys.insert("snapshot", json_keys.snapshot[1][0].to_private_key());
                None
            }
            Some(Role::Timestamp) => {
                keys.insert("timestamp", json_keys.timestamp[1][0].to_private_key());
                None
            }
            None => None,
        };
        update_root(
            &repo,
            &keys,
            root_signer.as_ref().map(|x| x as &dyn PrivateKey),
            (i + 1).into(),
            consistent_snapshot,
        )
        .await;
        add_target(&repo, &keys, i, consistent_snapshot).await;
        i += 1;
    }
    Ok(())
}
<|endoftext|>


<commit_before>extern crate core;

use core::num::FromPrimitive;
use core::fmt;

use Direction::{SpinUp, SpinDown, SpinSuper};
use Plan::{Switch, OddBall};

#[derive(Copy)]
#[derive(Show)]
enum Direction {
    SpinUp,
    SpinDown,
    SpinSuper,
}

impl fmt::String for Direction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let r = match self {
            &SpinUp => "SpinUp",
            &SpinDown => "SpinDown",
            &SpinSuper => "SpinSuper"
        };
        write!(f, "{}", r)
    }
}

struct Pair<T> {
    lhs: T,
    rhs: T
}

struct Particle {
    spin: Direction
}

enum Plan {
    Switch, // up-up-up -> down-down-down
    OddBall //
}

impl Particle {
    fn new_pair () -> Pair<Particle> {
        let d1 = SpinSuper;
        let d2 = SpinSuper;
        let p1 = Particle{spin: d1};
        let p2 = Particle{spin: d2};

        return Pair{lhs: p1, rhs: p2};
    }

    pub fn measure (&mut self, theta: int) {
        // TODO theta = 60degrees use 3/4th and 1/4th
        // TODO theta = 0 SpinUp
        // TODO theta = 180 SpinDown
    }

    // measure with with a message
    pub fn spooky (&mut self, friend: &mut Particle) -> Pair<Direction> {

        let spin = match self.spin {
            SpinUp => SpinDown,
            SpinDown => SpinUp,
            SpinSuper => SpinUp
        };
        friend.spin = spin;

        let spin = match friend.spin {
            SpinUp => SpinDown,
            SpinDown => SpinUp,
            _ => panic!("broke the universe")
        };
        self.spin = spin;

        return Pair{lhs: self.spin, rhs: friend.spin};
    }

    pub fn premeditated (&mut self, friend: &mut Particle, theta: int, plan: Plan) -> Pair<Direction> {

        // TODO: Use plan
        friend.spin = SpinUp;

        let spin = match friend.spin {
            SpinUp => SpinDown,
            SpinDown => SpinUp,
            _ => panic!("broke the universe")
        };
        self.spin = spin;

        return Pair{lhs: self.spin, rhs: friend.spin};
    }
}

fn main () {

    let particles = Particle::new_pair();

    let mut lhs = particles.lhs;
    let mut rhs = particles.rhs;

    lhs.spooky(&mut rhs);

    println!("lhs.spin {}, rhs.spin {}", lhs.spin, rhs.spin);
}
<commit_msg>notes and detectors<commit_after>extern crate core;

use core::num::FromPrimitive;
use core::fmt;

use Direction::{SpinUp, SpinDown, SpinSuper};
use Plan::{Switch, OddBall};

#[derive(Copy)]
#[derive(Show)]
enum Direction {
    SpinUp,
    SpinDown,
    SpinSuper,
}

impl fmt::String for Direction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let r = match self {
            &SpinUp => "SpinUp",
            &SpinDown => "SpinDown",
            &SpinSuper => "SpinSuper"
        };
        write!(f, "{}", r)
    }
}

struct Pair<T> {
    lhs: T,
    rhs: T
}

struct Particle {
    spin: Direction
}

enum Plan {
    Switch, // up-up-up -> down-down-down
    OddBall //
}

enum Detector {
    D12, // 12 o'clock
    D3, // 3 o'clock
    D9, // 9 o' clock
}

impl Particle {
    fn new_pair () -> Pair<Particle> {
        let d1 = SpinSuper;
        let d2 = SpinSuper;
        let p1 = Particle{spin: d1};
        let p2 = Particle{spin: d2};

        return Pair{lhs: p1, rhs: p2};
    }

    pub fn measure (&mut self, theta: int) {
        // TODO theta = 60degrees use 3/4th and 1/4th
        // TODO theta = 0 SpinUp
        // TODO theta = 180 SpinDown
    }

    // NOTE on spooky and premeditated only if measured in the same
    // direction must the spins be opposite

    // measure with with a message
    pub fn spooky (&mut self, friend: &mut Particle) -> Pair<Direction> {

        let spin = match self.spin {
            SpinUp => SpinDown,
            SpinDown => SpinUp,
            SpinSuper => SpinUp
        };
        friend.spin = spin;

        let spin = match friend.spin {
            SpinUp => SpinDown,
            SpinDown => SpinUp,
            _ => panic!("broke the universe")
        };
        self.spin = spin;

        return Pair{lhs: self.spin, rhs: friend.spin};
    }

    pub fn premeditated (&mut self, friend: &mut Particle, theta: int, plan: Plan) -> Pair<Direction> {

        // TODO: Use plan
        friend.spin = SpinUp;

        let spin = match friend.spin {
            SpinUp => SpinDown,
            SpinDown => SpinUp,
            _ => panic!("broke the universe")
        };
        self.spin = spin;

        return Pair{lhs: self.spin, rhs: friend.spin};
    }
}

fn main () {

    let particles = Particle::new_pair();

    let mut lhs = particles.lhs;
    let mut rhs = particles.rhs;

    lhs.spooky(&mut rhs);

    println!("lhs.spin {}, rhs.spin {}", lhs.spin, rhs.spin);

    // premeditated should give +55.6% difference, spooky would give 50%
}
<|endoftext|>


<commit_before>//! How many Pythagorean triples exist less than or equal to a million?
//! i.e. a²+b²=c² and a,b,c ≤ 1000000

use num::Integer;
use rayon::prelude::*;
use std::f64::INFINITY;
use std::ops::Add;
use test;

/// Use Euclid's formula to count Pythagorean triples
///
/// https://en.wikipedia.org/wiki/Pythagorean_triple#Generating_a_triple
///
/// For coprime integers m and n, with m > n and m-n is odd, then
///     a = m²-n², b = 2mn, c = m²+n²
///
/// This is a coprime triple.  Multiplying by factors k covers all triples.
fn par_euclid(m_weight: f64, n_weight: f64) -> u32 {
    (1u32 .. 2000).into_par_iter().weight(m_weight).map(|m| {
        (1 .. m).into_par_iter().weight(n_weight)
            .filter(|n| (m - n).is_odd() && m.gcd(n) == 1)
            .map(|n| 4000000 / (m*m + n*n))
            .sum()
    }).sum()
}

/// Same as par_euclid, without explicit weights.
fn par_euclid_weightless() -> u32 {
    (1u32 .. 2000).into_par_iter().map(|m| {
        (1 .. m).into_par_iter()
            .filter(|n| (m - n).is_odd() && m.gcd(n) == 1)
            .map(|n| 4000000 / (m*m + n*n))
            .sum()
    }).sum()
}

/// Same as par_euclid, without using rayon.
fn euclid() -> u32 {
    (1u32 .. 2000).map(|m| {
        (1 .. m)
            .filter(|n| (m - n).is_odd() && m.gcd(n) == 1)
            .map(|n| 4000000 / (m*m + n*n))
            .fold(0, Add::add)
    }).fold(0, Add::add)
}

#[bench]
/// Benchmark without rayon at all
fn euclid_serial(b: &mut test::Bencher) {
    let count = euclid();
    b.iter(|| assert_eq!(euclid(), count))
}

#[bench]
/// Use zero weights to force it fully serialized.
fn euclid_faux_serial(b: &mut test::Bencher) {
    let count = euclid();
    b.iter(|| assert_eq!(par_euclid(0.0, 0.0), count))
}

#[bench]
/// Use the default without any weights
fn euclid_parallel_weightless(b: &mut test::Bencher) {
    let count = euclid();
    b.iter(|| assert_eq!(par_euclid_weightless(), count))
}

#[bench]
/// Use the default weights (1.0)
fn euclid_parallel_one(b: &mut test::Bencher) {
    let count = euclid();
    b.iter(|| assert_eq!(par_euclid(1.0, 1.0), count))
}

#[bench]
/// Use infinite weight to force the outer loop parallelized.
fn euclid_parallel_outer(b: &mut test::Bencher) {
    let count = euclid();
    b.iter(|| assert_eq!(par_euclid(INFINITY, 1.0), count))
}

#[bench]
/// Use infinite weights to force it fully parallelized.
fn euclid_parallel_full(b: &mut test::Bencher) {
    let count = euclid();
    b.iter(|| assert_eq!(par_euclid(INFINITY, INFINITY), count))
}
<commit_msg>Port the pythagoras demo to a weightless world<commit_after>//! How many Pythagorean triples exist less than or equal to a million?
//! i.e. a²+b²=c² and a,b,c ≤ 1000000

use num::Integer;
use rayon::prelude::*;
use rayon::range::RangeIter;
use std::usize;
use std::ops::Add;
use test;

/// Use Euclid's formula to count Pythagorean triples
///
/// https://en.wikipedia.org/wiki/Pythagorean_triple#Generating_a_triple
///
/// For coprime integers m and n, with m > n and m-n is odd, then
///     a = m²-n², b = 2mn, c = m²+n²
///
/// This is a coprime triple.  Multiplying by factors k covers all triples.
fn par_euclid<FM, M, FN, N>(map_m: FM, map_n: FN) -> u32
    where FM: FnOnce(RangeIter<u32>) -> M,
          M: ParallelIterator<Item=u32>,
          FN: Fn(RangeIter<u32>) -> N + Sync,
          N: ParallelIterator<Item=u32>,
{
    map_m((1u32 .. 2000).into_par_iter()).map(|m| {
        map_n((1 .. m).into_par_iter())
            .filter(|n| (m - n).is_odd() && m.gcd(n) == 1)
            .map(|n| 4000000 / (m*m + n*n))
            .sum()
    }).sum()
}

/// Same as par_euclid, without tweaking split lengths
fn par_euclid_weightless() -> u32 {
    (1u32 .. 2000).into_par_iter().map(|m| {
        (1 .. m).into_par_iter()
            .filter(|n| (m - n).is_odd() && m.gcd(n) == 1)
            .map(|n| 4000000 / (m*m + n*n))
            .sum()
    }).sum()
}

/// Same as par_euclid, without using rayon.
fn euclid() -> u32 {
    (1u32 .. 2000).map(|m| {
        (1 .. m)
            .filter(|n| (m - n).is_odd() && m.gcd(n) == 1)
            .map(|n| 4000000 / (m*m + n*n))
            .fold(0, Add::add)
    }).fold(0, Add::add)
}

#[bench]
/// Benchmark without rayon at all
fn euclid_serial(b: &mut test::Bencher) {
    let count = euclid();
    b.iter(|| assert_eq!(euclid(), count))
}

#[bench]
/// Use huge minimums to force it fully serialized.
fn euclid_faux_serial(b: &mut test::Bencher) {
    let count = euclid();
    let serial = |r: RangeIter<u32>| r.set_min_len(usize::MAX);
    b.iter(|| assert_eq!(par_euclid(&serial, &serial), count))
}

#[bench]
/// Use the default without any weights
fn euclid_parallel_weightless(b: &mut test::Bencher) {
    let count = euclid();
    b.iter(|| assert_eq!(par_euclid_weightless(), count))
}

#[bench]
/// Use the default settings.
fn euclid_parallel_one(b: &mut test::Bencher) {
    let count = euclid();
    b.iter(|| assert_eq!(par_euclid(|m| m, |n| n), count))
}

#[bench]
/// Use a low maximum to force the outer loop parallelized.
fn euclid_parallel_outer(b: &mut test::Bencher) {
    let count = euclid();
    let parallel = |r: RangeIter<u32>| r.set_max_len(1);
    b.iter(|| assert_eq!(par_euclid(&parallel, |n| n), count))
}

#[bench]
/// Use low maximums to force it fully parallelized.
fn euclid_parallel_full(b: &mut test::Bencher) {
    let count = euclid();
    let parallel = |r: RangeIter<u32>| r.set_max_len(1);
    b.iter(|| assert_eq!(par_euclid(&parallel, &parallel), count))
}
<|endoftext|>