<commit_before>use std::collections::HashMap;
use std::path::Path;
use std::str;

use semver::Version;
use serde_json;

use core::dependency::Dependency;
use core::{PackageId, SourceId, Summary};
use sources::registry::RegistryData;
use sources::registry::{RegistryPackage, INDEX_LOCK};
use util::{internal, CargoResult, Config, Filesystem};

pub struct RegistryIndex<'cfg> {
    source_id: SourceId,
    path: Filesystem,
    cache: HashMap<&'static str, Vec<(Summary, bool)>>,
    hashes: HashMap<&'static str, HashMap<Version, String>>, // (name, vers) => cksum
    config: &'cfg Config,
    locked: bool,
}

impl<'cfg> RegistryIndex<'cfg> {
    pub fn new(
        id: &SourceId,
        path: &Filesystem,
        config: &'cfg Config,
        locked: bool,
    ) -> RegistryIndex<'cfg> {
        RegistryIndex {
            source_id: id.clone(),
            path: path.clone(),
            cache: HashMap::new(),
            hashes: HashMap::new(),
            config,
            locked,
        }
    }

    /// Return the hash listed for a specified PackageId.
    pub fn hash(&mut self, pkg: &PackageId, load: &mut RegistryData) -> CargoResult<String> {
        let name = pkg.name().as_str();
        let version = pkg.version();
        if let Some(s) = self.hashes.get(name).and_then(|v| v.get(version)) {
            return Ok(s.clone());
        }
        // Ok, we're missing the key, so parse the index file to load it.
        self.summaries(name, load)?;
        self.hashes
            .get(name)
            .and_then(|v| v.get(version))
            .ok_or_else(|| internal(format!("no hash listed for {}", pkg)))
            .map(|s| s.clone())
    }

    /// Parse the on-disk metadata for the package provided
    ///
    /// Returns a list of pairs of (summary, yanked) for the package name
    /// specified.
    pub fn summaries(
        &mut self,
        name: &'static str,
        load: &mut RegistryData,
    ) -> CargoResult<&Vec<(Summary, bool)>> {
        if self.cache.contains_key(name) {
            return Ok(&self.cache[name]);
        }
        let summaries = self.load_summaries(name, load)?;
        self.cache.insert(name, summaries);
        Ok(&self.cache[name])
    }

    fn load_summaries(
        &mut self,
        name: &str,
        load: &mut RegistryData,
    ) -> CargoResult<Vec<(Summary, bool)>> {
        // Prepare the `RegistryData` which will lazily initialize internal data
        // structures. Note that this is also importantly needed to initialize
        // to avoid deadlocks where we acquire a lock below but the `load`
        // function inside *also* wants to acquire a lock. See an instance of
        // this on #5551.
        load.prepare()?;
        let (root, _lock) = if self.locked {
            let lock = self
                .path
                .open_ro(Path::new(INDEX_LOCK), self.config, "the registry index");
            match lock {
                Ok(lock) => (lock.path().parent().unwrap().to_path_buf(), Some(lock)),
                Err(_) => return Ok(Vec::new()),
            }
        } else {
            (self.path.clone().into_path_unlocked(), None)
        };

        let fs_name = name
            .chars()
            .flat_map(|c| c.to_lowercase())
            .collect::<String>();

        // see module comment for why this is structured the way it is
        let raw_path = match fs_name.len() {
            1 => format!("1/{}", fs_name),
            2 => format!("2/{}", fs_name),
            3 => format!("3/{}/{}", &fs_name[..1], fs_name),
            _ => format!("{}/{}/{}", &fs_name[0..2], &fs_name[2..4], fs_name),
        };
        let num_hyphen_underscore = raw_path.chars()
            .filter(|&c| c == '_' || c == '-')
            .count();
        let mut ret = Vec::new();
        // Crates.io treats hyphen and underscores as interchangeable
        // but, the index and old cargo do not. So the index must store uncanonicalized version
        // of the name so old cargos can find it.
        // This loop tries all possible combinations of
        // hyphen and underscores to find the uncanonicalized one.
        for hyphen_combination_num in 0u16..(1 << num_hyphen_underscore) {
            let path = raw_path.chars()
                .scan(0u32, |s, c| if c == '_' || c == '-' {
                    let out = Some(if (hyphen_combination_num & (1u16 << *s)) > 0 { '_' } else { '-' });
                    *s += 1;
                    out
                } else {
                    Some(c)
                })
                .collect::<String>();
            let mut hit_closure = false;
            let err = load.load(&root, Path::new(&path), &mut |contents| {
                hit_closure = true;
                let contents = str::from_utf8(contents)
                    .map_err(|_| format_err!("registry index file was not valid utf-8"))?;
                ret.reserve(contents.lines().count());
                let lines = contents.lines().map(|s| s.trim()).filter(|l| !l.is_empty());

                let online = !self.config.cli_unstable().offline;
                // Attempt forwards-compatibility on the index by ignoring
                // everything that we ourselves don't understand, that should
                // allow future cargo implementations to break the
                // interpretation of each line here and older cargo will simply
                // ignore the new lines.
                ret.extend(lines.filter_map(|line| {
                    let (summary, locked) = match self.parse_registry_package(line) {
                        Ok(p) => p,
                        Err(e) => {
                            info!("failed to parse `{}` registry package: {}", name, e);
                            trace!("line: {}", line);
                            return None;
                        }
                    };
                    if online || load.is_crate_downloaded(summary.package_id()) {
                        Some((summary, locked))
                    } else {
                        None
                    }
                }));

                Ok(())
            });

            // We ignore lookup failures as those are just crates which don't exist
            // or we haven't updated the registry yet. If we actually ran the
            // closure though then we care about those errors.
            if hit_closure {
                err?;
                // Crates.io ensures that there is only one hyphen and underscore equivalent
                // result in the index so return when we find it.
                return Ok(ret);
            }
        }

        Ok(ret)
    }

    /// Parse a line from the registry's index file into a Summary for a
    /// package.
    ///
    /// The returned boolean is whether or not the summary has been yanked.
    fn parse_registry_package(&mut self, line: &str) -> CargoResult<(Summary, bool)> {
        let RegistryPackage {
            name,
            vers,
            cksum,
            deps,
            features,
            yanked,
            links,
        } = serde_json::from_str(line)?;
        let pkgid = PackageId::new(&name, &vers, &self.source_id)?;
        let name = pkgid.name();
        let deps = deps
            .into_iter()
            .map(|dep| dep.into_dep(&self.source_id))
            .collect::<CargoResult<Vec<_>>>()?;
        let summary = Summary::new(pkgid, deps, features, links, false)?;
        let summary = summary.set_checksum(cksum.clone());
        self.hashes
            .entry(name.as_str())
            .or_insert_with(HashMap::new)
            .insert(vers, cksum);
        Ok((summary, yanked.unwrap_or(false)))
    }

    pub fn query(
        &mut self,
        dep: &Dependency,
        load: &mut RegistryData,
        f: &mut FnMut(Summary),
    ) -> CargoResult<()> {
        let source_id = self.source_id.clone();
        let summaries = self.summaries(dep.name().as_str(), load)?;
        let summaries = summaries
            .iter()
            .filter(|&&(_, yanked)| dep.source_id().precise().is_some() || !yanked)
            .map(|s| s.0.clone());

        // Handle `cargo update --precise` here. If specified, our own source
        // will have a precise version listed of the form
        // `<pkg>=<p_req>o-><f_req>` where `<pkg>` is the name of a crate on
        // this source, `<p_req>` is the version installed and `<f_req> is the
        // version requested (argument to `--precise`).
        let summaries = summaries.filter(|s| match source_id.precise() {
            Some(p) if p.starts_with(&*dep.name()) && p[dep.name().len()..].starts_with('=') => {
                let mut vers = p[dep.name().len() + 1..].splitn(2, "->");
                if dep
                    .version_req()
                    .matches(&Version::parse(vers.next().unwrap()).unwrap())
                {
                    vers.next().unwrap() == s.version().to_string()
                } else {
                    true
                }
            }
            _ => true,
        });

        for summary in summaries {
            if dep.matches(&summary) {
                f(summary);
            }
        }
        Ok(())
    }
}
<commit_msg>cargo +stable fmt<commit_after>use std::collections::HashMap;
use std::path::Path;
use std::str;

use semver::Version;
use serde_json;

use core::dependency::Dependency;
use core::{PackageId, SourceId, Summary};
use sources::registry::RegistryData;
use sources::registry::{RegistryPackage, INDEX_LOCK};
use util::{internal, CargoResult, Config, Filesystem};

pub struct RegistryIndex<'cfg> {
    source_id: SourceId,
    path: Filesystem,
    cache: HashMap<&'static str, Vec<(Summary, bool)>>,
    hashes: HashMap<&'static str, HashMap<Version, String>>, // (name, vers) => cksum
    config: &'cfg Config,
    locked: bool,
}

