<commit_before>use regex::Regex;

use std::path::PathBuf;
use std::str;

use ::errors::{ErrorKind, Result, ResultExt};

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) struct FileMask {
    zero_padded: bool,
    digits: usize,
}

#[derive(Clone, Debug, PartialEq, Hash)]
pub enum PathMode<'a> {
    Filemask(&'a str),
    Folder(&'a str),
}

pub(crate) fn parse_filemask<S: Into<String>>(s: S) -> Result<(String, FileMask, String)> {
    let s = s.into();
    let re = Regex::new(r"%(0)?([\d]+)d").unwrap();
    let mut result: Option<(String, FileMask, String)> = None;

    for cap in re.captures_iter(&s) {
        if result.is_some() {
            bail!(ErrorKind::MultipleFileMasks);
        }
        let mask = FileMask {
            zero_padded: cap.get(1).is_some(),
            digits: cap.get(2)
                .unwrap()
                .as_str()
                .parse()
                .unwrap(),
        };

        let mat = cap.get(0).unwrap();
        result = Some(((&s[..mat.start()]).into(), mask, (&s[mat.end()..]).into()));
    }

    match result {
        Some(result) => Ok(result),
        None => bail!(ErrorKind::NoFileMaskFound),
    }
}

pub fn get_paths(path_mode: PathMode) -> Result<Vec<PathBuf>> {
    match path_mode {
        PathMode::Filemask(filemask) => {
            let (left, mask, right) = parse_filemask(filemask)
                .chain_err(|| ErrorKind::CouldNotParseFilemask(filemask.into()))?;

            let mut paths = vec![];
            let width = if mask.zero_padded { mask.digits } else { 0 };
            for i in 0..10u32.pow(mask.digits as u32) {
                let filename = format!("{}{:0width$}{}", left, i, right, width = width);
                let buf: PathBuf = filename.into();

                if !buf.exists() {
                    if !paths.is_empty() {
                        // If we already started, then let's just end (i.e. we want the first actual
                        // sequence of files).
                        break;
                    }
                    // Otherwise do nothing
                } else {
                    paths.push(buf);
                }
            }

            if paths.is_empty() {
                bail!(ErrorKind::NoFilesFound);
            }

            Ok(paths)
        }
        PathMode::Folder(folder) => {
            // TODO
            bail!(ErrorKind::Unimplemented)
        },
    }
}

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

    use ::errors::*;

    #[test]
    fn test_parse_filemask() {
        let input1 = "foo%03d.png";
        let input2 = "foo%5d.jpg";
        let input3 = "foo.png";
        let input4 = "foo%02dbar%4d.png";

        let expected1 = ("foo".into(),
                         FileMask {
            zero_padded: true,
            digits: 3,
        },
                         ".png".into());

        let expected2 = ("foo".into(),
                         FileMask {
            zero_padded: false,
            digits: 5,
        },
                         ".jpg".into());

        assert_eq!(expected1, parse_filemask(input1).unwrap());
        assert_eq!(expected2, parse_filemask(input2).unwrap());
        match parse_filemask(input3) {
            Err(Error(ErrorKind::NoFileMaskFound, _)) => (),
            Err(e) => {
                assert!(false,
                        "expected `{}`, got `{}` instead.",
                        ErrorKind::NoFileMaskFound.description(),
                        e.description())
            }
            Ok(result) => {
                assert!(false,
                        "expected no file mask found error, but parsing succeeded with {:?}.",
                        result)
            }
        }
        match parse_filemask(input4) {
            Err(Error(ErrorKind::MultipleFileMasks, _)) => (),
            Err(Error(e, _)) => {
                assert!(false,
                        "expected `{}`, got `{}` instead.",
                        ErrorKind::MultipleFileMasks.description(),
                        e.description())
            }
            Ok(result) => {
                assert!(false,
                        "expected no file mask found error, but parsing succeeded with {:?}.",
                        result)
            }
        }
    }
}
<commit_msg>Mark variable as unused in unimplemented match arm<commit_after>use regex::Regex;

use std::path::PathBuf;
use std::str;

use ::errors::{ErrorKind, Result, ResultExt};

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub(crate) struct FileMask {
    zero_padded: bool,
    digits: usize,
}

#[derive(Clone, Debug, PartialEq, Hash)]
pub enum PathMode<'a> {
    Filemask(&'a str),
    Folder(&'a str),
}

pub(crate) fn parse_filemask<S: Into<String>>(s: S) -> Result<(String, FileMask, String)> {
    let s = s.into();
    let re = Regex::new(r"%(0)?([\d]+)d").unwrap();
    let mut result: Option<(String, FileMask, String)> = None;

    for cap in re.captures_iter(&s) {
        if result.is_some() {
            bail!(ErrorKind::MultipleFileMasks);
        }
        let mask = FileMask {
            zero_padded: cap.get(1).is_some(),
            digits: cap.get(2)
                .unwrap()
                .as_str()
                .parse()
                .unwrap(),
        };

        let mat = cap.get(0).unwrap();
        result = Some(((&s[..mat.start()]).into(), mask, (&s[mat.end()..]).into()));
    }

    match result {
        Some(result) => Ok(result),
        None => bail!(ErrorKind::NoFileMaskFound),
    }
}

pub fn get_paths(path_mode: PathMode) -> Result<Vec<PathBuf>> {
    match path_mode {
        PathMode::Filemask(filemask) => {
            let (left, mask, right) = parse_filemask(filemask)
                .chain_err(|| ErrorKind::CouldNotParseFilemask(filemask.into()))?;

            let mut paths = vec![];
            let width = if mask.zero_padded { mask.digits } else { 0 };
            for i in 0..10u32.pow(mask.digits as u32) {
                let filename = format!("{}{:0width$}{}", left, i, right, width = width);
                let buf: PathBuf = filename.into();

                if !buf.exists() {
                    if !paths.is_empty() {
                        // If we already started, then let's just end (i.e. we want the first actual
                        // sequence of files).
                        break;
                    }
                    // Otherwise do nothing
                } else {
                    paths.push(buf);
                }
            }

            if paths.is_empty() {
                bail!(ErrorKind::NoFilesFound);
            }

            Ok(paths)
        }
        PathMode::Folder(_folder) => {
            // TODO
            bail!(ErrorKind::Unimplemented)
        },
    }
}

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

    use ::errors::*;

    #[test]
    fn test_parse_filemask() {
        let input1 = "foo%03d.png";
        let input2 = "foo%5d.jpg";
        let input3 = "foo.png";
        let input4 = "foo%02dbar%4d.png";

        let expected1 = ("foo".into(),
                         FileMask {
            zero_padded: true,
            digits: 3,
        },
                         ".png".into());

        let expected2 = ("foo".into(),
                         FileMask {
            zero_padded: false,
            digits: 5,
        },
                         ".jpg".into());

        assert_eq!(expected1, parse_filemask(input1).unwrap());
        assert_eq!(expected2, parse_filemask(input2).unwrap());
        match parse_filemask(input3) {
            Err(Error(ErrorKind::NoFileMaskFound, _)) => (),
            Err(e) => {
                assert!(false,
                        "expected `{}`, got `{}` instead.",
                        ErrorKind::NoFileMaskFound.description(),
                        e.description())
            }
            Ok(result) => {
                assert!(false,
                        "expected no file mask found error, but parsing succeeded with {:?}.",
                        result)
            }
        }
        match parse_filemask(input4) {
            Err(Error(ErrorKind::MultipleFileMasks, _)) => (),
            Err(Error(e, _)) => {
                assert!(false,
                        "expected `{}`, got `{}` instead.",
                        ErrorKind::MultipleFileMasks.description(),
                        e.description())
            }
            Ok(result) => {
                assert!(false,
                        "expected no file mask found error, but parsing succeeded with {:?}.",
                        result)
            }
        }
    }
}
<|endoftext|>


<commit_before>use super::Hash256;

#[derive(Debug, Clone, PartialEq)]
pub struct AttestationData {
    pub slot: u64,
    pub shard: u64,
    pub beacon_block_hash: Hash256,
    pub epoch_boundary_hash: Hash256,
    pub shard_block_hash: Hash256,
    pub latest_crosslink_hash: Hash256,
    pub justified_slot: u64,
    pub justified_block_hash: Hash256,
}
<commit_msg>Add ssz encode/decode for AttestationData<commit_after>use super::ssz::{Decodable, DecodeError, Encodable, SszStream};
use super::Hash256;

#[derive(Debug, Clone, PartialEq)]
pub struct AttestationData {
    pub slot: u64,
    pub shard: u64,
    pub beacon_block_hash: Hash256,
    pub epoch_boundary_hash: Hash256,
    pub shard_block_hash: Hash256,
    pub latest_crosslink_hash: Hash256,
    pub justified_slot: u64,
    pub justified_block_hash: Hash256,
}

impl Encodable for AttestationData {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append(&self.slot);
        s.append(&self.shard);
        s.append(&self.beacon_block_hash);
        s.append(&self.epoch_boundary_hash);
        s.append(&self.shard_block_hash);
        s.append(&self.latest_crosslink_hash);
        s.append(&self.justified_slot);
        s.append(&self.justified_block_hash);
    }
}

impl Decodable for AttestationData {
    fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
        let (slot, i) = u64::ssz_decode(bytes, i)?;
        let (shard, i) = u64::ssz_decode(bytes, i)?;
        let (beacon_block_hash, i) = Hash256::ssz_decode(bytes, i)?;
        let (epoch_boundary_hash, i) = Hash256::ssz_decode(bytes, i)?;
        let (shard_block_hash, i) = Hash256::ssz_decode(bytes, i)?;
        let (latest_crosslink_hash, i) = Hash256::ssz_decode(bytes, i)?;
        let (justified_slot, i) = u64::ssz_decode(bytes, i)?;
        let (justified_block_hash, i) = Hash256::ssz_decode(bytes, i)?;

        let attestation_data = AttestationData {
            slot,
            shard,
            beacon_block_hash,
            epoch_boundary_hash,
            shard_block_hash,
            latest_crosslink_hash,
            justified_slot,
            justified_block_hash,
        };
        Ok((attestation_data, i))
    }
}

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

    #[test]
    pub fn test_attestation_record_ssz_round_trip() {
        let original = AttestationData {
            slot: 42,
            shard: 16,
            beacon_block_hash: Hash256::from("beacon".as_bytes()),
            epoch_boundary_hash: Hash256::from("epoch".as_bytes()),
            shard_block_hash: Hash256::from("shard".as_bytes()),
            latest_crosslink_hash: Hash256::from("xlink".as_bytes()),
            justified_slot: 8,
            justified_block_hash: Hash256::from("justified".as_bytes()),
        };

        let ssz = ssz_encode(&original);

        let (decoded, _) = AttestationData::ssz_decode(&ssz, 0).unwrap();

        assert_eq!(original, decoded);
    }
}
<|endoftext|>