impl<'cfg> RegistryIndex<'cfg> {
    pub fn new(
        id: &SourceId,
        path: &Filesystem,
        config: &'cfg Config,
        locked: bool,
    ) -> RegistryIndex<'cfg> {
        RegistryIndex {
            source_id: id.clone(),
            path: path.clone(),
            cache: HashMap::new(),
            hashes: HashMap::new(),
            config,
            locked,
        }
    }

    /// Return the hash listed for a specified PackageId.
    pub fn hash(&mut self, pkg: &PackageId, load: &mut RegistryData) -> CargoResult<String> {
        let name = pkg.name().as_str();
        let version = pkg.version();
        if let Some(s) = self.hashes.get(name).and_then(|v| v.get(version)) {
            return Ok(s.clone());
        }
        // Ok, we're missing the key, so parse the index file to load it.
        self.summaries(name, load)?;
        self.hashes
            .get(name)
            .and_then(|v| v.get(version))
            .ok_or_else(|| internal(format!("no hash listed for {}", pkg)))
            .map(|s| s.clone())
    }

    /// Parse the on-disk metadata for the package provided
    ///
    /// Returns a list of pairs of (summary, yanked) for the package name
    /// specified.
    pub fn summaries(
        &mut self,
        name: &'static str,
        load: &mut RegistryData,
    ) -> CargoResult<&Vec<(Summary, bool)>> {
        if self.cache.contains_key(name) {
            return Ok(&self.cache[name]);
        }
        let summaries = self.load_summaries(name, load)?;
        self.cache.insert(name, summaries);
        Ok(&self.cache[name])
    }

    fn load_summaries(
        &mut self,
        name: &str,
        load: &mut RegistryData,
    ) -> CargoResult<Vec<(Summary, bool)>> {
        // Prepare the `RegistryData` which will lazily initialize internal data
        // structures. Note that this is also importantly needed to initialize
        // to avoid deadlocks where we acquire a lock below but the `load`
        // function inside *also* wants to acquire a lock. See an instance of
        // this on #5551.
        load.prepare()?;
        let (root, _lock) = if self.locked {
            let lock = self
                .path
                .open_ro(Path::new(INDEX_LOCK), self.config, "the registry index");
            match lock {
                Ok(lock) => (lock.path().parent().unwrap().to_path_buf(), Some(lock)),
                Err(_) => return Ok(Vec::new()),
            }
        } else {
            (self.path.clone().into_path_unlocked(), None)
        };

        let fs_name = name
            .chars()
            .flat_map(|c| c.to_lowercase())
            .collect::<String>();

        // see module comment for why this is structured the way it is
        let raw_path = match fs_name.len() {
            1 => format!("1/{}", fs_name),
            2 => format!("2/{}", fs_name),
            3 => format!("3/{}/{}", &fs_name[..1], fs_name),
            _ => format!("{}/{}/{}", &fs_name[0..2], &fs_name[2..4], fs_name),
        };
        let num_hyphen_underscore = raw_path.chars()
            .filter(|&c| c == '_' || c == '-')
            .count();
        let mut ret = Vec::new();
        // Crates.io treats hyphen and underscores as interchangeable
        // but, the index and old cargo do not. So the index must store uncanonicalized version
        // of the name so old cargos can find it.
        // This loop tries all possible combinations of
        // hyphen and underscores to find the uncanonicalized one.
        for hyphen_combination_num in 0u16..(1 << num_hyphen_underscore) {
            let path = raw_path
                .chars()
                .scan(0u32, |s, c| {
                    if c == '_' || c == '-' {
                        let out = Some(if (hyphen_combination_num & (1u16 << *s)) > 0 {
                            '_'
                        } else {
                            '-'
                        });
                        *s += 1;
                        out
                    } else {
                        Some(c)
                    }
                })
                .collect::<String>();
            let mut hit_closure = false;
            let err = load.load(&root, Path::new(&path), &mut |contents| {
                hit_closure = true;
                let contents = str::from_utf8(contents)
                    .map_err(|_| format_err!("registry index file was not valid utf-8"))?;
                ret.reserve(contents.lines().count());
                let lines = contents.lines().map(|s| s.trim()).filter(|l| !l.is_empty());

                let online = !self.config.cli_unstable().offline;
                // Attempt forwards-compatibility on the index by ignoring
                // everything that we ourselves don't understand, that should
                // allow future cargo implementations to break the
                // interpretation of each line here and older cargo will simply
                // ignore the new lines.
                ret.extend(lines.filter_map(|line| {
                    let (summary, locked) = match self.parse_registry_package(line) {
                        Ok(p) => p,
                        Err(e) => {
                            info!("failed to parse `{}` registry package: {}", name, e);
                            trace!("line: {}", line);
                            return None;
                        }
                    };
                    if online || load.is_crate_downloaded(summary.package_id()) {
                        Some((summary, locked))
                    } else {
                        None
                    }
                }));

                Ok(())
            });

            // We ignore lookup failures as those are just crates which don't exist
            // or we haven't updated the registry yet. If we actually ran the
            // closure though then we care about those errors.
            if hit_closure {
                err?;
                // Crates.io ensures that there is only one hyphen and underscore equivalent
                // result in the index so return when we find it.
                return Ok(ret);
            }
        }

        Ok(ret)
    }

    /// Parse a line from the registry's index file into a Summary for a
    /// package.
    ///
    /// The returned boolean is whether or not the summary has been yanked.
    fn parse_registry_package(&mut self, line: &str) -> CargoResult<(Summary, bool)> {
        let RegistryPackage {
            name,
            vers,
            cksum,
            deps,
            features,
            yanked,
            links,
        } = serde_json::from_str(line)?;
        let pkgid = PackageId::new(&name, &vers, &self.source_id)?;
        let name = pkgid.name();
        let deps = deps
            .into_iter()
            .map(|dep| dep.into_dep(&self.source_id))
            .collect::<CargoResult<Vec<_>>>()?;
        let summary = Summary::new(pkgid, deps, features, links, false)?;
        let summary = summary.set_checksum(cksum.clone());
        self.hashes
            .entry(name.as_str())
            .or_insert_with(HashMap::new)
            .insert(vers, cksum);
        Ok((summary, yanked.unwrap_or(false)))
    }

    pub fn query(
        &mut self,
        dep: &Dependency,
        load: &mut RegistryData,
        f: &mut FnMut(Summary),
    ) -> CargoResult<()> {
        let source_id = self.source_id.clone();
        let summaries = self.summaries(dep.name().as_str(), load)?;
        let summaries = summaries
            .iter()
            .filter(|&&(_, yanked)| dep.source_id().precise().is_some() || !yanked)
            .map(|s| s.0.clone());

        // Handle `cargo update --precise` here. If specified, our own source
        // will have a precise version listed of the form
        // `<pkg>=<p_req>o-><f_req>` where `<pkg>` is the name of a crate on
        // this source, `<p_req>` is the version installed and `<f_req> is the
        // version requested (argument to `--precise`).
        let summaries = summaries.filter(|s| match source_id.precise() {
            Some(p) if p.starts_with(&*dep.name()) && p[dep.name().len()..].starts_with('=') => {
                let mut vers = p[dep.name().len() + 1..].splitn(2, "->");
                if dep
                    .version_req()
                    .matches(&Version::parse(vers.next().unwrap()).unwrap())
                {
                    vers.next().unwrap() == s.version().to_string()
                } else {
                    true
                }
            }
            _ => true,
        });

        for summary in summaries {
            if dep.matches(&summary) {
                f(summary);
            }
        }
        Ok(())
    }
}
<|endoftext|>


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

use itertools::Itertools;
use quote::{ToTokens, Tokens, Ident};

use cfg::CargonautsConfig;

use ast::*;

pub fn formats(routes: &Routes, cfg: &CargonautsConfig) -> Tokens {
    let root = cfg.templates();
    let method_refs = &MethodRef::build(routes).into_iter().group_by(|m| m.format);
    let builders = method_refs.into_iter().map(|(format, methods)| {
        let format = Ident::new(format);

        let templates = methods.filter_map(|method| {
            method.template(&root).map(|path| (path, method))
        }).map(|(path, method)| {
            let r = method.resource;
            let m = method.method;
            let key = match method.relation {
                Some(rel)   => quote!(::cargonauts::formats::TemplateKey::new_rel(#r, #rel, #m)),
                None        => quote!(::cargonauts::formats::TemplateKey::new(#r, #m)),
            };
            Template { key, path }
        });

        quote!({
            <#format as ::cargonauts::formats::BuildFormat>::build(&[
                #(#templates,)*
            ])?
        })
    });
    quote!({
        let mut formats = ::cargonauts::routing::FormatLender::default();
        #(formats.store(#builders);)*
        Ok(formats)
    })
}

#[derive(Copy, Clone)]
struct MethodRef<'a> {
    format: &'a str,
    method: &'a str,
    resource: &'a str,
    relation: Option<&'a str>,
}

impl<'a> MethodRef<'a> {
    fn build(routes: &'a Routes) -> Vec<MethodRef<'a>> {
        let mut vec = vec![];
        routes.visit_resources(&mut vec, |vec, resource| {
            for member in &resource.members {
                match *member {
                    ResourceMember::Method(ref m, _)    => {
                        for method in &m.methods {
                            vec.push(MethodRef {
                                format: &m.format[..],
                                method: &method[..],
                                resource: &resource.header.ty[..],
                                relation: None,
                            });
                        }
                    }
                    ResourceMember::Relation(ref rel, _) => {
                        for member in &rel.members {
                            match *member {
                                RelationMember::Method(ref m, _) => {
                                    for method in &m.methods {
                                        vec.push(MethodRef {
                                            format: &m.format[..],
                                            method: &method[..],
                                            resource: &resource.header.ty[..],
                                            relation: Some(&rel.rel[..]),
                                        });
                                    }
                                }
                            }
                        }
                    }
                }
            }
        });
        vec
    }

    fn template(self, root: &Path) -> Option<PathBuf> {
        let mut root = root.join(self.resource);
        if let Some(rel) = self.relation { root.push(rel); }
        let read_dir = if let Some(rd) = fs::read_dir(root).ok() { rd } else { return None };
        for entry in read_dir {
            let entry = entry.unwrap();
            if entry.file_name().to_str().unwrap().starts_with(self.method) {
                return Some(entry.path())
            }
        }
        None
    }
}

struct Template {
    path: PathBuf,
    key: Tokens,
}

impl ToTokens for Template {
    fn to_tokens(&self, tokens: &mut Tokens) {
        let path = self.path.to_string_lossy();
        let key = &self.key;
        tokens.append(quote! {
            ::cargonauts::formats::Template {
                key: #key,
                template: include_str!(#path),
            }
        })
    }
}
<commit_msg>Snake case path names for templates.<commit_after>use std::fs;
use std::path::{Path, PathBuf};

use heck::SnekCase;
use itertools::Itertools;
use quote::{ToTokens, Tokens, Ident};

use cfg::CargonautsConfig;

use ast::*;

pub fn formats(routes: &Routes, cfg: &CargonautsConfig) -> Tokens {
    let root = cfg.templates();
    let method_refs = &MethodRef::build(routes).into_iter().group_by(|m| m.format);
    let builders = method_refs.into_iter().map(|(format, methods)| {
        let format = Ident::new(format);

        let templates = methods.filter_map(|method| {
            method.template(&root).map(|path| (path, method))
        }).map(|(path, method)| {
            let r = method.resource;
            let m = method.method;
            let key = match method.relation {
                Some(rel)   => quote!(::cargonauts::formats::TemplateKey::new_rel(#r, #rel, #m)),
                None        => quote!(::cargonauts::formats::TemplateKey::new(#r, #m)),
            };
            Template { key, path }
        });

        quote!({
            <#format as ::cargonauts::formats::BuildFormat>::build(&[
                #(#templates,)*
            ])?
        })
    });
    quote!({
        let mut formats = ::cargonauts::routing::FormatLender::default();
        #(formats.store(#builders);)*
        Ok(formats)
    })
}

#[derive(Copy, Clone)]
struct MethodRef<'a> {
    format: &'a str,
    method: &'a str,
    resource: &'a str,
    relation: Option<&'a str>,
}

impl<'a> MethodRef<'a> {
    fn build(routes: &'a Routes) -> Vec<MethodRef<'a>> {
        let mut vec = vec![];
        routes.visit_resources(&mut vec, |vec, resource| {
            for member in &resource.members {
                match *member {
                    ResourceMember::Method(ref m, _)    => {
                        for method in &m.methods {
                            vec.push(MethodRef {
                                format: &m.format[..],
                                method: &method[..],
                                resource: &resource.header.ty[..],
                                relation: None,
                            });
                        }
                    }
                    ResourceMember::Relation(ref rel, _) => {
                        for member in &rel.members {
                            match *member {
                                RelationMember::Method(ref m, _) => {
                                    for method in &m.methods {
                                        vec.push(MethodRef {
                                            format: &m.format[..],
                                            method: &method[..],
                                            resource: &resource.header.ty[..],
                                            relation: Some(&rel.rel[..]),
                                        });
                                    }
                                }
                            }
                        }
                    }
                }
            }
        });
        vec
    }

    fn template(self, root: &Path) -> Option<PathBuf> {
        let mut root = root.join(self.resource.to_snek_case());
        if let Some(rel) = self.relation { root.push(rel.to_snek_case()); }
        let read_dir = if let Some(rd) = fs::read_dir(root).ok() { rd } else { return None };
        for entry in read_dir {
            let entry = entry.unwrap();
            if entry.file_name().to_str().unwrap().starts_with(&self.method.to_snek_case()) {
                return Some(entry.path())
            }
        }
        None
    }
}

struct Template {
    path: PathBuf,
    key: Tokens,
}

impl ToTokens for Template {
    fn to_tokens(&self, tokens: &mut Tokens) {
        let path = self.path.to_string_lossy();
        let key = &self.key;
        tokens.append(quote! {
            ::cargonauts::formats::Template {
                key: #key,
                template: include_str!(#path),
            }
        })
    }
}
<|endoftext|>


<commit_before>//! `crypto_scalarmult_curve25519` specified in
//! [Cryptography in NaCl](http://nacl.cr.yp.to/valid.html), Sections 2, 3, and 4.
//! This function is conjectured to be strong. For background see Bernstein,
//! "Curve25519: new Diffie-Hellman speed records," Lecture Notes in Computer
//! Science 3958 (2006), 207–228, http://cr.yp.to/papers.html#curve25519.
use ffi;

pub const BYTES: usize = ffi::crypto_scalarmult_curve25519_BYTES;
pub const SCALARBYTES: usize = ffi::crypto_scalarmult_curve25519_SCALARBYTES;

/// `Scalar` value (integer in byte representation)
#[derive(Copy)]
pub struct Scalar(pub [u8; SCALARBYTES]);

newtype_drop!(Scalar);
newtype_clone!(Scalar);
newtype_impl!(Scalar, SCALARBYTES);

/// `GroupElement`
#[derive(Copy)]
pub struct GroupElement(pub [u8; BYTES]);

newtype_clone!(GroupElement);
newtype_impl!(GroupElement, BYTES);

/// `scalarmult()` multiplies a group element `p`
/// by an integer `n`. It returns the resulting group element
/// `q`.
pub fn scalarmult(&Scalar(ref n): &Scalar,
                  &GroupElement(ref p): &GroupElement) -> GroupElement {
    let mut q = [0; BYTES];
    unsafe {
        ffi::crypto_scalarmult_curve25519(&mut q, n, p);
    }
    GroupElement(q)
}

/// `scalarmult_base()` computes the scalar product of a standard
/// group element and an integer `n`. It returns the resulting
/// group element `q`/
pub fn scalarmult_base(&Scalar(ref n): &Scalar) -> GroupElement {
    let mut q = [0; BYTES];
    unsafe {
        ffi::crypto_scalarmult_curve25519_base(&mut q, n);
    }
    GroupElement(q)
}

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

    #[test]
    fn test_vector_1() {
        // corresponding to tests/scalarmult.c and tests/scalarmult3.cpp from NaCl
        let alicesk = Scalar([0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d
                             ,0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45
                             ,0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a
                             ,0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a]);
        let alicepk_expected = [0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54
                               ,0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a
                               ,0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4
                               ,0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a];
        let GroupElement(alicepk) = scalarmult_base(&alicesk);
        assert!(alicepk == alicepk_expected);
    }

    #[test]
    fn test_vector_2() {
        // corresponding to tests/scalarmult2.c and tests/scalarmult4.cpp from NaCl
        let bobsk = Scalar([0x5d,0xab,0x08,0x7e,0x62,0x4a,0x8a,0x4b
                           ,0x79,0xe1,0x7f,0x8b,0x83,0x80,0x0e,0xe6
                           ,0x6f,0x3b,0xb1,0x29,0x26,0x18,0xb6,0xfd
                           ,0x1c,0x2f,0x8b,0x27,0xff,0x88,0xe0,0xeb]);
        let bobpk_expected = [0xde,0x9e,0xdb,0x7d,0x7b,0x7d,0xc1,0xb4
                             ,0xd3,0x5b,0x61,0xc2,0xec,0xe4,0x35,0x37
                             ,0x3f,0x83,0x43,0xc8,0x5b,0x78,0x67,0x4d
                             ,0xad,0xfc,0x7e,0x14,0x6f,0x88,0x2b,0x4f];
        let GroupElement(bobpk) = scalarmult_base(&bobsk);
        assert!(bobpk == bobpk_expected);
    }

    #[test]
    fn test_vector_3() {
        // corresponding to tests/scalarmult5.c and tests/scalarmult7.cpp from NaCl
        let alicesk = Scalar([0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d
                             ,0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45
                             ,0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a
                             ,0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a]);
        let bobpk = GroupElement([0xde,0x9e,0xdb,0x7d,0x7b,0x7d,0xc1,0xb4
                                 ,0xd3,0x5b,0x61,0xc2,0xec,0xe4,0x35,0x37
                                 ,0x3f,0x83,0x43,0xc8,0x5b,0x78,0x67,0x4d
                                 ,0xad,0xfc,0x7e,0x14,0x6f,0x88,0x2b,0x4f]);
        let k_expected = [0x4a,0x5d,0x9d,0x5b,0xa4,0xce,0x2d,0xe1
                         ,0x72,0x8e,0x3b,0xf4,0x80,0x35,0x0f,0x25
                         ,0xe0,0x7e,0x21,0xc9,0x47,0xd1,0x9e,0x33
                         ,0x76,0xf0,0x9b,0x3c,0x1e,0x16,0x17,0x42];
        let GroupElement(k) = scalarmult(&alicesk, &bobpk);
        assert!(k == k_expected);
    }

    #[test]
    fn test_vector_4() {
        // corresponding to tests/scalarmult6.c from NaCl
        let bobsk = Scalar([0x5d,0xab,0x08,0x7e,0x62,0x4a,0x8a,0x4b
                           ,0x79,0xe1,0x7f,0x8b,0x83,0x80,0x0e,0xe6
                           ,0x6f,0x3b,0xb1,0x29,0x26,0x18,0xb6,0xfd
                           ,0x1c,0x2f,0x8b,0x27,0xff,0x88,0xe0,0xeb]);
        let alicepk = GroupElement([0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54
                                   ,0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a
                                   ,0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4
                                   ,0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a]);
        let k_expected = [0x4a,0x5d,0x9d,0x5b,0xa4,0xce,0x2d,0xe1
                         ,0x72,0x8e,0x3b,0xf4,0x80,0x35,0x0f,0x25
                         ,0xe0,0x7e,0x21,0xc9,0x47,0xd1,0x9e,0x33
                         ,0x76,0xf0,0x9b,0x3c,0x1e,0x16,0x17,0x42];
        let GroupElement(k) = scalarmult(&bobsk, &alicepk);
        assert!(k == k_expected);
    }
}

#[cfg(feature = "benchmarks")]
#[cfg(test)]
mod bench {
    extern crate test;
    use randombytes::randombytes_into;
    use super::*;

    #[bench]
    fn bench_scalarmult(b: &mut test::Bencher) {
        let mut gbs = [0u8; BYTES];
        let mut sbs = [0u8; SCALARBYTES];
        randombytes_into(&mut gbs);
        randombytes_into(&mut sbs);
        let g = GroupElement(gbs);
        let s = Scalar(sbs);
        b.iter(|| {
            scalarmult(&s, &g);
        });
    }

    #[bench]
    fn bench_scalarmult_base(b: &mut test::Bencher) {
        let mut sbs = [0u8; SCALARBYTES];
        randombytes_into(&mut sbs);
        let s = Scalar(sbs);
        b.iter(|| {
            scalarmult_base(&s);
        });
    }
}
<commit_msg>Remove derived Copy for private key<commit_after>//! `crypto_scalarmult_curve25519` specified in
//! [Cryptography in NaCl](http://nacl.cr.yp.to/valid.html), Sections 2, 3, and 4.
//! This function is conjectured to be strong. For background see Bernstein,
//! "Curve25519: new Diffie-Hellman speed records," Lecture Notes in Computer
//! Science 3958 (2006), 207–228, http://cr.yp.to/papers.html#curve25519.
use ffi;

pub const BYTES: usize = ffi::crypto_scalarmult_curve25519_BYTES;
pub const SCALARBYTES: usize = ffi::crypto_scalarmult_curve25519_SCALARBYTES;

/// `Scalar` value (integer in byte representation)
pub struct Scalar(pub [u8; SCALARBYTES]);

newtype_drop!(Scalar);
newtype_clone!(Scalar);
newtype_impl!(Scalar, SCALARBYTES);

/// `GroupElement`
#[derive(Copy)]
pub struct GroupElement(pub [u8; BYTES]);

newtype_clone!(GroupElement);
newtype_impl!(GroupElement, BYTES);

/// `scalarmult()` multiplies a group element `p`
/// by an integer `n`. It returns the resulting group element
/// `q`.
pub fn scalarmult(&Scalar(ref n): &Scalar,
                  &GroupElement(ref p): &GroupElement) -> GroupElement {
    let mut q = [0; BYTES];
    unsafe {
        ffi::crypto_scalarmult_curve25519(&mut q, n, p);
    }
    GroupElement(q)
}

/// `scalarmult_base()` computes the scalar product of a standard
/// group element and an integer `n`. It returns the resulting
/// group element `q`/
pub fn scalarmult_base(&Scalar(ref n): &Scalar) -> GroupElement {
    let mut q = [0; BYTES];
    unsafe {
        ffi::crypto_scalarmult_curve25519_base(&mut q, n);
    }
    GroupElement(q)
}

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

    #[test]
    fn test_vector_1() {
        // corresponding to tests/scalarmult.c and tests/scalarmult3.cpp from NaCl
        let alicesk = Scalar([0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d
                             ,0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45
                             ,0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a
                             ,0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a]);
        let alicepk_expected = [0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54
                               ,0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a
                               ,0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4
                               ,0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a];
        let GroupElement(alicepk) = scalarmult_base(&alicesk);
        assert!(alicepk == alicepk_expected);
    }

    #[test]
    fn test_vector_2() {
        // corresponding to tests/scalarmult2.c and tests/scalarmult4.cpp from NaCl
        let bobsk = Scalar([0x5d,0xab,0x08,0x7e,0x62,0x4a,0x8a,0x4b
                           ,0x79,0xe1,0x7f,0x8b,0x83,0x80,0x0e,0xe6
                           ,0x6f,0x3b,0xb1,0x29,0x26,0x18,0xb6,0xfd
                           ,0x1c,0x2f,0x8b,0x27,0xff,0x88,0xe0,0xeb]);
        let bobpk_expected = [0xde,0x9e,0xdb,0x7d,0x7b,0x7d,0xc1,0xb4
                             ,0xd3,0x5b,0x61,0xc2,0xec,0xe4,0x35,0x37
                             ,0x3f,0x83,0x43,0xc8,0x5b,0x78,0x67,0x4d
                             ,0xad,0xfc,0x7e,0x14,0x6f,0x88,0x2b,0x4f];
        let GroupElement(bobpk) = scalarmult_base(&bobsk);
        assert!(bobpk == bobpk_expected);
    }

    #[test]
    fn test_vector_3() {
        // corresponding to tests/scalarmult5.c and tests/scalarmult7.cpp from NaCl
        let alicesk = Scalar([0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d
                             ,0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45
                             ,0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a
                             ,0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a]);
        let bobpk = GroupElement([0xde,0x9e,0xdb,0x7d,0x7b,0x7d,0xc1,0xb4
                                 ,0xd3,0x5b,0x61,0xc2,0xec,0xe4,0x35,0x37
                                 ,0x3f,0x83,0x43,0xc8,0x5b,0x78,0x67,0x4d
                                 ,0xad,0xfc,0x7e,0x14,0x6f,0x88,0x2b,0x4f]);
        let k_expected = [0x4a,0x5d,0x9d,0x5b,0xa4,0xce,0x2d,0xe1
                         ,0x72,0x8e,0x3b,0xf4,0x80,0x35,0x0f,0x25
                         ,0xe0,0x7e,0x21,0xc9,0x47,0xd1,0x9e,0x33
                         ,0x76,0xf0,0x9b,0x3c,0x1e,0x16,0x17,0x42];
        let GroupElement(k) = scalarmult(&alicesk, &bobpk);
        assert!(k == k_expected);
    }

    #[test]
    fn test_vector_4() {
        // corresponding to tests/scalarmult6.c from NaCl
        let bobsk = Scalar([0x5d,0xab,0x08,0x7e,0x62,0x4a,0x8a,0x4b
                           ,0x79,0xe1,0x7f,0x8b,0x83,0x80,0x0e,0xe6
                           ,0x6f,0x3b,0xb1,0x29,0x26,0x18,0xb6,0xfd
                           ,0x1c,0x2f,0x8b,0x27,0xff,0x88,0xe0,0xeb]);
        let alicepk = GroupElement([0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54
                                   ,0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a
                                   ,0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4
                                   ,0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a]);
        let k_expected = [0x4a,0x5d,0x9d,0x5b,0xa4,0xce,0x2d,0xe1
                         ,0x72,0x8e,0x3b,0xf4,0x80,0x35,0x0f,0x25
                         ,0xe0,0x7e,0x21,0xc9,0x47,0xd1,0x9e,0x33
                         ,0x76,0xf0,0x9b,0x3c,0x1e,0x16,0x17,0x42];
        let GroupElement(k) = scalarmult(&bobsk, &alicepk);
        assert!(k == k_expected);
    }
}

#[cfg(feature = "benchmarks")]
#[cfg(test)]
mod bench {
    extern crate test;
    use randombytes::randombytes_into;
    use super::*;

    #[bench]
    fn bench_scalarmult(b: &mut test::Bencher) {
        let mut gbs = [0u8; BYTES];
        let mut sbs = [0u8; SCALARBYTES];
        randombytes_into(&mut gbs);
        randombytes_into(&mut sbs);
        let g = GroupElement(gbs);
        let s = Scalar(sbs);
        b.iter(|| {
            scalarmult(&s, &g);
        });
    }

    #[bench]
    fn bench_scalarmult_base(b: &mut test::Bencher) {
        let mut sbs = [0u8; SCALARBYTES];
        randombytes_into(&mut sbs);
        let s = Scalar(sbs);
        b.iter(|| {
            scalarmult_base(&s);
        });
    }
}
<|endoftext|>


<commit_before>#![stable(feature = "wake_trait", since = "1.51.0")]
//! Types and Traits for working with asynchronous tasks.
use core::mem::ManuallyDrop;
use core::task::{RawWaker, RawWakerVTable, Waker};

use crate::sync::Arc;

/// The implementation of waking a task on an executor.
///
/// This trait can be used to create a [`Waker`]. An executor can define an
/// implementation of this trait, and use that to construct a Waker to pass
/// to the tasks that are executed on that executor.
///
/// This trait is a memory-safe and ergonomic alternative to constructing a
/// [`RawWaker`]. It supports the common executor design in which the data used
/// to wake up a task is stored in an [`Arc`]. Some executors (especially
/// those for embedded systems) cannot use this API, which is why [`RawWaker`]
/// exists as an alternative for those systems.
///
/// [arc]: ../../std/sync/struct.Arc.html
///
/// # Examples
///
/// A basic `block_on` function that takes a future and runs it to completion on
/// the current thread.
///
/// **Note:** This example trades correctness for simplicity. In order to prevent
/// deadlocks, production-grade implementations will also need to handle
/// intermediate calls to `thread::unpark` as well as nested invocations.
///
/// ```rust
/// use std::future::Future;
/// use std::sync::Arc;
/// use std::task::{Context, Poll, Wake};
/// use std::thread::{self, Thread};
///
/// /// A waker that wakes up the current thread when called.
/// struct ThreadWaker(Thread);
///
/// impl Wake for ThreadWaker {
///     fn wake(self: Arc<Self>) {
///         self.0.unpark();
///     }
/// }
///
/// /// Run a future to completion on the current thread.
/// fn block_on<T>(fut: impl Future<Output = T>) -> T {
///     // Pin the future so it can be polled.
///     let mut fut = Box::pin(fut);
///
///     // Create a new context to be passed to the future.
///     let t = thread::current();
///     let waker = Arc::new(ThreadWaker(t)).into();
///     let mut cx = Context::from_waker(&waker);
///
///     // Run the future to completion.
///     loop {
///         match fut.as_mut().poll(&mut cx) {
///             Poll::Ready(res) => return res,
///             Poll::Pending => thread::park(),
///         }
///     }
/// }
///
/// block_on(async {
///     println!("Hi from inside a future!");
/// });
/// ```
#[stable(feature = "wake_trait", since = "1.51.0")]
pub trait Wake {
    /// Wake this task.
    #[stable(feature = "wake_trait", since = "1.51.0")]
    fn wake(self: Arc<Self>);

    /// Wake this task without consuming the waker.
    ///
    /// If an executor supports a cheaper way to wake without consuming the
    /// waker, it should override this method. By default, it clones the
    /// [`Arc`] and calls [`wake`] on the clone.
    ///
    /// [`wake`]: Wake::wake
    #[stable(feature = "wake_trait", since = "1.51.0")]
    fn wake_by_ref(self: &Arc<Self>) {
        self.clone().wake();
    }
}

#[stable(feature = "wake_trait", since = "1.51.0")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
    fn from(waker: Arc<W>) -> Waker {
        // SAFETY: This is safe because raw_waker safely constructs
        // a RawWaker from Arc<W>.
        unsafe { Waker::from_raw(raw_waker(waker)) }
    }
}

#[stable(feature = "wake_trait", since = "1.51.0")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
    fn from(waker: Arc<W>) -> RawWaker {
        raw_waker(waker)
    }
}

// NB: This private function for constructing a RawWaker is used, rather than
// inlining this into the `From<Arc<W>> for RawWaker` impl, to ensure that
// the safety of `From<Arc<W>> for Waker` does not depend on the correct
// trait dispatch - instead both impls call this function directly and
// explicitly.
#[inline(always)]
fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
    // Increment the reference count of the arc to clone it.
    unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker {
        unsafe { Arc::increment_strong_count(waker as *const W) };
        RawWaker::new(
            waker as *const (),
            &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
        )
    }

    // Wake by value, moving the Arc into the Wake::wake function
    unsafe fn wake<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        let waker = unsafe { Arc::from_raw(waker as *const W) };
        <W as Wake>::wake(waker);
    }

    // Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
    unsafe fn wake_by_ref<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        let waker = unsafe { ManuallyDrop::new(Arc::from_raw(waker as *const W)) };
        <W as Wake>::wake_by_ref(&waker);
    }

    // Decrement the reference count of the Arc on drop
    unsafe fn drop_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        unsafe { Arc::decrement_strong_count(waker as *const W) };
    }

    RawWaker::new(
        Arc::into_raw(waker) as *const (),
        &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
    )
}
<commit_msg>Document From implementations for Waker and RawWaker<commit_after>#![stable(feature = "wake_trait", since = "1.51.0")]
//! Types and Traits for working with asynchronous tasks.
use core::mem::ManuallyDrop;
use core::task::{RawWaker, RawWakerVTable, Waker};