<commit_before>// Note: More specifically this lint is largely inspired (aka copied) from
// *rustc*'s
// [`missing_doc`].
//
// [`missing_doc`]: https://github.com/rust-lang/rust/blob/cf9cf7c923eb01146971429044f216a3ca905e06/compiler/rustc_lint/src/builtin.rs#L415
//

use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::sym;

declare_clippy_lint! {
    /// **What it does:** Warns if there is missing doc for any documentable item
    /// (public or private).
    ///
    /// **Why is this bad?** Doc is good. *rustc* has a `MISSING_DOCS`
    /// allowed-by-default lint for
    /// public members, but has no way to enforce documentation of private items.
    /// This lint fixes that.
    ///
    /// **Known problems:** None.
    pub MISSING_DOCS_IN_PRIVATE_ITEMS,
    restriction,
    "detects missing documentation for public and private members"
}

pub struct MissingDoc {
    /// Stack of whether #[doc(hidden)] is set
    /// at each level which has lint attributes.
    doc_hidden_stack: Vec<bool>,
}

impl Default for MissingDoc {
    #[must_use]
    fn default() -> Self {
        Self::new()
    }
}

impl MissingDoc {
    #[must_use]
    pub fn new() -> Self {
        Self {
            doc_hidden_stack: vec![false],
        }
    }

    fn doc_hidden(&self) -> bool {
        *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
    }

    fn check_missing_docs_attrs(
        &self,
        cx: &LateContext<'_>,
        attrs: &[ast::Attribute],
        sp: Span,
        article: &'static str,
        desc: &'static str,
    ) {
        // If we're building a test harness, then warning about
        // documentation is probably not really relevant right now.
        if cx.sess().opts.test {
            return;
        }

        // `#[doc(hidden)]` disables missing_docs check.
        if self.doc_hidden() {
            return;
        }

        if sp.from_expansion() {
            return;
        }

        let has_doc = attrs
            .iter()
            .any(|a| a.doc_str().is_some());
        if !has_doc {
            span_lint(
                cx,
                MISSING_DOCS_IN_PRIVATE_ITEMS,
                sp,
                &format!("missing documentation for {} {}", article, desc),
            );
        }
    }
}

impl_lint_pass!(MissingDoc => [MISSING_DOCS_IN_PRIVATE_ITEMS]);

impl<'tcx> LateLintPass<'tcx> for MissingDoc {
    fn enter_lint_attrs(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [ast::Attribute]) {
        let doc_hidden = self.doc_hidden() || is_doc_hidden(attrs);
        self.doc_hidden_stack.push(doc_hidden);
    }

    fn exit_lint_attrs(&mut self, _: &LateContext<'tcx>, _: &'tcx [ast::Attribute]) {
        self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
    }

    fn check_crate(&mut self, cx: &LateContext<'tcx>, krate: &'tcx hir::Crate<'_>) {
        let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
        self.check_missing_docs_attrs(cx, attrs, krate.item.inner, "the", "crate");
    }

    fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
        match it.kind {
            hir::ItemKind::Fn(..) => {
                // ignore main()
                if it.ident.name == sym::main {
                    let def_key = cx.tcx.hir().def_key(it.def_id);
                    if def_key.parent == Some(hir::def_id::CRATE_DEF_INDEX) {
                        return;
                    }
                }
            },
            hir::ItemKind::Const(..)
            | hir::ItemKind::Enum(..)
            | hir::ItemKind::Mod(..)
            | hir::ItemKind::Static(..)
            | hir::ItemKind::Struct(..)
            | hir::ItemKind::Trait(..)
            | hir::ItemKind::TraitAlias(..)
            | hir::ItemKind::TyAlias(..)
            | hir::ItemKind::Union(..)
            | hir::ItemKind::OpaqueTy(..) => {},
            hir::ItemKind::ExternCrate(..)
            | hir::ItemKind::ForeignMod { .. }
            | hir::ItemKind::GlobalAsm(..)
            | hir::ItemKind::Impl { .. }
            | hir::ItemKind::Use(..) => return,
        };

        let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());

        let attrs = cx.tcx.hir().attrs(it.hir_id());
        self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
    }

    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) {
        let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());

        let attrs = cx.tcx.hir().attrs(trait_item.hir_id());
        self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
    }

    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
        // If the method is an impl for a trait, don't doc.
        match cx.tcx.associated_item(impl_item.def_id).container {
            ty::TraitContainer(_) => return,
            ty::ImplContainer(cid) => {
                if cx.tcx.impl_trait_ref(cid).is_some() {
                    return;
                }
            },
        }

        let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
        let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
        self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
    }

    fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) {
        if !sf.is_positional() {
            let attrs = cx.tcx.hir().attrs(sf.hir_id);
            self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
        }
    }

    fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
        let attrs = cx.tcx.hir().attrs(v.id);
        self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
    }
}
<commit_msg>Auto merge of #83723 - cjgillot:ownernode, r=petrochenkov<commit_after>// Note: More specifically this lint is largely inspired (aka copied) from
// *rustc*'s
// [`missing_doc`].
//
// [`missing_doc`]: https://github.com/rust-lang/rust/blob/cf9cf7c923eb01146971429044f216a3ca905e06/compiler/rustc_lint/src/builtin.rs#L415
//

use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::sym;

declare_clippy_lint! {
    /// **What it does:** Warns if there is missing doc for any documentable item
    /// (public or private).
    ///
    /// **Why is this bad?** Doc is good. *rustc* has a `MISSING_DOCS`
    /// allowed-by-default lint for
    /// public members, but has no way to enforce documentation of private items.
    /// This lint fixes that.
    ///
    /// **Known problems:** None.
    pub MISSING_DOCS_IN_PRIVATE_ITEMS,
    restriction,
    "detects missing documentation for public and private members"
}

pub struct MissingDoc {
    /// Stack of whether #[doc(hidden)] is set
    /// at each level which has lint attributes.
    doc_hidden_stack: Vec<bool>,
}

impl Default for MissingDoc {
    #[must_use]
    fn default() -> Self {
        Self::new()
    }
}

impl MissingDoc {
    #[must_use]
    pub fn new() -> Self {
        Self {
            doc_hidden_stack: vec![false],
        }
    }

    fn doc_hidden(&self) -> bool {
        *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
    }

    fn check_missing_docs_attrs(
        &self,
        cx: &LateContext<'_>,
        attrs: &[ast::Attribute],
        sp: Span,
        article: &'static str,
        desc: &'static str,
    ) {
        // If we're building a test harness, then warning about
        // documentation is probably not really relevant right now.
        if cx.sess().opts.test {
            return;
        }

        // `#[doc(hidden)]` disables missing_docs check.
        if self.doc_hidden() {
            return;
        }

        if sp.from_expansion() {
            return;
        }

        let has_doc = attrs
            .iter()
            .any(|a| a.doc_str().is_some());
        if !has_doc {
            span_lint(
                cx,
                MISSING_DOCS_IN_PRIVATE_ITEMS,
                sp,
                &format!("missing documentation for {} {}", article, desc),
            );
        }
    }
}

impl_lint_pass!(MissingDoc => [MISSING_DOCS_IN_PRIVATE_ITEMS]);

impl<'tcx> LateLintPass<'tcx> for MissingDoc {
    fn enter_lint_attrs(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [ast::Attribute]) {
        let doc_hidden = self.doc_hidden() || is_doc_hidden(attrs);
        self.doc_hidden_stack.push(doc_hidden);
    }

    fn exit_lint_attrs(&mut self, _: &LateContext<'tcx>, _: &'tcx [ast::Attribute]) {
        self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
    }

    fn check_crate(&mut self, cx: &LateContext<'tcx>, krate: &'tcx hir::Crate<'_>) {
        let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID);
        self.check_missing_docs_attrs(cx, attrs, krate.module().inner, "the", "crate");
    }

    fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'_>) {
        match it.kind {
            hir::ItemKind::Fn(..) => {
                // ignore main()
                if it.ident.name == sym::main {
                    let def_key = cx.tcx.hir().def_key(it.def_id);
                    if def_key.parent == Some(hir::def_id::CRATE_DEF_INDEX) {
                        return;
                    }
                }
            },
            hir::ItemKind::Const(..)
            | hir::ItemKind::Enum(..)
            | hir::ItemKind::Mod(..)
            | hir::ItemKind::Static(..)
            | hir::ItemKind::Struct(..)
            | hir::ItemKind::Trait(..)
            | hir::ItemKind::TraitAlias(..)
            | hir::ItemKind::TyAlias(..)
            | hir::ItemKind::Union(..)
            | hir::ItemKind::OpaqueTy(..) => {},
            hir::ItemKind::ExternCrate(..)
            | hir::ItemKind::ForeignMod { .. }
            | hir::ItemKind::GlobalAsm(..)
            | hir::ItemKind::Impl { .. }
            | hir::ItemKind::Use(..) => return,
        };

        let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());

        let attrs = cx.tcx.hir().attrs(it.hir_id());
        self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
    }

    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) {
        let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());

        let attrs = cx.tcx.hir().attrs(trait_item.hir_id());
        self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
    }

    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
        // If the method is an impl for a trait, don't doc.
        match cx.tcx.associated_item(impl_item.def_id).container {
            ty::TraitContainer(_) => return,
            ty::ImplContainer(cid) => {
                if cx.tcx.impl_trait_ref(cid).is_some() {
                    return;
                }
            },
        }

        let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
        let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
        self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
    }

    fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) {
        if !sf.is_positional() {
            let attrs = cx.tcx.hir().attrs(sf.hir_id);
            self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
        }
    }

    fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
        let attrs = cx.tcx.hir().attrs(v.id);
        self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
    }
}
<|endoftext|>


<commit_before>extern crate env_logger;
#[macro_use]
extern crate gluon_codegen;
extern crate gluon;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate gluon_vm;

mod init;

use gluon::{
    vm::{
        self,
        api::{
            self,
            generic::{self, L, R},
            OpaqueValue,
        },
        ExternModule,
    },
    {import, Compiler, RootedThread, Thread},
};
use init::new_vm;