use crate::sync::Arc;

/// The implementation of waking a task on an executor.
///
/// This trait can be used to create a [`Waker`]. An executor can define an
/// implementation of this trait, and use that to construct a Waker to pass
/// to the tasks that are executed on that executor.
///
/// This trait is a memory-safe and ergonomic alternative to constructing a
/// [`RawWaker`]. It supports the common executor design in which the data used
/// to wake up a task is stored in an [`Arc`]. Some executors (especially
/// those for embedded systems) cannot use this API, which is why [`RawWaker`]
/// exists as an alternative for those systems.
///
/// [arc]: ../../std/sync/struct.Arc.html
///
/// # Examples
///
/// A basic `block_on` function that takes a future and runs it to completion on
/// the current thread.
///
/// **Note:** This example trades correctness for simplicity. In order to prevent
/// deadlocks, production-grade implementations will also need to handle
/// intermediate calls to `thread::unpark` as well as nested invocations.
///
/// ```rust
/// use std::future::Future;
/// use std::sync::Arc;
/// use std::task::{Context, Poll, Wake};
/// use std::thread::{self, Thread};
///
/// /// A waker that wakes up the current thread when called.
/// struct ThreadWaker(Thread);
///
/// impl Wake for ThreadWaker {
///     fn wake(self: Arc<Self>) {
///         self.0.unpark();
///     }
/// }
///
/// /// Run a future to completion on the current thread.
/// fn block_on<T>(fut: impl Future<Output = T>) -> T {
///     // Pin the future so it can be polled.
///     let mut fut = Box::pin(fut);
///
///     // Create a new context to be passed to the future.
///     let t = thread::current();
///     let waker = Arc::new(ThreadWaker(t)).into();
///     let mut cx = Context::from_waker(&waker);
///
///     // Run the future to completion.
///     loop {
///         match fut.as_mut().poll(&mut cx) {
///             Poll::Ready(res) => return res,
///             Poll::Pending => thread::park(),
///         }
///     }
/// }
///
/// block_on(async {
///     println!("Hi from inside a future!");
/// });
/// ```
#[stable(feature = "wake_trait", since = "1.51.0")]
pub trait Wake {
    /// Wake this task.
    #[stable(feature = "wake_trait", since = "1.51.0")]
    fn wake(self: Arc<Self>);

    /// Wake this task without consuming the waker.
    ///
    /// If an executor supports a cheaper way to wake without consuming the
    /// waker, it should override this method. By default, it clones the
    /// [`Arc`] and calls [`wake`] on the clone.
    ///
    /// [`wake`]: Wake::wake
    #[stable(feature = "wake_trait", since = "1.51.0")]
    fn wake_by_ref(self: &Arc<Self>) {
        self.clone().wake();
    }
}

#[stable(feature = "wake_trait", since = "1.51.0")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
    /// Use a `Wake`-able type as a `Waker`.
    ///
    /// No heap allocations or atomic operations are used for this conversion.
    fn from(waker: Arc<W>) -> Waker {
        // SAFETY: This is safe because raw_waker safely constructs
        // a RawWaker from Arc<W>.
        unsafe { Waker::from_raw(raw_waker(waker)) }
    }
}

#[stable(feature = "wake_trait", since = "1.51.0")]
impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
    /// Use a `Wake`-able type as a `RawWaker`.
    ///
    /// No heap allocations or atomic operations are used for this conversion.
    fn from(waker: Arc<W>) -> RawWaker {
        raw_waker(waker)
    }
}

// NB: This private function for constructing a RawWaker is used, rather than
// inlining this into the `From<Arc<W>> for RawWaker` impl, to ensure that
// the safety of `From<Arc<W>> for Waker` does not depend on the correct
// trait dispatch - instead both impls call this function directly and
// explicitly.
#[inline(always)]
fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
    // Increment the reference count of the arc to clone it.
    unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker {
        unsafe { Arc::increment_strong_count(waker as *const W) };
        RawWaker::new(
            waker as *const (),
            &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
        )
    }

    // Wake by value, moving the Arc into the Wake::wake function
    unsafe fn wake<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        let waker = unsafe { Arc::from_raw(waker as *const W) };
        <W as Wake>::wake(waker);
    }

    // Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
    unsafe fn wake_by_ref<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        let waker = unsafe { ManuallyDrop::new(Arc::from_raw(waker as *const W)) };
        <W as Wake>::wake_by_ref(&waker);
    }

    // Decrement the reference count of the Arc on drop
    unsafe fn drop_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) {
        unsafe { Arc::decrement_strong_count(waker as *const W) };
    }

    RawWaker::new(
        Arc::into_raw(waker) as *const (),
        &RawWakerVTable::new(clone_waker::<W>, wake::<W>, wake_by_ref::<W>, drop_waker::<W>),
    )
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Richard Diamond & contributors.
//
// This file is part of the Rust PPApi project.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use ffi;
use ppb::{ResourceInterface, MediaStreamVideoTrackIf, get_media_stream_video_track};

use super::{Callback, CallbackArgs, StringVar, Code, Resource};
use super::video_frame::{self, VideoFrame};

/// Created on the JS side and sent in a message.
#[derive(Hash, Eq, PartialEq, Debug)]
pub struct VideoTrack(ffi::PP_Resource);

impl_clone_drop_for!(VideoTrack);
impl_resource_for!(VideoTrack, ResourceType::VideoFrame);

#[doc(hidden)]
impl From<ffi::PP_Resource> for VideoTrack {
    fn from(v: ffi::PP_Resource) -> VideoTrack {
        debug_assert!(get_media_stream_video_track().is(v));
        VideoTrack(v)
    }
}

#[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)]
pub enum Attr {
    /// The number of buffer frames. Chrome may use more or less. How many
    /// frames to buffer depends on usage - request at least 2 to make sure
    /// latency doesn't cause lost frames. If the plugin expects to hold on to
    /// more than one frame at a time (e.g. to do multi-frame processing), it
    /// should request that many more. If this attribute is not specified or
    /// value 0 is specified for this attribute, the default value will be
    /// used.
    Buffers(u32),

    /// The width of video frames in pixels.
    ///
    /// It should be a multiple of 4. If the specified size is different from
    /// the video source (webcam), frames will be scaled to specified size. If
    /// this attribute is not specified or value 0 is specified, the original
    /// frame size of the video track will be used.
    ///
    /// Maximum value: 4096 (4K resolution).
    Width(u32),
    /// The height of video frames in pixels.
    ///
    /// It should be a multiple of 4. If the specified size is different from
    /// the video source (webcam), frames will be scaled to specified size. If
    /// this attribute is not specified or value 0 is specified, the original
    /// frame size of the video track will be used.
    ///
    /// Maximum value: 4096 (4K resolution).
    Height(u32),

    /// The format of video frames.
    ///
    /// The attribute value is a `video_frame::Format`. If the specified
    /// format is different from the video source (webcam), frames will be
    /// converted to specified format. If this attribute is not specified or
    /// value `Format::Unknown` is specified, the orignal frame format of the
    /// video track will be used.
    Format(video_frame::Format),
}
impl Attr {
    #[doc(hidden)]
    pub fn to_ffi(self) -> ffi::PP_MediaStreamVideoTrack_Attrib {
        match self {
            Attr::Buffers(..) => ffi::PP_MEDIASTREAMVIDEOTRACK_ATTRIB_BUFFERED_FRAMES,
            Attr::Width(..) => ffi::PP_MEDIASTREAMVIDEOTRACK_ATTRIB_WIDTH,
            Attr::Height(..) => ffi::PP_MEDIASTREAMVIDEOTRACK_ATTRIB_HEIGHT,
            Attr::Format(..) => ffi::PP_MEDIASTREAMVIDEOTRACK_ATTRIB_FORMAT,
        }
    }
}