#[derive(Getable, VmType, Debug, Serialize, Deserialize)]
#[gluon(vm_type = "types.TupleEnum")]
enum TupleEnum {
    Variant,
    OtherVariant,
    One(u32),
    LotsOfTupleThings(i32, String, f64),
}

fn load_tuple_enum_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        tuple_enum_to_str => primitive!(1, tuple_enum_to_str),
    };

    ExternModule::new(vm, module)
}

fn tuple_enum_to_str(val: TupleEnum) -> String {
    format!("{:?}", val)
}

#[test]
fn enum_tuple_variants() {
    let vm = new_vm();
    let mut compiler = Compiler::new();

    let src = api::typ::make_source::<TupleEnum>(&vm).unwrap();
    compiler.load_script(&vm, "types", &src).unwrap();
    import::add_extern_module(&vm, "functions", load_tuple_enum_mod);

    let script = r#"
        let { TupleEnum } = import! types
        let { tuple_enum_to_str } = import! functions
        let { assert } = import! std.test

        assert (tuple_enum_to_str Variant == "Variant")
        assert (tuple_enum_to_str OtherVariant == "OtherVariant")
        assert (tuple_enum_to_str (One 1) == "One(1)")
        assert (tuple_enum_to_str (LotsOfTupleThings 42 "Text" 0.0) == "LotsOfTupleThings(42, \"Text\", 0.0)")
    "#;

    if let Err(why) = compiler.run_expr::<()>(&vm, "test", script) {
        panic!("{}", why);
    }
}

#[derive(Getable, VmType, Debug, Serialize, Deserialize)]
#[gluon(vm_type = "types.StructEnum")]
enum StructEnum {
    OneField { field: i32 },
    TwoFields { name: String, val: f64 },
}

fn load_struct_enum_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        struct_enum_to_str => primitive!(1, struct_enum_to_str),
    };

    ExternModule::new(vm, module)
}

fn struct_enum_to_str(val: StructEnum) -> String {
    format!("{:?}", val)
}

#[test]
fn enum_struct_variants() {
    let vm = new_vm();
    let mut compiler = Compiler::new();

    let src = api::typ::make_source::<StructEnum>(&vm).unwrap();
    compiler.load_script(&vm, "types", &src).unwrap();
    import::add_extern_module(&vm, "functions", load_struct_enum_mod);

    let script = r#"
        let { StructEnum } = import! types
        let { struct_enum_to_str } = import! functions
        let { assert } = import! std.test

        assert (struct_enum_to_str (OneField 1337) == "OneField { field: 1337 }")
        assert (struct_enum_to_str (TwoFields "Pi" 3.14) == "TwoFields { name: \"Pi\", val: 3.14 }")
    "#;

    if let Err(why) = compiler.run_expr::<()>(&vm, "test", script) {
        panic!("{}", why);
    }
}

#[derive(Getable, VmType)]
enum Either<L, R> {
    Left(L),
    Right(R),
}

fn load_either_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        type Either l r => Either<L, R>,
        left => primitive!(1, left),
        extract_str => primitive!(1, extract_str),
    };

    ExternModule::new(vm, module)
}

type GenericL = OpaqueValue<RootedThread, generic::L>;
type GenericR = OpaqueValue<RootedThread, generic::R>;

fn left(either: Either<GenericL, GenericR>) -> Option<GenericL> {
    match either {
        Either::Left(left) => Some(left),
        _ => None,
    }
}

fn extract_str(either: Either<String, String>) -> String {
    match either {
        Either::Left(string) => string,
        Either::Right(string) => string,
    }
}

#[test]
fn enum_generic_variants() {
    let _ = env_logger::try_init();

    let vm = new_vm();
    let mut compiler = Compiler::new();

    import::add_extern_module(&vm, "functions", load_either_mod);

    let script = r#"
        let { Either, left, extract_str } = import! functions
        let { assert } = import! std.test

        assert (left (Left 42) == Some 42)
        assert (left (Right 0.0) == None)

        assert (extract_str (Left "left") == "left")
        assert (extract_str (Right "right") == "right")
    "#;

    if let Err(why) = compiler.run_expr::<()>(&vm, "test", script) {
        panic!("{}", why);
    }
}

#[derive(Getable)]
struct LifetimeStruct<'a> {
    _str: &'a str,
}

// TODO: impl tests for lifetimes, this requires
// a safe interface for Getable::from_value()

#[derive(Getable, VmType, Debug, Serialize, Deserialize)]
#[gluon(vm_type = "types.Struct")]
struct Struct {
    string: String,
    int: i32,
    tuple: (f64, f64),
}

fn load_struct_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        struct_to_str => primitive!(1, struct_to_str),
    };

    ExternModule::new(vm, module)
}

fn struct_to_str(val: Struct) -> String {
    format!("{:?}", val)
}

#[test]
fn struct_derive() {
    let vm = new_vm();
    let mut compiler = Compiler::new();

    let src = api::typ::make_source::<Struct>(&vm).unwrap();
    compiler.load_script(&vm, "types", &src).unwrap();
    import::add_extern_module(&vm, "functions", load_struct_mod);

    let script = r#"
        let { Struct } = import! types
        let { struct_to_str } = import! functions
        let { assert } = import! std.test

        assert (struct_to_str { string = "test", int = 55, tuple = (0.0, 1.0) } == "Struct { string: \"test\", int: 55, tuple: (0.0, 1.0) }")
    "#;

    if let Err(why) = compiler.run_expr::<()>(&vm, "test", script) {
        panic!("{}", why);
    }
}

#[derive(Serialize, Deserialize, Debug, VmType, Getable)]
#[gluon(vm_type = "types.TupleStruct")]
struct TupleStruct(i32, i32);

fn load_tuple_struct_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        tuple_struct_to_str => primitive!(1, tuple_struct_to_str),
    };

    ExternModule::new(vm, module)
}

fn tuple_struct_to_str(val: TupleStruct) -> String {
    format!("{:?}", val)
}

#[test]
fn tuple_struct_derive() {
    let vm = new_vm();
    let mut compiler = Compiler::new();

    let src = r#"
        type TupleStruct = (Int, Int)
        { TupleStruct }
    "#;

    compiler.load_script(&vm, "types", &src).unwrap();
    import::add_extern_module(&vm, "functions", load_tuple_struct_mod);

    let script = r#"
        let { TupleStruct } = import! types
        let { tuple_struct_to_str } = import! functions
        let { assert } = import! std.test

        assert (tuple_struct_to_str (1, 2) == "TupleStruct(1, 2)")
    "#;

    if let Err(why) = compiler.run_expr::<()>(&vm, "test", script) {
        panic!("{}", why);
    }
}
<commit_msg>test: Check derives for VmType on enum's<commit_after>extern crate env_logger;
#[macro_use]
extern crate gluon_codegen;
extern crate gluon;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate gluon_vm;

mod init;

use gluon::{
    vm::{
        self,
        api::{
            self,
            generic::{self, L, R},
            OpaqueValue,
        },
        ExternModule,
    },
    {import, Compiler, RootedThread, Thread},
};
use init::new_vm;

#[derive(Getable, VmType, Debug, Serialize, Deserialize)]
#[gluon(vm_type = "types.TupleEnum")]
enum TupleEnum {
    Variant,
    OtherVariant,
    One(u32),
    LotsOfTupleThings(i32, String, f64),
}

fn load_tuple_enum_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        tuple_enum_to_str => primitive!(1, tuple_enum_to_str),
    };

    ExternModule::new(vm, module)
}

fn tuple_enum_to_str(val: TupleEnum) -> String {
    format!("{:?}", val)
}

#[test]
fn enum_tuple_variants() {
    let vm = new_vm();
    let mut compiler = Compiler::new();

    let src = api::typ::make_source::<TupleEnum>(&vm).unwrap();
    compiler.load_script(&vm, "types", &src).unwrap();
    import::add_extern_module(&vm, "functions", load_tuple_enum_mod);

    let script = r#"
        let { TupleEnum } = import! types
        let { tuple_enum_to_str } = import! functions
        let { assert } = import! std.test

        assert (tuple_enum_to_str Variant == "Variant")
        assert (tuple_enum_to_str OtherVariant == "OtherVariant")
        assert (tuple_enum_to_str (One 1) == "One(1)")
        assert (tuple_enum_to_str (LotsOfTupleThings 42 "Text" 0.0) == "LotsOfTupleThings(42, \"Text\", 0.0)")
    "#;

    if let Err(why) = compiler.run_expr::<()>(&vm, "test", script) {
        panic!("{}", why);
    }
}

#[derive(Getable, VmType, Debug, Serialize, Deserialize)]
#[gluon(vm_type = "types.StructEnum")]
enum StructEnum {
    OneField { field: i32 },
    TwoFields { name: String, val: f64 },
}

fn load_struct_enum_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        struct_enum_to_str => primitive!(1, struct_enum_to_str),
    };

    ExternModule::new(vm, module)
}

fn struct_enum_to_str(val: StructEnum) -> String {
    format!("{:?}", val)
}

#[test]
fn enum_struct_variants() {
    let vm = new_vm();
    let mut compiler = Compiler::new();

    let src = api::typ::make_source::<StructEnum>(&vm).unwrap();
    compiler.load_script(&vm, "types", &src).unwrap();
    import::add_extern_module(&vm, "functions", load_struct_enum_mod);

    let script = r#"
        let { StructEnum } = import! types
        let { struct_enum_to_str } = import! functions
        let { assert } = import! std.test

        assert (struct_enum_to_str (OneField 1337) == "OneField { field: 1337 }")
        assert (struct_enum_to_str (TwoFields "Pi" 3.14) == "TwoFields { name: \"Pi\", val: 3.14 }")
    "#;

    if let Err(why) = compiler.run_expr::<()>(&vm, "test", script) {
        panic!("{}", why);
    }
}

#[derive(Getable, VmType)]
enum Either<L, R> {
    Left(L),
    Right(R),
}

fn load_either_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        type Either l r => Either<L, R>,
        left => primitive!(1, left),
        extract_str => primitive!(1, extract_str),
    };

    ExternModule::new(vm, module)
}

type GenericL = OpaqueValue<RootedThread, generic::L>;
type GenericR = OpaqueValue<RootedThread, generic::R>;

fn left(either: Either<GenericL, GenericR>) -> Option<GenericL> {
    match either {
        Either::Left(left) => Some(left),
        _ => None,
    }
}