impl VideoTrack {
    pub fn configure<'a, T: AsRef<&'a [Attr]>, F>(&self, attrs: T, callback: F) -> Code
        where F: Callback
    {
        use std::cmp::min;

        let mut nattrs: Vec<ffi::PP_MediaStreamVideoTrack_Attrib> =
            Vec::with_capacity(attrs.as_ref().len() + 1);
        for attr in attrs.as_ref().iter() {
            nattrs.push(attr.to_ffi());
            match attr {
                &Attr::Buffers(c) => {
                    nattrs.push(c as ffi::PP_MediaStreamVideoTrack_Attrib);
                },
                &Attr::Width(c) | &Attr::Height(c) => {
                    nattrs.push(min(c, 4096) as ffi::PP_MediaStreamVideoTrack_Attrib);
                },
                &Attr::Format(f) => {
                    nattrs.push(f.to_ffi());
                },
            }
        }
        nattrs.push(ffi::PP_MEDIASTREAMVIDEOTRACK_ATTRIB_NONE);

        let cc = callback.to_ffi_callback();

        let code = get_media_stream_video_track()
            .configure(self.unwrap(), nattrs.as_ref(), cc.cc);
        cc.drop_with_code(code)
    }
    pub fn buffer_count(&self) -> Code<u32> {
        get_media_stream_video_track()
            .get_attrib(self.unwrap(), Attr::Buffers(0).to_ffi())
            .map_ok(|i| {
                i as u32
            })
    }
    pub fn width(&self) -> Code<u32> {
        get_media_stream_video_track()
            .get_attrib(self.unwrap(), Attr::Width(0).to_ffi())
            .map_ok(|i| {
                i as u32
            })
    }
    pub fn height(&self) -> Code<u32> {
        get_media_stream_video_track()
            .get_attrib(self.unwrap(), Attr::Height(0).to_ffi())
            .map_ok(|i| {
                i as u32
            })
    }
    pub fn format(&self) -> Code<video_frame::Format> {
        get_media_stream_video_track()
            .get_attrib(self.unwrap(),
                        Attr::Format(video_frame::Format::Unknown).to_ffi())
            .map_ok(|i| {
                From::from(i as ffi::PP_VideoFrame_Format)
            })
    }
    pub fn get_id(&self) -> StringVar {
        From::from(get_media_stream_video_track().get_id(self.unwrap()))
    }
    pub fn has_ended(&self) -> bool {
        get_media_stream_video_track()
            .has_ended(self.unwrap())
    }
    pub fn get_frame<F>(&self, f: CallbackArgs<F, (VideoTrack, VideoFrame)>) ->
        Code<(VideoTrack, VideoFrame)> where F: FnOnce(Code<(VideoTrack, VideoFrame)>)
    {
        impl super::InPlaceInit for (VideoTrack, i32) { }
        fn map_args((this, frame): (VideoTrack, i32), _status: Code) ->
            (VideoTrack, VideoFrame)
        {
            (this, From::from(frame))
        }

        let mapper = super::StorageToArgsMapper(map_args);
        let mut cc = f.to_ffi_callback((self.clone(), 0i32), mapper);
        let fficc = cc.cc;
        let code = get_media_stream_video_track()
            .get_frame(self.unwrap(), &mut cc.1, fficc);
        cc.drop_with_code(code)
    }
    pub fn recycle_frame(&self, frame: VideoFrame) -> Code {
        get_media_stream_video_track()
            .recycle_frame(self.unwrap(), frame.unwrap())
    }
    pub fn close(self) {
        get_media_stream_video_track()
            .close(self.unwrap())
    }
}
<commit_msg>Update configure to use `CallbackArgs`.<commit_after>// Copyright (c) 2014 Richard Diamond & contributors.
//
// This file is part of the Rust PPApi project.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use ffi;
use ppb::{ResourceInterface, MediaStreamVideoTrackIf, get_media_stream_video_track};

use super::{Callback, CallbackArgs, StringVar, Code, Resource};
use super::video_frame::{self, VideoFrame};

/// Created on the JS side and sent in a message.
#[derive(Hash, Eq, PartialEq, Debug)]
pub struct VideoTrack(ffi::PP_Resource);

impl_clone_drop_for!(VideoTrack);
impl_resource_for!(VideoTrack, ResourceType::VideoFrame);

#[doc(hidden)]
impl From<ffi::PP_Resource> for VideoTrack {
    fn from(v: ffi::PP_Resource) -> VideoTrack {
        debug_assert!(get_media_stream_video_track().is(v));
        VideoTrack(v)
    }
}

#[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)]
pub enum Attr {
    /// The number of buffer frames. Chrome may use more or less. How many
    /// frames to buffer depends on usage - request at least 2 to make sure
    /// latency doesn't cause lost frames. If the plugin expects to hold on to
    /// more than one frame at a time (e.g. to do multi-frame processing), it
    /// should request that many more. If this attribute is not specified or
    /// value 0 is specified for this attribute, the default value will be
    /// used.
    Buffers(u32),

    /// The width of video frames in pixels.
    ///
    /// It should be a multiple of 4. If the specified size is different from
    /// the video source (webcam), frames will be scaled to specified size. If
    /// this attribute is not specified or value 0 is specified, the original
    /// frame size of the video track will be used.
    ///
    /// Maximum value: 4096 (4K resolution).
    Width(u32),
    /// The height of video frames in pixels.
    ///
    /// It should be a multiple of 4. If the specified size is different from
    /// the video source (webcam), frames will be scaled to specified size. If
    /// this attribute is not specified or value 0 is specified, the original
    /// frame size of the video track will be used.
    ///
    /// Maximum value: 4096 (4K resolution).
    Height(u32),

    /// The format of video frames.
    ///
    /// The attribute value is a `video_frame::Format`. If the specified
    /// format is different from the video source (webcam), frames will be
    /// converted to specified format. If this attribute is not specified or
    /// value `Format::Unknown` is specified, the orignal frame format of the
    /// video track will be used.
    Format(video_frame::Format),
}
impl Attr {
    #[doc(hidden)]
    pub fn to_ffi(self) -> ffi::PP_MediaStreamVideoTrack_Attrib {
        match self {
            Attr::Buffers(..) => ffi::PP_MEDIASTREAMVIDEOTRACK_ATTRIB_BUFFERED_FRAMES,
            Attr::Width(..) => ffi::PP_MEDIASTREAMVIDEOTRACK_ATTRIB_WIDTH,
            Attr::Height(..) => ffi::PP_MEDIASTREAMVIDEOTRACK_ATTRIB_HEIGHT,
            Attr::Format(..) => ffi::PP_MEDIASTREAMVIDEOTRACK_ATTRIB_FORMAT,
        }
    }
}

impl VideoTrack {
    pub fn configure<'a, T: AsRef<&'a [Attr]>, F>(&self, attrs: T, callback: CallbackArgs<F, ()>) -> Code<()>
        where F: FnOnce(Code<()>)
    {
        use std::cmp::min;

        let mut nattrs: Vec<ffi::PP_MediaStreamVideoTrack_Attrib> =
            Vec::with_capacity(attrs.as_ref().len() + 1);
        for attr in attrs.as_ref().iter() {
            nattrs.push(attr.to_ffi());
            match attr {
                &Attr::Buffers(c) => {
                    nattrs.push(c as ffi::PP_MediaStreamVideoTrack_Attrib);
                },
                &Attr::Width(c) | &Attr::Height(c) => {
                    nattrs.push(min(c, 4096) as ffi::PP_MediaStreamVideoTrack_Attrib);
                },
                &Attr::Format(f) => {
                    nattrs.push(f.to_ffi());
                },
            }
        }
        nattrs.push(ffi::PP_MEDIASTREAMVIDEOTRACK_ATTRIB_NONE);

        let cc = callback.to_ffi_callback();

        let code = get_media_stream_video_track()
            .configure(self.unwrap(), nattrs.as_ref(), cc.cc);
        cc.drop_with_code(code)
    }
    pub fn buffer_count(&self) -> Code<u32> {
        get_media_stream_video_track()
            .get_attrib(self.unwrap(), Attr::Buffers(0).to_ffi())
            .map_ok(|i| {
                i as u32
            })
    }
    pub fn width(&self) -> Code<u32> {
        get_media_stream_video_track()
            .get_attrib(self.unwrap(), Attr::Width(0).to_ffi())
            .map_ok(|i| {
                i as u32
            })
    }
    pub fn height(&self) -> Code<u32> {
        get_media_stream_video_track()
            .get_attrib(self.unwrap(), Attr::Height(0).to_ffi())
            .map_ok(|i| {
                i as u32
            })
    }
    pub fn format(&self) -> Code<video_frame::Format> {
        get_media_stream_video_track()
            .get_attrib(self.unwrap(),
                        Attr::Format(video_frame::Format::Unknown).to_ffi())
            .map_ok(|i| {
                From::from(i as ffi::PP_VideoFrame_Format)
            })
    }
    pub fn get_id(&self) -> StringVar {
        From::from(get_media_stream_video_track().get_id(self.unwrap()))
    }
    pub fn has_ended(&self) -> bool {
        get_media_stream_video_track()
            .has_ended(self.unwrap())
    }
    pub fn get_frame<F>(&self, f: CallbackArgs<F, (VideoTrack, VideoFrame)>) ->
        Code<(VideoTrack, VideoFrame)> where F: FnOnce(Code<(VideoTrack, VideoFrame)>)
    {
        impl super::InPlaceInit for (VideoTrack, i32) { }
        fn map_args((this, frame): (VideoTrack, i32), _status: Code) ->
            (VideoTrack, VideoFrame)
        {
            (this, From::from(frame))
        }

        let mapper = super::StorageToArgsMapper(map_args);
        let mut cc = f.to_ffi_callback((self.clone(), 0i32), mapper);
        let fficc = cc.cc;
        let code = get_media_stream_video_track()
            .get_frame(self.unwrap(), &mut cc.1, fficc);
        cc.drop_with_code(code)
    }
    pub fn recycle_frame(&self, frame: VideoFrame) -> Code {
        get_media_stream_video_track()
            .recycle_frame(self.unwrap(), frame.unwrap())
    }
    pub fn close(self) {
        get_media_stream_video_track()
            .close(self.unwrap())
    }
}
<|endoftext|>


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

#![allow(unknown_lints)]

use ty::layout::{HasDataLayout, Size};
use ty::subst::Substs;
use hir::def_id::DefId;