fn extract_str(either: Either<String, String>) -> String {
    match either {
        Either::Left(string) => string,
        Either::Right(string) => string,
    }
}

#[test]
fn enum_generic_variants() {
    let _ = env_logger::try_init();

    let vm = new_vm();
    let mut compiler = Compiler::new();

    import::add_extern_module(&vm, "functions", load_either_mod);

    let script = r#"
        let { Either, left, extract_str } = import! functions
        let { assert } = import! std.test

        assert (left (Left 42) == Some 42)
        assert (left (Right 0.0) == None)

        assert (extract_str (Left "left") == "left")
        assert (extract_str (Right "right") == "right")
    "#;

    if let Err(why) = compiler.run_expr::<()>(&vm, "test", script) {
        panic!("{}", why);
    }
}

#[derive(Getable, Pushable, VmType)]
enum Enum {
    TestVariant,
    TestVariant2(i32),
}

#[test]
fn derive_generates_same_type_as_gluon_define() {
    let _ = env_logger::try_init();

    let vm = new_vm();
    let mut compiler = Compiler::new();

    import::add_extern_module(&vm, "test", |vm| {
        ExternModule::new(vm, primitive!(1, "test", |_: Enum| ()))
    });

    let script = r#"
        let test = import! test

        type Enum = | TestVariant | TestVariant2 Int

        test TestVariant
        test (TestVariant2 123)
    "#;

    if let Err(why) = compiler.run_expr::<()>(&vm, "test", script) {
        panic!("{}", why);
    }
}

#[derive(Getable)]
struct LifetimeStruct<'a> {
    _str: &'a str,
}

// TODO: impl tests for lifetimes, this requires
// a safe interface for Getable::from_value()

#[derive(Getable, VmType, Debug, Serialize, Deserialize)]
#[gluon(vm_type = "types.Struct")]
struct Struct {
    string: String,
    int: i32,
    tuple: (f64, f64),
}

fn load_struct_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        struct_to_str => primitive!(1, struct_to_str),
    };

    ExternModule::new(vm, module)
}

fn struct_to_str(val: Struct) -> String {
    format!("{:?}", val)
}

#[test]
fn struct_derive() {
    let vm = new_vm();
    let mut compiler = Compiler::new();

    let src = api::typ::make_source::<Struct>(&vm).unwrap();
    compiler.load_script(&vm, "types", &src).unwrap();
    import::add_extern_module(&vm, "functions", load_struct_mod);

    let script = r#"
        let { Struct } = import! types
        let { struct_to_str } = import! functions
        let { assert } = import! std.test

        assert (struct_to_str { string = "test", int = 55, tuple = (0.0, 1.0) } == "Struct { string: \"test\", int: 55, tuple: (0.0, 1.0) }")
    "#;

    if let Err(why) = compiler.run_expr::<()>(&vm, "test", script) {
        panic!("{}", why);
    }
}

#[derive(Serialize, Deserialize, Debug, VmType, Getable)]
#[gluon(vm_type = "types.TupleStruct")]
struct TupleStruct(i32, i32);

fn load_tuple_struct_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        tuple_struct_to_str => primitive!(1, tuple_struct_to_str),
    };

    ExternModule::new(vm, module)
}

fn tuple_struct_to_str(val: TupleStruct) -> String {
    format!("{:?}", val)
}

#[test]
fn tuple_struct_derive() {
    let vm = new_vm();
    let mut compiler = Compiler::new();

    let src = r#"
        type TupleStruct = (Int, Int)
        { TupleStruct }
    "#;

    compiler.load_script(&vm, "types", &src).unwrap();
    import::add_extern_module(&vm, "functions", load_tuple_struct_mod);

    let script = r#"
        let { TupleStruct } = import! types
        let { tuple_struct_to_str } = import! functions
        let { assert } = import! std.test

        assert (tuple_struct_to_str (1, 2) == "TupleStruct(1, 2)")
    "#;

    if let Err(why) = compiler.run_expr::<()>(&vm, "test", script) {
        panic!("{}", why);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use mirai_annotations::debug_checked_precondition;
use serde::{Serialize, Serializer};
use static_assertions::const_assert;
use std::{fmt, str};
use thiserror::Error;

/// An efficient container for formatting a byte slice as a hex-formatted string,
/// stored on the stack.
///
/// Using `ShortHexStr` instead of `hex::encode` is about 3-4x faster on a recent
/// MBP 2019 (~48 ns/iter vs ~170 ns/iter) in an artifical micro benchmark.
#[derive(Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
pub struct ShortHexStr([u8; ShortHexStr::LENGTH]);

#[derive(Error, Debug)]
pub enum Error {
    #[error("Input bytes are too short")]
    InputTooShortError,
    #[error("Overflow error: {0}")]
    OverflowError(String),
}

impl ShortHexStr {
    pub const SOURCE_LENGTH: usize = 4;
    pub const LENGTH: usize = 2 * ShortHexStr::SOURCE_LENGTH;

    /// Format a new `ShortHexStr` from a byte slice.
    ///
    /// Returns `Err(Error::InputTooShortError)` if the input byte slice length is less
    /// than `SOURCE_LENGTH` bytes.
    pub fn try_from_bytes(src_bytes: &[u8]) -> Result<ShortHexStr, Error> {
        if src_bytes.len() >= ShortHexStr::SOURCE_LENGTH {
            let src_short_bytes = &src_bytes[0..ShortHexStr::SOURCE_LENGTH];
            let mut dest_bytes = [0u8; ShortHexStr::LENGTH];

            // We include a tiny hex encode here instead of using the `hex` crate's
            // `encode_to_slice`, since the compiler seems unable to inline across
            // the crate boundary.
            hex_encode(&src_short_bytes, &mut dest_bytes)?;
            Ok(Self(dest_bytes))
        } else {
            Err(Error::InputTooShortError)
        }
    }

    pub fn as_str(&self) -> &str {
        // We could also do str::from_utf8_unchecked here to avoid the unnecessary
        // runtime check. Shaves ~6-7 ns/iter in a micro bench but the unsafe is
        // probably not worth the hassle.
        str::from_utf8(&self.0).expect(
            "This can never fail since &self.0 will only ever contain the \
             following characters: '0123456789abcdef', which are all valid \
             ASCII characters and therefore all valid UTF-8",
        )
    }
}

impl fmt::Debug for ShortHexStr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_str())
    }
}

impl fmt::Display for ShortHexStr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_str())
    }
}

impl Serialize for ShortHexStr {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(self.as_str())
    }
}

/// Maps a nibble to its corresponding hex-formatted ASCII character.
const HEX_CHARS_LOWER: &[u8; 16] = b"0123456789abcdef";

/// Format a byte as hex. Returns a tuple containing the first character and then
/// the second character as ASCII bytes.
#[inline(always)]
fn byte2hex(byte: u8) -> Result<(u8, u8), Error> {
    let hi = HEX_CHARS_LOWER[(byte
        .checked_shr(4)
        .ok_or_else(|| Error::OverflowError("byte2hex::byte".into()))?
        & 0x0f) as usize];
    let lo = HEX_CHARS_LOWER[(byte & 0x0f) as usize];
    Ok((hi, lo))
}

/// Hex encode a byte slice into the destination byte slice.
#[inline(always)]
fn hex_encode(src: &[u8], dst: &mut [u8]) -> Result<(), Error> {
    let expected_length = src
        .len()
        .checked_mul(2)
        .ok_or_else(|| Error::OverflowError("hex_encode::src".into()))?;
    debug_checked_precondition!(dst.len() == expected_length);

    for (byte, out) in src.iter().zip(dst.chunks_mut(2)) {
        let (hi, lo) = byte2hex(*byte)?;
        out[0] = hi;
        out[1] = lo;
    }
    Ok(())
}

pub trait AsShortHexStr {
    fn short_str(&self) -> ShortHexStr;
}

impl AsShortHexStr for [u8; 16] {
    fn short_str(&self) -> ShortHexStr {
        const_assert!(16 >= ShortHexStr::SOURCE_LENGTH);
        ShortHexStr::try_from_bytes(self)
            .expect("This can never fail since 16 >= ShortHexStr::SOURCE_LENGTH")
    }
}

impl AsShortHexStr for [u8; 32] {
    fn short_str(&self) -> ShortHexStr {
        const_assert!(32 >= ShortHexStr::SOURCE_LENGTH);
        ShortHexStr::try_from_bytes(self)
            .expect("This can never fail since 32 >= ShortHexStr::SOURCE_LENGTH")
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use proptest::prelude::*;
    use std::{str, u8};

    #[test]
    fn test_hex_encode() {
        let src = [0x12_u8, 0x34, 0xfe, 0xba];
        let mut actual = [0u8; 8];
        hex_encode(&src, &mut actual).unwrap();
        let expected = b"1234feba";
        assert_eq!(&actual, expected);
    }

    #[test]
    fn test_byte2hex_equivalence() {
        for byte in 0..=u8::MAX {
            let (hi, lo) = byte2hex(byte).unwrap();
            let formatted_bytes = [hi, lo];
            let actual = str::from_utf8(&formatted_bytes[..]).unwrap();
            let expected = hex::encode(&[byte][..]);
            assert_eq!(actual, expected.as_str());
        }
    }

    proptest! {
        #[test]
        fn test_address_short_str_equivalence(addr in any::<[u8; 16]>()) {
            let short_str_old = hex::encode(&addr[0..ShortHexStr::SOURCE_LENGTH]);
            let short_str_new = ShortHexStr::try_from_bytes(&addr).unwrap();
            prop_assert_eq!(short_str_old.as_str(), short_str_new.as_str());
        }
    }
}
<commit_msg>[short-hex-str] revert: Fix Unchecked Arithmetic in Diem-Core<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use mirai_annotations::debug_checked_precondition;
use serde::{Serialize, Serializer};
use static_assertions::const_assert;
use std::{fmt, str};
use thiserror::Error;

/// An efficient container for formatting a byte slice as a hex-formatted string,
/// stored on the stack.
///
/// Using `ShortHexStr` instead of `hex::encode` is about 3-4x faster on a recent
/// MBP 2019 (~48 ns/iter vs ~170 ns/iter) in an artifical micro benchmark.
#[derive(Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
pub struct ShortHexStr([u8; ShortHexStr::LENGTH]);

#[derive(Error, Debug)]
#[error("Input bytes are too short")]
pub struct InputTooShortError;

impl ShortHexStr {
    pub const SOURCE_LENGTH: usize = 4;
    pub const LENGTH: usize = 2 * ShortHexStr::SOURCE_LENGTH;

    /// Format a new `ShortHexStr` from a byte slice.
    ///
    /// Returns `Err(InputTooShortError)` if the input byte slice length is less
    /// than `SOURCE_LENGTH` bytes.
    pub fn try_from_bytes(src_bytes: &[u8]) -> Result<ShortHexStr, InputTooShortError> {
        if src_bytes.len() >= ShortHexStr::SOURCE_LENGTH {
            let src_short_bytes = &src_bytes[0..ShortHexStr::SOURCE_LENGTH];
            let mut dest_bytes = [0u8; ShortHexStr::LENGTH];

            // We include a tiny hex encode here instead of using the `hex` crate's
            // `encode_to_slice`, since the compiler seems unable to inline across
            // the crate boundary.
            hex_encode(&src_short_bytes, &mut dest_bytes);
            Ok(Self(dest_bytes))
        } else {
            Err(InputTooShortError)
        }
    }

    pub fn as_str(&self) -> &str {
        // We could also do str::from_utf8_unchecked here to avoid the unnecessary
        // runtime check. Shaves ~6-7 ns/iter in a micro bench but the unsafe is
        // probably not worth the hassle.
        str::from_utf8(&self.0).expect(
            "This can never fail since &self.0 will only ever contain the \
             following characters: '0123456789abcdef', which are all valid \
             ASCII characters and therefore all valid UTF-8",
        )
    }
}

impl fmt::Debug for ShortHexStr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_str())
    }
}

impl fmt::Display for ShortHexStr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_str())
    }
}

impl Serialize for ShortHexStr {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(self.as_str())
    }
}

/// Maps a nibble to its corresponding hex-formatted ASCII character.
const HEX_CHARS_LOWER: &[u8; 16] = b"0123456789abcdef";

/// Format a byte as hex. Returns a tuple containing the first character and then
/// the second character as ASCII bytes.
#[inline(always)]
fn byte2hex(byte: u8) -> (u8, u8) {
    let hi = HEX_CHARS_LOWER[((byte >> 4) & 0x0f) as usize];
    let lo = HEX_CHARS_LOWER[(byte & 0x0f) as usize];
    (hi, lo)
}

/// Hex encode a byte slice into the destination byte slice.
#[inline(always)]
fn hex_encode(src: &[u8], dst: &mut [u8]) {
    debug_checked_precondition!(dst.len() == 2 * src.len());

    for (byte, out) in src.iter().zip(dst.chunks_mut(2)) {
        let (hi, lo) = byte2hex(*byte);
        out[0] = hi;
        out[1] = lo;
    }
}

pub trait AsShortHexStr {
    fn short_str(&self) -> ShortHexStr;
}

impl AsShortHexStr for [u8; 16] {
    fn short_str(&self) -> ShortHexStr {
        const_assert!(16 >= ShortHexStr::SOURCE_LENGTH);
        ShortHexStr::try_from_bytes(self)
            .expect("This can never fail since 16 >= ShortHexStr::SOURCE_LENGTH")
    }
}