use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};

/// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
/// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
pub enum ConstValue<'tcx> {
    /// Never returned from the `const_eval` query, but the HIR contains these frequently in order
    /// to allow HIR creation to happen for everything before needing to be able to run constant
    /// evaluation
    Unevaluated(DefId, &'tcx Substs<'tcx>),

    /// Used only for types with layout::abi::Scalar ABI and ZSTs
    ///
    /// Not using the enum `Value` to encode that this must not be `Undef`
    Scalar(Scalar),

    /// Used only for *fat pointers* with layout::abi::ScalarPair
    ///
    /// Needed for pattern matching code related to slices and strings.
    ScalarPair(Scalar, Scalar),

    /// An allocation + offset into the allocation.
    /// Invariant: The AllocId matches the allocation.
    ByRef(AllocId, &'tcx Allocation, Size),
}

impl<'tcx> ConstValue<'tcx> {
    #[inline]
    pub fn try_to_scalar(&self) -> Option<Scalar> {
        match *self {
            ConstValue::Unevaluated(..) |
            ConstValue::ByRef(..) |
            ConstValue::ScalarPair(..) => None,
            ConstValue::Scalar(val) => Some(val),
        }
    }

    #[inline]
    pub fn try_to_bits(&self, size: Size) -> Option<u128> {
        self.try_to_scalar()?.to_bits(size).ok()
    }

    #[inline]
    pub fn try_to_ptr(&self) -> Option<Pointer> {
        self.try_to_scalar()?.to_ptr().ok()
    }

    #[inline]
    pub fn new_slice(
        val: Scalar,
        len: u64,
        cx: impl HasDataLayout
    ) -> Self {
        ConstValue::ScalarPair(val, Scalar::Bits {
            bits: len as u128,
            size: cx.data_layout().pointer_size.bytes() as u8,
        })
    }

    #[inline]
    pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
        ConstValue::ScalarPair(val, Scalar::Ptr(vtable))
    }
}

/// A `Scalar` represents an immediate, primitive value existing outside of a
/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
/// of a simple value or a pointer into another `Allocation`
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
pub enum Scalar<Tag=(), Id=AllocId> {
    /// The raw bytes of a simple value.
    Bits {
        /// The first `size` bytes are the value.
        /// Do not try to read less or more bytes that that. The remaining bytes must be 0.
        size: u8,
        bits: u128,
    },

    /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
    /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
    /// relocation and its associated offset together as a `Pointer` here.
    Ptr(Pointer<Tag, Id>),
}

impl<'tcx> Scalar<()> {
    #[inline]
    pub fn with_default_tag<Tag>(self) -> Scalar<Tag>
        where Tag: Default
    {
        match self {
            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_default_tag()),
            Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
        }
    }
}

impl<'tcx, Tag> Scalar<Tag> {
    #[inline]
    pub fn erase_tag(self) -> Scalar {
        match self {
            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.erase_tag()),
            Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
        }
    }

    #[inline]
    pub fn ptr_null(cx: impl HasDataLayout) -> Self {
        Scalar::Bits {
            bits: 0,
            size: cx.data_layout().pointer_size.bytes() as u8,
        }
    }

    #[inline]
    pub fn zst() -> Self {
        Scalar::Bits { bits: 0, size: 0 }
    }

    #[inline]
    pub fn ptr_signed_offset(self, i: i64, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Ok(Scalar::Bits {
                    bits: layout.signed_offset(bits as u64, i)? as u128,
                    size,
                })
            }
            Scalar::Ptr(ptr) => ptr.signed_offset(i, layout).map(Scalar::Ptr),
        }
    }

    #[inline]
    pub fn ptr_offset(self, i: Size, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Ok(Scalar::Bits {
                    bits: layout.offset(bits as u64, i.bytes())? as u128,
                    size,
                })
            }
            Scalar::Ptr(ptr) => ptr.offset(i, layout).map(Scalar::Ptr),
        }
    }

    #[inline]
    pub fn ptr_wrapping_signed_offset(self, i: i64, cx: impl HasDataLayout) -> Self {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Scalar::Bits {
                    bits: layout.wrapping_signed_offset(bits as u64, i) as u128,
                    size,
                }
            }
            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_signed_offset(i, layout)),
        }
    }

    #[inline]
    pub fn is_null_ptr(self, cx: impl HasDataLayout) -> bool {
        match self {
            Scalar::Bits { bits, size } =>  {
                assert_eq!(size as u64, cx.data_layout().pointer_size.bytes());
                bits == 0
            },
            Scalar::Ptr(_) => false,
        }
    }

    #[inline]
    pub fn is_null(self) -> bool {
        match self {
            Scalar::Bits { bits, .. } => bits == 0,
            Scalar::Ptr(_) => false
        }
    }

    #[inline]
    pub fn from_bool(b: bool) -> Self {
        Scalar::Bits { bits: b as u128, size: 1 }
    }

    #[inline]
    pub fn from_char(c: char) -> Self {
        Scalar::Bits { bits: c as u128, size: 4 }
    }

    #[inline]
    pub fn from_uint(i: impl Into<u128>, size: Size) -> Self {
        let i = i.into();
        debug_assert_eq!(truncate(i, size), i,
                         "Unsigned value {} does not fit in {} bits", i, size.bits());
        Scalar::Bits { bits: i, size: size.bytes() as u8 }
    }

    #[inline]
    pub fn from_int(i: impl Into<i128>, size: Size) -> Self {
        let i = i.into();
        // `into` performed sign extension, we have to truncate
        let truncated = truncate(i as u128, size);
        debug_assert_eq!(sign_extend(truncated, size) as i128, i,
                         "Signed value {} does not fit in {} bits", i, size.bits());
        Scalar::Bits { bits: truncated, size: size.bytes() as u8 }
    }

    #[inline]
    pub fn from_f32(f: f32) -> Self {
        Scalar::Bits { bits: f.to_bits() as u128, size: 4 }
    }

    #[inline]
    pub fn from_f64(f: f64) -> Self {
        Scalar::Bits { bits: f.to_bits() as u128, size: 8 }
    }

    #[inline]
    pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(target_size.bytes(), size as u64);
                assert_ne!(size, 0, "to_bits cannot be used with zsts");
                Ok(bits)
            }
            Scalar::Ptr(_) => err!(ReadPointerAsBytes),
        }
    }

    #[inline]
    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
        match self {
            Scalar::Bits { bits: 0, .. } => err!(InvalidNullPointerUsage),
            Scalar::Bits { .. } => err!(ReadBytesAsPointer),
            Scalar::Ptr(p) => Ok(p),
        }
    }

    #[inline]
    pub fn is_bits(self) -> bool {
        match self {
            Scalar::Bits { .. } => true,
            _ => false,
        }
    }

    #[inline]
    pub fn is_ptr(self) -> bool {
        match self {
            Scalar::Ptr(_) => true,
            _ => false,
        }
    }

    pub fn to_bool(self) -> EvalResult<'tcx, bool> {
        match self {
            Scalar::Bits { bits: 0, size: 1 } => Ok(false),
            Scalar::Bits { bits: 1, size: 1 } => Ok(true),
            _ => err!(InvalidBool),
        }
    }

    pub fn to_char(self) -> EvalResult<'tcx, char> {
        let val = self.to_u32()?;
        match ::std::char::from_u32(val) {
            Some(c) => Ok(c),
            None => err!(InvalidChar(val as u128)),
        }
    }

    pub fn to_u8(self) -> EvalResult<'static, u8> {
        let sz = Size::from_bits(8);
        let b = self.to_bits(sz)?;
        assert_eq!(b as u8 as u128, b);
        Ok(b as u8)
    }

    pub fn to_u32(self) -> EvalResult<'static, u32> {
        let sz = Size::from_bits(32);
        let b = self.to_bits(sz)?;
        assert_eq!(b as u32 as u128, b);
        Ok(b as u32)
    }

    pub fn to_u64(self) -> EvalResult<'static, u64> {
        let sz = Size::from_bits(64);
        let b = self.to_bits(sz)?;
        assert_eq!(b as u64 as u128, b);
        Ok(b as u64)
    }

    pub fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> {
        let b = self.to_bits(cx.data_layout().pointer_size)?;
        assert_eq!(b as u64 as u128, b);
        Ok(b as u64)
    }

    pub fn to_i8(self) -> EvalResult<'static, i8> {
        let sz = Size::from_bits(8);
        let b = self.to_bits(sz)?;
        let b = sign_extend(b, sz) as i128;
        assert_eq!(b as i8 as i128, b);
        Ok(b as i8)
    }

    pub fn to_i32(self) -> EvalResult<'static, i32> {
        let sz = Size::from_bits(32);
        let b = self.to_bits(sz)?;
        let b = sign_extend(b, sz) as i128;
        assert_eq!(b as i32 as i128, b);
        Ok(b as i32)
    }

    pub fn to_i64(self) -> EvalResult<'static, i64> {
        let sz = Size::from_bits(64);
        let b = self.to_bits(sz)?;
        let b = sign_extend(b, sz) as i128;
        assert_eq!(b as i64 as i128, b);
        Ok(b as i64)
    }

    pub fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> {
        let b = self.to_bits(cx.data_layout().pointer_size)?;
        let b = sign_extend(b, cx.data_layout().pointer_size) as i128;
        assert_eq!(b as i64 as i128, b);
        Ok(b as i64)
    }

    #[inline]
    pub fn to_f32(self) -> EvalResult<'static, f32> {
        Ok(f32::from_bits(self.to_u32()?))
    }

    #[inline]
    pub fn to_f64(self) -> EvalResult<'static, f64> {
        Ok(f64::from_bits(self.to_u64()?))
    }
}

impl<Tag> From<Pointer<Tag>> for Scalar<Tag> {
    #[inline(always)]
    fn from(ptr: Pointer<Tag>) -> Self {
        Scalar::Ptr(ptr)
    }
}
<commit_msg>Rollup merge of #55345 - RalfJung:no-null, r=oli-obk<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(unknown_lints)]

use ty::layout::{HasDataLayout, Size};
use ty::subst::Substs;
use hir::def_id::DefId;

use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};

/// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
/// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
pub enum ConstValue<'tcx> {
    /// Never returned from the `const_eval` query, but the HIR contains these frequently in order
    /// to allow HIR creation to happen for everything before needing to be able to run constant
    /// evaluation
    Unevaluated(DefId, &'tcx Substs<'tcx>),

    /// Used only for types with layout::abi::Scalar ABI and ZSTs
    ///
    /// Not using the enum `Value` to encode that this must not be `Undef`
    Scalar(Scalar),

    /// Used only for *fat pointers* with layout::abi::ScalarPair
    ///
    /// Needed for pattern matching code related to slices and strings.
    ScalarPair(Scalar, Scalar),

    /// An allocation + offset into the allocation.
    /// Invariant: The AllocId matches the allocation.
    ByRef(AllocId, &'tcx Allocation, Size),
}

impl<'tcx> ConstValue<'tcx> {
    #[inline]
    pub fn try_to_scalar(&self) -> Option<Scalar> {
        match *self {
            ConstValue::Unevaluated(..) |
            ConstValue::ByRef(..) |
            ConstValue::ScalarPair(..) => None,
            ConstValue::Scalar(val) => Some(val),
        }
    }

    #[inline]
    pub fn try_to_bits(&self, size: Size) -> Option<u128> {
        self.try_to_scalar()?.to_bits(size).ok()
    }

    #[inline]
    pub fn try_to_ptr(&self) -> Option<Pointer> {
        self.try_to_scalar()?.to_ptr().ok()
    }

    #[inline]
    pub fn new_slice(
        val: Scalar,
        len: u64,
        cx: impl HasDataLayout
    ) -> Self {
        ConstValue::ScalarPair(val, Scalar::Bits {
            bits: len as u128,
            size: cx.data_layout().pointer_size.bytes() as u8,
        })
    }

    #[inline]
    pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
        ConstValue::ScalarPair(val, Scalar::Ptr(vtable))
    }
}

/// A `Scalar` represents an immediate, primitive value existing outside of a
/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
/// of a simple value or a pointer into another `Allocation`
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
pub enum Scalar<Tag=(), Id=AllocId> {
    /// The raw bytes of a simple value.
    Bits {
        /// The first `size` bytes are the value.
        /// Do not try to read less or more bytes that that. The remaining bytes must be 0.
        size: u8,
        bits: u128,
    },

    /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
    /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
    /// relocation and its associated offset together as a `Pointer` here.
    Ptr(Pointer<Tag, Id>),
}

impl<'tcx> Scalar<()> {
    #[inline]
    pub fn with_default_tag<Tag>(self) -> Scalar<Tag>
        where Tag: Default
    {
        match self {
            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_default_tag()),
            Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
        }
    }
}

impl<'tcx, Tag> Scalar<Tag> {
    #[inline]
    pub fn erase_tag(self) -> Scalar {
        match self {
            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.erase_tag()),
            Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
        }
    }

    #[inline]
    pub fn ptr_null(cx: impl HasDataLayout) -> Self {
        Scalar::Bits {
            bits: 0,
            size: cx.data_layout().pointer_size.bytes() as u8,
        }
    }

    #[inline]
    pub fn zst() -> Self {
        Scalar::Bits { bits: 0, size: 0 }
    }

    #[inline]
    pub fn ptr_signed_offset(self, i: i64, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Ok(Scalar::Bits {
                    bits: layout.signed_offset(bits as u64, i)? as u128,
                    size,
                })
            }
            Scalar::Ptr(ptr) => ptr.signed_offset(i, layout).map(Scalar::Ptr),
        }
    }

    #[inline]
    pub fn ptr_offset(self, i: Size, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Ok(Scalar::Bits {
                    bits: layout.offset(bits as u64, i.bytes())? as u128,
                    size,
                })
            }
            Scalar::Ptr(ptr) => ptr.offset(i, layout).map(Scalar::Ptr),
        }
    }

    #[inline]
    pub fn ptr_wrapping_signed_offset(self, i: i64, cx: impl HasDataLayout) -> Self {
        let layout = cx.data_layout();
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, layout.pointer_size.bytes());
                Scalar::Bits {
                    bits: layout.wrapping_signed_offset(bits as u64, i) as u128,
                    size,
                }
            }
            Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_signed_offset(i, layout)),
        }
    }

    #[inline]
    pub fn is_null_ptr(self, cx: impl HasDataLayout) -> bool {
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(size as u64, cx.data_layout().pointer_size.bytes());
                bits == 0
            },
            Scalar::Ptr(_) => false,
        }
    }

    #[inline]
    pub fn from_bool(b: bool) -> Self {
        Scalar::Bits { bits: b as u128, size: 1 }
    }

    #[inline]
    pub fn from_char(c: char) -> Self {
        Scalar::Bits { bits: c as u128, size: 4 }
    }

    #[inline]
    pub fn from_uint(i: impl Into<u128>, size: Size) -> Self {
        let i = i.into();
        debug_assert_eq!(truncate(i, size), i,
                         "Unsigned value {} does not fit in {} bits", i, size.bits());
        Scalar::Bits { bits: i, size: size.bytes() as u8 }
    }

    #[inline]
    pub fn from_int(i: impl Into<i128>, size: Size) -> Self {
        let i = i.into();
        // `into` performed sign extension, we have to truncate
        let truncated = truncate(i as u128, size);
        debug_assert_eq!(sign_extend(truncated, size) as i128, i,
                         "Signed value {} does not fit in {} bits", i, size.bits());
        Scalar::Bits { bits: truncated, size: size.bytes() as u8 }
    }

    #[inline]
    pub fn from_f32(f: f32) -> Self {
        Scalar::Bits { bits: f.to_bits() as u128, size: 4 }
    }

    #[inline]
    pub fn from_f64(f: f64) -> Self {
        Scalar::Bits { bits: f.to_bits() as u128, size: 8 }
    }

    #[inline]
    pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
        match self {
            Scalar::Bits { bits, size } => {
                assert_eq!(target_size.bytes(), size as u64);
                assert_ne!(size, 0, "to_bits cannot be used with zsts");
                Ok(bits)
            }
            Scalar::Ptr(_) => err!(ReadPointerAsBytes),
        }
    }

    #[inline]
    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
        match self {
            Scalar::Bits { bits: 0, .. } => err!(InvalidNullPointerUsage),
            Scalar::Bits { .. } => err!(ReadBytesAsPointer),
            Scalar::Ptr(p) => Ok(p),
        }
    }

    #[inline]
    pub fn is_bits(self) -> bool {
        match self {
            Scalar::Bits { .. } => true,
            _ => false,
        }
    }

    #[inline]
    pub fn is_ptr(self) -> bool {
        match self {
            Scalar::Ptr(_) => true,
            _ => false,
        }
    }

    pub fn to_bool(self) -> EvalResult<'tcx, bool> {
        match self {
            Scalar::Bits { bits: 0, size: 1 } => Ok(false),
            Scalar::Bits { bits: 1, size: 1 } => Ok(true),
            _ => err!(InvalidBool),
        }
    }

    pub fn to_char(self) -> EvalResult<'tcx, char> {
        let val = self.to_u32()?;
        match ::std::char::from_u32(val) {
            Some(c) => Ok(c),
            None => err!(InvalidChar(val as u128)),
        }
    }

    pub fn to_u8(self) -> EvalResult<'static, u8> {
        let sz = Size::from_bits(8);
        let b = self.to_bits(sz)?;
        assert_eq!(b as u8 as u128, b);
        Ok(b as u8)
    }

    pub fn to_u32(self) -> EvalResult<'static, u32> {
        let sz = Size::from_bits(32);
        let b = self.to_bits(sz)?;
        assert_eq!(b as u32 as u128, b);
        Ok(b as u32)
    }

    pub fn to_u64(self) -> EvalResult<'static, u64> {
        let sz = Size::from_bits(64);
        let b = self.to_bits(sz)?;
        assert_eq!(b as u64 as u128, b);
        Ok(b as u64)
    }

    pub fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> {
        let b = self.to_bits(cx.data_layout().pointer_size)?;
        assert_eq!(b as u64 as u128, b);
        Ok(b as u64)
    }

    pub fn to_i8(self) -> EvalResult<'static, i8> {
        let sz = Size::from_bits(8);
        let b = self.to_bits(sz)?;
        let b = sign_extend(b, sz) as i128;
        assert_eq!(b as i8 as i128, b);
        Ok(b as i8)
    }

    pub fn to_i32(self) -> EvalResult<'static, i32> {
        let sz = Size::from_bits(32);
        let b = self.to_bits(sz)?;
        let b = sign_extend(b, sz) as i128;
        assert_eq!(b as i32 as i128, b);
        Ok(b as i32)
    }

    pub fn to_i64(self) -> EvalResult<'static, i64> {
        let sz = Size::from_bits(64);
        let b = self.to_bits(sz)?;
        let b = sign_extend(b, sz) as i128;
        assert_eq!(b as i64 as i128, b);
        Ok(b as i64)
    }

    pub fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> {
        let b = self.to_bits(cx.data_layout().pointer_size)?;
        let b = sign_extend(b, cx.data_layout().pointer_size) as i128;
        assert_eq!(b as i64 as i128, b);
        Ok(b as i64)
    }

    #[inline]
    pub fn to_f32(self) -> EvalResult<'static, f32> {
        Ok(f32::from_bits(self.to_u32()?))
    }

    #[inline]
    pub fn to_f64(self) -> EvalResult<'static, f64> {
        Ok(f64::from_bits(self.to_u64()?))
    }
}

impl<Tag> From<Pointer<Tag>> for Scalar<Tag> {
    #[inline(always)]
    fn from(ptr: Pointer<Tag>) -> Self {
        Scalar::Ptr(ptr)
    }
}
<|endoftext|>