impl AsShortHexStr for [u8; 32] {
    fn short_str(&self) -> ShortHexStr {
        const_assert!(32 >= ShortHexStr::SOURCE_LENGTH);
        ShortHexStr::try_from_bytes(self)
            .expect("This can never fail since 32 >= ShortHexStr::SOURCE_LENGTH")
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use proptest::prelude::*;
    use std::{str, u8};

    #[test]
    fn test_hex_encode() {
        let src = [0x12_u8, 0x34, 0xfe, 0xba];
        let mut actual = [0u8; 8];
        hex_encode(&src, &mut actual);
        let expected = b"1234feba";
        assert_eq!(&actual, expected);
    }

    #[test]
    fn test_byte2hex_equivalence() {
        for byte in 0..=u8::MAX {
            let (hi, lo) = byte2hex(byte);
            let formatted_bytes = [hi, lo];
            let actual = str::from_utf8(&formatted_bytes[..]).unwrap();
            let expected = hex::encode(&[byte][..]);
            assert_eq!(actual, expected.as_str());
        }
    }

    proptest! {
        #[test]
        fn test_address_short_str_equivalence(addr in any::<[u8; 16]>()) {
            let short_str_old = hex::encode(&addr[0..ShortHexStr::SOURCE_LENGTH]);
            let short_str_new = ShortHexStr::try_from_bytes(&addr).unwrap();
            prop_assert_eq!(short_str_old.as_str(), short_str_new.as_str());
        }
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::cell::RefCell;
use std::cmp;
use std::collections::HashMap;

use rand;
use rand::Rng;
use itertools::Itertools;
use ndarray::prelude::*;
use ndarray;
use bit_vec::BitVec;
use rgsl::randist::multinomial::multinomial_pdf;
use ordered_float::NotNaN;

use bio::stats::{Prob, LogProb};

use io::codebook::{self, Codebook, Codeword, FeatureID};

use model::readout::{Expressions, Counts, Miscalls, FeatureModel, NoiseModel, Xi};
use model::readout::feature_model::AbstractFeatureModel;

pub struct JointModel {
    feature_models: HashMap<FeatureID, FeatureModel>,
    noise_model: NoiseModel,
    expressions: Expressions,
    miscalls_exact: Miscalls,
    miscalls_mismatch: Miscalls,
    margin: u32,
    em_run: bool,
    rng: rand::StdRng,
    debug_id: Option<FeatureID>,
    noise_id: FeatureID
}

impl JointModel {
    pub fn new<'a, I: Iterator<Item=(&'a String, &'a Counts)>>(
        counts: I,
        p0: &[Prob],
        p1: &[Prob],
        codebook: &Codebook,
        window_width: u32) -> Self {
        let mut xi = Xi::new(p0, p1);
        let mut rng = rand::StdRng::new().unwrap();

        // Generate feature models and info about not expressed features.
        let mut feature_models = HashMap::new();
        let mut not_expressed_counts = Vec::new();
        let mut not_expressed_feature_ids = Vec::new();
        for (feature, counts) in counts {
            let feature = codebook.get_id(feature);
            let rec = codebook.record(feature);
            if rec.expressed() {
                feature_models.insert(
                    feature, FeatureModel::new(feature, counts.clone(), codebook, &xi)
                );
            } else {
                not_expressed_counts.push(counts.clone());
                not_expressed_feature_ids.push(feature);
            }
        }

        // Take value larger than maximum feature id as noise id.
        let noise_id = codebook.len();
        let noise_model = NoiseModel::new(
            codebook.len(), not_expressed_feature_ids, not_expressed_counts, codebook, &xi
        );
        let feature_count = codebook.len() + 1;

        // calculate start values (we take random numbers as start expression)
        let mut expressions = Array1::from_iter((0..feature_count).map(
            |model| rng.next_u32()
        ));

        let miscalls_exact = Miscalls::new(feature_count, &feature_models, &noise_model, true);
        let miscalls_mismatch = Miscalls::new(feature_count, &feature_models, &noise_model, false);

        JointModel {
            feature_models: feature_models,
            noise_model: noise_model,
            expressions: expressions,
            miscalls_exact: miscalls_exact,
            miscalls_mismatch: miscalls_mismatch,
            margin: window_width / 2,
            em_run: false,
            rng: rng,
            debug_id: None, //codebook.get_id("THBS1")
            noise_id: noise_id
        }
    }

    /// Jointly estimate MAP using the EM algorithm.
    ///
    /// Expressions are our model parameters to estimate, miscalls are our latent variables,
    /// counts are our observed variables.
    pub fn expectation_maximization(&mut self) {
        let mut feature_models: Vec<Box<&AbstractFeatureModel>> =
            self.feature_models.values().map(|m| Box::new(m as &AbstractFeatureModel)).collect_vec();
        feature_models.push(Box::new(&self.noise_model));
        let n_iterations = 100;

        let mut last_changes = Array2::from_elem((self.expressions.len(), 5), 0.0);

        // EM iterations
        for i in 1..n_iterations + 1 {
            debug!("EM-iteration {} of at most {}", i, n_iterations);

            // E-step: estimate miscalls
            debug!("E-step");

            // Shuffle models, such that miscalls can be drawn unbiased
            // this is necessary because there is a maximum miscall count for each feature.
            // If we would not shuffle, it would be easier for the first model to provide miscalls.
            self.rng.shuffle(&mut feature_models);
            for m in &feature_models {
                m.mle_miscalls(
                    &self.expressions,
                    &mut self.miscalls_exact,
                    &mut self.miscalls_mismatch,
                    &mut self.rng
                );
            }

            // M-step: estimate expressions that maximize the probability
            debug!("M-step");
            for m in &feature_models {
                let feature_id = m.feature_id();
                last_changes[(feature_id, feature_id % 5)] = m.mle_expression(
                    &mut self.expressions,
                    &self.miscalls_exact,
                    &self.miscalls_mismatch
                ) as f64;
            }

            // calculate mean change per feature of last 5 steps
            let mean_changes = last_changes.mean(Axis(1));
            debug!("x={:?}", self.expressions);
            debug!("mean changes={:?}", mean_changes);
            let convergence = *mean_changes.iter().map(
                |&c| NotNaN::new(c.abs()).unwrap()
            ).max().unwrap() <= 1.0;

            if i >= 5 && convergence {
                debug!("Convergence reached, stopping EM algorithm.");
                break;
            }
        }
        self.em_run = true;
    }

    pub fn likelihood(&mut self, feature_id: FeatureID, x: u32) -> LogProb {
        assert!(self.em_run);
        self.feature_model(feature_id).likelihood(
            x, &self.miscalls_exact, &self.miscalls_mismatch
        )
    }

    pub fn map_estimate(&self, feature_id: FeatureID) -> u32 {
        assert!(self.em_run);
        self.expressions[feature_id as usize]
    }

    fn feature_model(&self, feature_id: FeatureID) -> &FeatureModel {
        self.feature_models.get(&feature_id).unwrap()
    }

    /// Prior window for calculating expression PMF
    pub fn window(&self, feature_id: FeatureID) -> (u32, u32) {
        assert!(self.em_run);
        let x = self.map_estimate(feature_id);
        let xmin = self.feature_model(feature_id).min_expression(
            &self.miscalls_exact, &self.miscalls_mismatch
        );
        let xmax = x + self.margin;
        assert!(xmax >= xmin, "xmax has to be greater than xmin: xmin={}, xmax={}", xmin, xmax);
        (xmin, xmax)
    }
}
<commit_msg>More reasonable start values.<commit_after>use std::mem;
use std::cell::RefCell;
use std::cmp;
use std::collections::HashMap;

use rand;
use rand::Rng;
use rand::distributions::IndependentSample;
use itertools::Itertools;
use ndarray::prelude::*;
use ndarray;
use bit_vec::BitVec;
use rgsl::randist::multinomial::multinomial_pdf;
use ordered_float::NotNaN;

use bio::stats::{Prob, LogProb};

use io::codebook::{self, Codebook, Codeword, FeatureID};

use model::readout::{Expressions, Counts, Miscalls, FeatureModel, NoiseModel, Xi};
use model::readout::feature_model::AbstractFeatureModel;

pub struct JointModel {
    feature_models: HashMap<FeatureID, FeatureModel>,
    noise_model: NoiseModel,
    expressions: Expressions,
    miscalls_exact: Miscalls,
    miscalls_mismatch: Miscalls,
    margin: u32,
    em_run: bool,
    rng: rand::StdRng,
    debug_id: Option<FeatureID>,
    noise_id: FeatureID
}

impl JointModel {
    pub fn new<'a, I: Iterator<Item=(&'a String, &'a Counts)>>(
        counts: I,
        p0: &[Prob],
        p1: &[Prob],
        codebook: &Codebook,
        window_width: u32) -> Self {
        let mut xi = Xi::new(p0, p1);
        let mut rng = rand::StdRng::new().unwrap();

        // Generate feature models and info about not expressed features.
        let mut feature_models = HashMap::new();
        let mut not_expressed_counts = Vec::new();
        let mut not_expressed_feature_ids = Vec::new();
        for (feature, counts) in counts {
            let feature = codebook.get_id(feature);
            let rec = codebook.record(feature);
            if rec.expressed() {
                feature_models.insert(
                    feature, FeatureModel::new(feature, counts.clone(), codebook, &xi)
                );
            } else {
                not_expressed_counts.push(counts.clone());
                not_expressed_feature_ids.push(feature);
            }
        }

        let feature_count = codebook.len() + 1;

        // calculate start values (we take random numbers as start expression)
        let start_range = rand::distributions::Range::new(1, 10000);
        let mut expressions = Array1::from_iter((0..feature_count).map(
            |model| start_range.ind_sample(&mut rng)
        ));
        for &feat_id in &not_expressed_feature_ids {
            expressions[feat_id] = 0;
        }

        // Take value larger than maximum feature id as noise id.
        let noise_id = codebook.len();
        let noise_model = NoiseModel::new(
            codebook.len(), not_expressed_feature_ids, not_expressed_counts, codebook, &xi
        );

        let miscalls_exact = Miscalls::new(feature_count, &feature_models, &noise_model, true);
        let miscalls_mismatch = Miscalls::new(feature_count, &feature_models, &noise_model, false);

        JointModel {
            feature_models: feature_models,
            noise_model: noise_model,
            expressions: expressions,
            miscalls_exact: miscalls_exact,
            miscalls_mismatch: miscalls_mismatch,
            margin: window_width / 2,
            em_run: false,
            rng: rng,
            debug_id: None, //codebook.get_id("THBS1")
            noise_id: noise_id
        }
    }

    /// Jointly estimate MAP using the EM algorithm.
    ///
    /// Expressions are our model parameters to estimate, miscalls are our latent variables,
    /// counts are our observed variables.
    pub fn expectation_maximization(&mut self) {
        let mut feature_models: Vec<Box<&AbstractFeatureModel>> =
            self.feature_models.values().map(|m| Box::new(m as &AbstractFeatureModel)).collect_vec();
        feature_models.push(Box::new(&self.noise_model));
        let n_iterations = 100;

        let mut last_changes = Array2::from_elem((self.expressions.len(), 5), 0.0);

        // EM iterations
        for i in 1..n_iterations + 1 {
            debug!("EM-iteration {} of at most {}", i, n_iterations);

            // E-step: estimate miscalls
            debug!("E-step");

            // Shuffle models, such that miscalls can be drawn unbiased
            // this is necessary because there is a maximum miscall count for each feature.
            // If we would not shuffle, it would be easier for the first model to provide miscalls.
            self.rng.shuffle(&mut feature_models);
            for m in &feature_models {
                m.mle_miscalls(
                    &self.expressions,
                    &mut self.miscalls_exact,
                    &mut self.miscalls_mismatch,
                    &mut self.rng
                );
            }

            // M-step: estimate expressions that maximize the probability
            debug!("M-step");
            for m in &feature_models {
                let feature_id = m.feature_id();
                last_changes[(feature_id, feature_id % 5)] = m.mle_expression(
                    &mut self.expressions,
                    &self.miscalls_exact,
                    &self.miscalls_mismatch
                ) as f64;
            }

            // calculate mean change per feature of last 5 steps
            let mean_changes = last_changes.mean(Axis(1));
            debug!("x={:?}", self.expressions);
            debug!("mean changes={:?}", mean_changes);
            let convergence = *mean_changes.iter().map(
                |&c| NotNaN::new(c.abs()).unwrap()
            ).max().unwrap() <= 1.0;

            if i >= 5 && convergence {
                debug!("Convergence reached, stopping EM algorithm.");
                break;
            }
        }
        self.em_run = true;
    }

    pub fn likelihood(&mut self, feature_id: FeatureID, x: u32) -> LogProb {
        assert!(self.em_run);
        self.feature_model(feature_id).likelihood(
            x, &self.miscalls_exact, &self.miscalls_mismatch
        )
    }

    pub fn map_estimate(&self, feature_id: FeatureID) -> u32 {
        assert!(self.em_run);
        self.expressions[feature_id as usize]
    }

    fn feature_model(&self, feature_id: FeatureID) -> &FeatureModel {
        self.feature_models.get(&feature_id).unwrap()
    }

    /// Prior window for calculating expression PMF
    pub fn window(&self, feature_id: FeatureID) -> (u32, u32) {
        assert!(self.em_run);
        let x = self.map_estimate(feature_id);
        let xmin = self.feature_model(feature_id).min_expression(
            &self.miscalls_exact, &self.miscalls_mismatch
        );
        let xmax = x + self.margin;
        assert!(xmax >= xmin, "xmax has to be greater than xmin: xmin={}, xmax={}", xmin, xmax);
        (xmin, xmax)
    }
}
<|endoftext|>


<commit_before>//! Physical devices and adapters.
//!
//! The `PhysicalDevice` trait specifies the API a backend must provide for dealing with
//! and querying a physical device, such as a particular GPU.  An `Adapter` is a struct
//! containing a `PhysicalDevice` and metadata for a particular GPU, generally created
//! from an `Instance` of that backend.  `adapter.open_with(...)` will return a `Device`
//! that has the properties specified.

use std::any::Any;

use error::DeviceCreationError;
use queue::{Capability, QueueGroup};
use {format, image, memory, Backend, Features, Gpu, Limits};

/// Scheduling hint for devices about the priority of a queue.  Values range from `0.0` (low) to
/// `1.0` (high).
pub type QueuePriority = f32;

/// A strongly-typed index to a particular `MemoryType`.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MemoryTypeId(pub usize);

impl From<usize> for MemoryTypeId {
    fn from(id: usize) -> Self {
        MemoryTypeId(id)
    }
}

/// A description for a single chunk of memory in a heap.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MemoryType {
    /// Properties of the associated memory, such as synchronization
    /// properties or whether it's on the CPU or GPU.
    pub properties: memory::Properties,
    /// Index to the underlying memory heap in `Gpu::memory_heaps`
    pub heap_index: usize,
}

/// Types of memory supported by this adapter and available memory.
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MemoryProperties {
    /// Each memory type is associated with one heap of `memory_heaps`.
    /// Multiple types can point to the same heap.
    pub memory_types: Vec<MemoryType>,
    /// Memory heaps with their size in bytes.
    pub memory_heaps: Vec<u64>,
}

/// Represents a physical device (such as a GPU) capable of supporting the given backend.
pub trait PhysicalDevice<B: Backend>: Any + Send + Sync {
    /// Create a new logical device.
    ///
    /// # Errors
    ///
    /// - Returns `TooManyObjects` if the implementation can't create a new logical device.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # extern crate gfx_backend_empty as empty;
    /// # extern crate gfx_hal;
    /// # fn main() {
    /// use gfx_hal::PhysicalDevice;
    ///
    /// # let physical_device: empty::PhysicalDevice = return;
    /// # let family: empty::QueueFamily = return;
    /// let gpu = physical_device.open(&[(&family, &[1.0; 1])]);
    /// # }
    /// ```
    fn open(
        &self,
        families: &[(&B::QueueFamily, &[QueuePriority])],
    ) -> Result<Gpu<B>, DeviceCreationError>;

    /// Fetch details for a particular format.
    fn format_properties(&self, format: Option<format::Format>) -> format::Properties;

    /// Fetch details for a particular image format.
    fn image_format_properties(
        &self,
        format: format::Format,
        dimensions: u8,
        tiling: image::Tiling,
        usage: image::Usage,
        view_caps: image::ViewCapabilities,
    ) -> Option<image::FormatProperties>;

    /// Fetch details for the memory regions provided by the device.
    fn memory_properties(&self) -> MemoryProperties;

    /// Returns the features of this `Device`. This usually depends on the graphics API being
    /// used.
    fn features(&self) -> Features;

    /// Returns the resource limits of this `Device`.
    fn limits(&self) -> Limits;
}

/// Supported physical device types
#[derive(Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum DeviceType {
    /// Other
    Other = 0,
    /// Integrated
    IntegratedGpu = 1,
    /// Discrete
    DiscreteGpu = 2,
    /// Virtual / Hosted
    VirtualGpu = 3,
    /// Cpu / Software Rendering
    Cpu = 4,
}

/// Metadata about a backend adapter.
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct AdapterInfo {
    /// Adapter name
    pub name: String,
    /// Vendor PCI id of the adapter
    pub vendor: usize,
    /// PCI id of the adapter
    pub device: usize,
    /// Type of device
    pub device_type: DeviceType,
}

/// The list of `Adapter` instances is obtained by calling `Instance::enumerate_adapters()`.
///
/// Given an `Adapter` a `Gpu` can be constructed by calling `PhysicalDevice::open()` on its
/// `physical_device` field. However, if only a single queue family is needed, then the
/// `Adapter::open_with` convenience method can be used instead.
pub struct Adapter<B: Backend> {
    /// General information about this adapter.
    pub info: AdapterInfo,
    /// Actual physical device.
    pub physical_device: B::PhysicalDevice,
    /// Queue families supported by this adapter.
    pub queue_families: Vec<B::QueueFamily>,
}

impl<B: Backend> Adapter<B> {
    /// Open the physical device with `count` queues from some active queue family. The family is
    /// the first that both provides the capability `C`, supports at least `count' queues, and for
    /// which `selector` returns true.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # extern crate gfx_backend_empty as empty;
    /// # extern crate gfx_hal as hal;
    /// use hal::General;
    /// # fn main() {
    ///
    /// # let mut adapter: hal::Adapter<empty::Backend> = return;
    /// let (device, queues) = adapter.open_with::<_, General>(1, |_| true).unwrap();
    /// # }
    /// ```
    ///
    /// # Return
    ///
    /// Returns the same errors as `open` and `InitializationFailed` if no suitable
    /// queue family could be found.
    pub fn open_with<F, C>(
        &mut self,
        count: usize,
        selector: F,
    ) -> Result<(B::Device, QueueGroup<B, C>), DeviceCreationError>
    where
        F: Fn(&B::QueueFamily) -> bool,
        C: Capability,
    {
        use queue::QueueFamily;

        let requested_family = self
            .queue_families
            .drain(..)
            .filter(|family| {
                C::supported_by(family.queue_type())
                    && selector(&family)
                    && count <= family.max_queues()
            })
            .next();

        let priorities = vec![1.0; count];
        let (id, families) = match requested_family {
            Some(ref family) => (family.id(), [(family, priorities.as_slice())]),
            _ => return Err(DeviceCreationError::InitializationFailed),
        };

        let Gpu { device, mut queues } = self.physical_device.open(&families)?;
        Ok((device, queues.take(id).unwrap()))
    }
}
<commit_msg>Fix incorrect apostrophe.<commit_after>//! Physical devices and adapters.
//!
//! The `PhysicalDevice` trait specifies the API a backend must provide for dealing with
//! and querying a physical device, such as a particular GPU.  An `Adapter` is a struct
//! containing a `PhysicalDevice` and metadata for a particular GPU, generally created
//! from an `Instance` of that backend.  `adapter.open_with(...)` will return a `Device`
//! that has the properties specified.

use std::any::Any;

use error::DeviceCreationError;
use queue::{Capability, QueueGroup};
use {format, image, memory, Backend, Features, Gpu, Limits};

/// Scheduling hint for devices about the priority of a queue.  Values range from `0.0` (low) to
/// `1.0` (high).
pub type QueuePriority = f32;

/// A strongly-typed index to a particular `MemoryType`.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MemoryTypeId(pub usize);

impl From<usize> for MemoryTypeId {
    fn from(id: usize) -> Self {
        MemoryTypeId(id)
    }
}

/// A description for a single chunk of memory in a heap.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MemoryType {
    /// Properties of the associated memory, such as synchronization
    /// properties or whether it's on the CPU or GPU.
    pub properties: memory::Properties,
    /// Index to the underlying memory heap in `Gpu::memory_heaps`
    pub heap_index: usize,
}

/// Types of memory supported by this adapter and available memory.
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MemoryProperties {
    /// Each memory type is associated with one heap of `memory_heaps`.
    /// Multiple types can point to the same heap.
    pub memory_types: Vec<MemoryType>,
    /// Memory heaps with their size in bytes.
    pub memory_heaps: Vec<u64>,
}

/// Represents a physical device (such as a GPU) capable of supporting the given backend.
pub trait PhysicalDevice<B: Backend>: Any + Send + Sync {
    /// Create a new logical device.
    ///
    /// # Errors
    ///
    /// - Returns `TooManyObjects` if the implementation can't create a new logical device.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # extern crate gfx_backend_empty as empty;
    /// # extern crate gfx_hal;
    /// # fn main() {
    /// use gfx_hal::PhysicalDevice;
    ///
    /// # let physical_device: empty::PhysicalDevice = return;
    /// # let family: empty::QueueFamily = return;
    /// let gpu = physical_device.open(&[(&family, &[1.0; 1])]);
    /// # }
    /// ```
    fn open(
        &self,
        families: &[(&B::QueueFamily, &[QueuePriority])],
    ) -> Result<Gpu<B>, DeviceCreationError>;

    /// Fetch details for a particular format.
    fn format_properties(&self, format: Option<format::Format>) -> format::Properties;

    /// Fetch details for a particular image format.
    fn image_format_properties(
        &self,
        format: format::Format,
        dimensions: u8,
        tiling: image::Tiling,
        usage: image::Usage,
        view_caps: image::ViewCapabilities,
    ) -> Option<image::FormatProperties>;

    /// Fetch details for the memory regions provided by the device.
    fn memory_properties(&self) -> MemoryProperties;

    /// Returns the features of this `Device`. This usually depends on the graphics API being
    /// used.
    fn features(&self) -> Features;

    /// Returns the resource limits of this `Device`.
    fn limits(&self) -> Limits;
}

/// Supported physical device types
#[derive(Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum DeviceType {
    /// Other
    Other = 0,
    /// Integrated
    IntegratedGpu = 1,
    /// Discrete
    DiscreteGpu = 2,
    /// Virtual / Hosted
    VirtualGpu = 3,
    /// Cpu / Software Rendering
    Cpu = 4,
}

/// Metadata about a backend adapter.
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct AdapterInfo {
    /// Adapter name
    pub name: String,
    /// Vendor PCI id of the adapter
    pub vendor: usize,
    /// PCI id of the adapter
    pub device: usize,
    /// Type of device
    pub device_type: DeviceType,
}

/// The list of `Adapter` instances is obtained by calling `Instance::enumerate_adapters()`.
///
/// Given an `Adapter` a `Gpu` can be constructed by calling `PhysicalDevice::open()` on its
/// `physical_device` field. However, if only a single queue family is needed, then the
/// `Adapter::open_with` convenience method can be used instead.
pub struct Adapter<B: Backend> {
    /// General information about this adapter.
    pub info: AdapterInfo,
    /// Actual physical device.
    pub physical_device: B::PhysicalDevice,
    /// Queue families supported by this adapter.
    pub queue_families: Vec<B::QueueFamily>,
}

impl<B: Backend> Adapter<B> {
    /// Open the physical device with `count` queues from some active queue family. The family is
    /// the first that both provides the capability `C`, supports at least `count` queues, and for
    /// which `selector` returns true.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # extern crate gfx_backend_empty as empty;
    /// # extern crate gfx_hal as hal;
    /// use hal::General;
    /// # fn main() {
    ///
    /// # let mut adapter: hal::Adapter<empty::Backend> = return;
    /// let (device, queues) = adapter.open_with::<_, General>(1, |_| true).unwrap();
    /// # }
    /// ```
    ///
    /// # Return
    ///
    /// Returns the same errors as `open` and `InitializationFailed` if no suitable
    /// queue family could be found.
    pub fn open_with<F, C>(
        &mut self,
        count: usize,
        selector: F,
    ) -> Result<(B::Device, QueueGroup<B, C>), DeviceCreationError>
    where
        F: Fn(&B::QueueFamily) -> bool,
        C: Capability,
    {
        use queue::QueueFamily;

        let requested_family = self
            .queue_families
            .drain(..)
            .filter(|family| {
                C::supported_by(family.queue_type())
                    && selector(&family)
                    && count <= family.max_queues()
            })
            .next();

        let priorities = vec![1.0; count];
        let (id, families) = match requested_family {
            Some(ref family) => (family.id(), [(family, priorities.as_slice())]),
            _ => return Err(DeviceCreationError::InitializationFailed),
        };

        let Gpu { device, mut queues } = self.physical_device.open(&families)?;
        Ok((device, queues.take(id).unwrap()))
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::slice;
use std::ffi;

use htslib;

pub type SampleSubset = Vec<i32>;

/// A BCF header.
pub struct Header {
    pub inner: *mut htslib::vcf::bcf_hdr_t,
    pub subset: Option<SampleSubset>,
}

impl Header {
    /// Create a new header.
    pub fn new() -> Self {
        Header {
            inner: unsafe { htslib::vcf::bcf_hdr_init(ffi::CString::new(&b"w"[..]).unwrap().as_ptr()) },
            subset: None,
        }
    }

    pub fn with_template(header: &HeaderView) -> Self {
        Header { inner: unsafe { htslib::vcf::bcf_hdr_dup(header.inner) }, subset: None }
    }

    pub fn subset_template(header: &HeaderView, samples: &[&[u8]]) -> Result<Self, SubsetError> {
        let mut imap = vec![0; samples.len()];
        let names: Vec<_> = samples.iter().map(|&s| ffi::CString::new(s).unwrap()).collect();
        let name_pointers: Vec<_> = names.iter().map(|s| s.as_ptr() as *mut i8).collect();
        let inner = unsafe {
            htslib::vcf::bcf_hdr_subset(header.inner, samples.len() as i32, name_pointers.as_ptr(), imap.as_mut_ptr() as *mut i32)
        };
        if inner.is_null() {
            Err(SubsetError::DuplicateSampleName)
        }
        else {
            Ok(Header { inner: inner, subset: Some(imap) })
        }
    }

    pub fn push_sample(&mut self, sample: &[u8]) -> &mut Self {
        unsafe { htslib::vcf::bcf_hdr_add_sample(self.inner, ffi::CString::new(sample).unwrap().as_ptr()) };
        self
    }

    /// Add a record to the header.
    pub fn push_record(&mut self, record: &[u8]) -> &mut Self {
        unsafe { htslib::vcf::bcf_hdr_append(self.inner, ffi::CString::new(record).unwrap().as_ptr()) };
        self
    }

    pub fn remove_info(&mut self, tag: &[u8]) -> &mut Self {
        unsafe {
            htslib::vcf::bcf_hdr_remove(self.inner, htslib::vcf::BCF_HL_INFO, tag.as_ptr() as *const i8);
        }
        self
    }

    pub fn remove_format(&mut self, tag: &[u8]) -> &mut Self {
        unsafe {
            htslib::vcf::bcf_hdr_remove(self.inner, htslib::vcf::BCF_HL_FMT, tag.as_ptr() as *const i8);
        }
        self
    }
}

impl Drop for Header {
    fn drop(&mut self) {
        unsafe { htslib::vcf::bcf_hdr_destroy(self.inner) };
    }
}

pub struct HeaderView {
    pub inner: *mut htslib::vcf::bcf_hdr_t,
}

impl HeaderView {
    pub fn new(inner: *mut htslib::vcf::bcf_hdr_t) -> Self {
        HeaderView { inner: inner }
    }

    #[inline]
    fn inner(&self) -> htslib::vcf::bcf_hdr_t {
        unsafe { (*self.inner) }
    }

    pub fn sample_count(&self) -> u32 {
        self.inner().n[htslib::vcf::BCF_DT_SAMPLE as usize] as u32
    }

    pub fn samples(&self) -> Vec<&[u8]> {
        let names = unsafe { slice::from_raw_parts(self.inner().samples, self.sample_count() as usize) };
        names.iter().map(|name| unsafe { ffi::CStr::from_ptr(*name).to_bytes() }).collect()
    }

    pub fn rid2name(&self, rid: u32) -> &[u8] {
        unsafe {
            let dict = self.inner().id[htslib::vcf::BCF_DT_CTG as usize];
            let ptr = (*dict.offset(rid as isize)).key;
            ffi::CStr::from_ptr(ptr).to_bytes()
        }
    }

    pub fn info_type(&self, tag: &[u8]) -> Result<(TagType, TagLength), TagTypeError> {
        self.tag_type(tag, htslib::vcf::BCF_HL_INFO)
    }

    pub fn format_type(&self, tag: &[u8]) -> Result<(TagType, TagLength), TagTypeError> {
        self.tag_type(tag, htslib::vcf::BCF_HL_FMT)
    }

    fn tag_type(&self, tag: &[u8], hdr_type: ::libc::c_int) -> Result<(TagType, TagLength), TagTypeError> {
        let (_type, length) = unsafe {
            let id = htslib::vcf::bcf_hdr_id2int(
                self.inner,
                htslib::vcf::BCF_DT_ID,
                ffi::CString::new(tag).unwrap().as_ptr() as *mut i8
            );
            let n = (*self.inner).n[htslib::vcf::BCF_DT_ID as usize] as usize;
            let entry = slice::from_raw_parts((*self.inner).id[htslib::vcf::BCF_DT_ID as usize], n);
            let d = (*entry[id as usize].val).info[hdr_type as usize];
            (d >> 4 & 0xf, d >> 8 & 0xf)
        };
        let _type = match _type as ::libc::c_int {
            htslib::vcf::BCF_HT_FLAG => TagType::Flag,
            htslib::vcf::BCF_HT_INT => TagType::Integer,
            htslib::vcf::BCF_HT_REAL => TagType::Float,
            htslib::vcf::BCF_HT_STR => TagType::String,
            _ => return Err(TagTypeError::UnexpectedTagType)
        };
        let length = match length as ::libc::c_int {
            htslib::vcf::BCF_VL_FIXED => TagLength::Fixed,
            htslib::vcf::BCF_VL_VAR => TagLength::Variable,
            htslib::vcf::BCF_VL_A => TagLength::AltAlleles,
            htslib::vcf::BCF_VL_R => TagLength::Alleles,
            htslib::vcf::BCF_VL_G => TagLength::Genotypes,
            _ => return Err(TagTypeError::UnexpectedTagType)
        };

        Ok((_type, length))
    }
}

pub enum TagType {
    Flag,
    Integer,
    Float,
    String
}

pub enum TagLength {
    Fixed,
    AltAlleles,
    Alleles,
    Genotypes,
    Variable
}

quick_error! {
    #[derive(Debug)]
    pub enum SubsetError {
        DuplicateSampleName {
            description("duplicate sample name when subsetting header")
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum TagTypeError {
        UnexpectedTagType {
            description("unexpected tag type in header")
        }
    }
}
<commit_msg>Implement name2rid.<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

use std::slice;
use std::ffi;
use std::str;

use htslib;

pub type SampleSubset = Vec<i32>;

/// A BCF header.
pub struct Header {
    pub inner: *mut htslib::vcf::bcf_hdr_t,
    pub subset: Option<SampleSubset>,
}

impl Header {
    /// Create a new header.
    pub fn new() -> Self {
        Header {
            inner: unsafe { htslib::vcf::bcf_hdr_init(ffi::CString::new(&b"w"[..]).unwrap().as_ptr()) },
            subset: None,
        }
    }

    pub fn with_template(header: &HeaderView) -> Self {
        Header { inner: unsafe { htslib::vcf::bcf_hdr_dup(header.inner) }, subset: None }
    }

    pub fn subset_template(header: &HeaderView, samples: &[&[u8]]) -> Result<Self, SubsetError> {
        let mut imap = vec![0; samples.len()];
        let names: Vec<_> = samples.iter().map(|&s| ffi::CString::new(s).unwrap()).collect();
        let name_pointers: Vec<_> = names.iter().map(|s| s.as_ptr() as *mut i8).collect();
        let inner = unsafe {
            htslib::vcf::bcf_hdr_subset(header.inner, samples.len() as i32, name_pointers.as_ptr(), imap.as_mut_ptr() as *mut i32)
        };
        if inner.is_null() {
            Err(SubsetError::DuplicateSampleName)
        }
        else {
            Ok(Header { inner: inner, subset: Some(imap) })
        }
    }

    pub fn push_sample(&mut self, sample: &[u8]) -> &mut Self {
        unsafe { htslib::vcf::bcf_hdr_add_sample(self.inner, ffi::CString::new(sample).unwrap().as_ptr()) };
        self
    }

    /// Add a record to the header.
    pub fn push_record(&mut self, record: &[u8]) -> &mut Self {
        unsafe { htslib::vcf::bcf_hdr_append(self.inner, ffi::CString::new(record).unwrap().as_ptr()) };
        self
    }

    pub fn remove_info(&mut self, tag: &[u8]) -> &mut Self {
        unsafe {
            htslib::vcf::bcf_hdr_remove(self.inner, htslib::vcf::BCF_HL_INFO, tag.as_ptr() as *const i8);
        }
        self
    }

    pub fn remove_format(&mut self, tag: &[u8]) -> &mut Self {
        unsafe {
            htslib::vcf::bcf_hdr_remove(self.inner, htslib::vcf::BCF_HL_FMT, tag.as_ptr() as *const i8);
        }
        self
    }
}

impl Drop for Header {
    fn drop(&mut self) {
        unsafe { htslib::vcf::bcf_hdr_destroy(self.inner) };
    }
}

pub struct HeaderView {
    pub inner: *mut htslib::vcf::bcf_hdr_t,
}

impl HeaderView {
    pub fn new(inner: *mut htslib::vcf::bcf_hdr_t) -> Self {
        HeaderView { inner: inner }
    }

    #[inline]
    fn inner(&self) -> htslib::vcf::bcf_hdr_t {
        unsafe { (*self.inner) }
    }

    pub fn sample_count(&self) -> u32 {
        self.inner().n[htslib::vcf::BCF_DT_SAMPLE as usize] as u32
    }

    pub fn samples(&self) -> Vec<&[u8]> {
        let names = unsafe { slice::from_raw_parts(self.inner().samples, self.sample_count() as usize) };
        names.iter().map(|name| unsafe { ffi::CStr::from_ptr(*name).to_bytes() }).collect()
    }

    pub fn rid2name(&self, rid: u32) -> &[u8] {
        unsafe {
            let dict = self.inner().id[htslib::vcf::BCF_DT_CTG as usize];
            let ptr = (*dict.offset(rid as isize)).key;
            ffi::CStr::from_ptr(ptr).to_bytes()
        }
    }

    pub fn name2rid(&self, name: &[u8]) -> Result<u32, RidError> {
        unsafe {
            match htslib::vcf::bcf_hdr_id2int(
                self.inner,
                htslib::vcf::BCF_DT_CTG,
                ffi::CString::new(name).unwrap().as_ptr() as *mut i8
            ) {
                -1 => Err(RidError::UnknownSequence(str::from_utf8(name).unwrap().to_owned())),
                i  => Ok(i as u32)
            }
        }
    }

    pub fn info_type(&self, tag: &[u8]) -> Result<(TagType, TagLength), TagTypeError> {
        self.tag_type(tag, htslib::vcf::BCF_HL_INFO)
    }

    pub fn format_type(&self, tag: &[u8]) -> Result<(TagType, TagLength), TagTypeError> {
        self.tag_type(tag, htslib::vcf::BCF_HL_FMT)
    }

    fn tag_type(&self, tag: &[u8], hdr_type: ::libc::c_int) -> Result<(TagType, TagLength), TagTypeError> {
        let (_type, length) = unsafe {
            let id = htslib::vcf::bcf_hdr_id2int(
                self.inner,
                htslib::vcf::BCF_DT_ID,
                ffi::CString::new(tag).unwrap().as_ptr() as *mut i8
            );
            let n = (*self.inner).n[htslib::vcf::BCF_DT_ID as usize] as usize;
            let entry = slice::from_raw_parts((*self.inner).id[htslib::vcf::BCF_DT_ID as usize], n);
            let d = (*entry[id as usize].val).info[hdr_type as usize];
            (d >> 4 & 0xf, d >> 8 & 0xf)
        };
        let _type = match _type as ::libc::c_int {
            htslib::vcf::BCF_HT_FLAG => TagType::Flag,
            htslib::vcf::BCF_HT_INT => TagType::Integer,
            htslib::vcf::BCF_HT_REAL => TagType::Float,
            htslib::vcf::BCF_HT_STR => TagType::String,
            _ => return Err(TagTypeError::UnexpectedTagType)
        };
        let length = match length as ::libc::c_int {
            htslib::vcf::BCF_VL_FIXED => TagLength::Fixed,
            htslib::vcf::BCF_VL_VAR => TagLength::Variable,
            htslib::vcf::BCF_VL_A => TagLength::AltAlleles,
            htslib::vcf::BCF_VL_R => TagLength::Alleles,
            htslib::vcf::BCF_VL_G => TagLength::Genotypes,
            _ => return Err(TagTypeError::UnexpectedTagType)
        };

        Ok((_type, length))
    }
}

pub enum TagType {
    Flag,
    Integer,
    Float,
    String
}

pub enum TagLength {
    Fixed,
    AltAlleles,
    Alleles,
    Genotypes,
    Variable
}

quick_error! {
    #[derive(Debug)]
    pub enum RidError {
        UnknownSequence(name: String) {
            description("unknown sequence")
            display("sequence {} not found in header", name)
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum SubsetError {
        DuplicateSampleName {
            description("duplicate sample name when subsetting header")
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum TagTypeError {
        UnexpectedTagType {
            description("unexpected tag type in header")
        }
    }
}
<|endoftext|>