<commit_before>//! This module contains the implementation for an in-memory DICOM object.

use itertools::Itertools;
use smallvec::SmallVec;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::{BufReader, Read};
use std::path::Path;

use crate::meta::FileMetaTable;
use crate::{DicomObject, RootDicomObject};
use dicom_core::dictionary::{DataDictionary, DictionaryEntry};
use dicom_core::header::Header;
use dicom_core::value::{DicomValueType, Value, ValueType, C};
use dicom_core::{DataElement, Length, Tag, VR};
use dicom_dictionary_std::StandardDataDictionary;
use dicom_encoding::text::SpecificCharacterSet;
use dicom_encoding::transfer_syntax::TransferSyntaxIndex;
use dicom_parser::dataset::{DataSetReader, DataToken};
use dicom_parser::error::{DataSetSyntaxError, Error, Result};
use dicom_parser::parser::Parse;
use dicom_transfer_syntax_registry::TransferSyntaxRegistry;

/// A full in-memory DICOM data element.
pub type InMemElement<D> = DataElement<InMemDicomObject<D>>;

/** A DICOM object that is fully contained in memory.
 */
#[derive(Debug, Clone)]
pub struct InMemDicomObject<D> {
    /// the element map
    entries: BTreeMap<Tag, InMemElement<D>>,
    /// the data dictionary
    dict: D,
    /// The length of the DICOM object in bytes.
    /// It is usually undefined, unless it is part of an item
    /// in a sequence with a specified length in its item header.
    len: Length,
}

impl<'s, D> PartialEq for InMemDicomObject<D> {
    // This implementation ignores the data dictionary.
    fn eq(&self, other: &Self) -> bool {
        self.entries == other.entries
    }
}

impl<D> DicomValueType for InMemDicomObject<D> {
    fn value_type(&self) -> ValueType {
        ValueType::Item
    }

    fn size(&self) -> Length {
        self.len
    }
}

impl<'s, D: 's> DicomObject for &'s InMemDicomObject<D>
where
    D: DataDictionary,
    D: Clone,
{
    type Element = &'s InMemElement<D>;

    fn element(&self, tag: Tag) -> Result<Self::Element> {
        self.entries.get(&tag).ok_or(Error::NoSuchDataElement)
    }

    fn element_by_name(&self, name: &str) -> Result<Self::Element> {
        let tag = self.lookup_name(name)?;
        self.element(tag)
    }
}

impl RootDicomObject<InMemDicomObject<StandardDataDictionary>> {
    /// Create a DICOM object by reading from a file.
    ///
    /// This function assumes the standard file encoding structure: 128-byte
    /// preamble, file meta group, and the rest of the data set.
    pub fn open_file<P: AsRef<Path>>(path: P) -> Result<Self> {
        Self::open_file_with_dict(path, StandardDataDictionary)
    }

    /// Create a DICOM object by reading from a byte source.
    ///
    /// This function assumes the standard file encoding structure without the
    /// preamble: file meta group, followed by the rest of the data set.
    pub fn from_reader<S>(src: S) -> Result<Self>
    where
        S: Read,
    {
        Self::from_reader_with_dict(src, StandardDataDictionary)
    }
}

impl InMemDicomObject<StandardDataDictionary> {
    /// Create a new empty DICOM object.
    pub fn create_empty() -> Self {
        InMemDicomObject {
            entries: BTreeMap::new(),
            dict: StandardDataDictionary,
            len: Length::UNDEFINED,
        }
    }

    /// Construct a DICOM object from an iterator of structured elements.
    pub fn from_element_iter<I>(iter: I) -> Result<Self>
    where
        I: IntoIterator<Item = Result<InMemElement<StandardDataDictionary>>>,
    {
        Self::from_iter_with_dict(iter, StandardDataDictionary)
    }
}

impl<D> RootDicomObject<InMemDicomObject<D>>
where
    D: DataDictionary,
    D: Clone,
{
    /// Create a new empty object, using the given dictionary and
    /// file meta table.
    pub fn new_empty_with_dict_and_meta(dict: D, meta: FileMetaTable) -> Self {
        RootDicomObject {
            meta,
            obj: InMemDicomObject {
                entries: BTreeMap::new(),
                dict,
                len: Length::UNDEFINED,
            },
        }
    }

    /// Create a DICOM object by reading from a file.
    ///
    /// This function assumes the standard file encoding structure: 128-byte
    /// preamble, file meta group, and the rest of the data set.
    pub fn open_file_with_dict<P: AsRef<Path>>(path: P, dict: D) -> Result<Self> {
        let mut file = BufReader::new(File::open(path)?);

        // skip preamble
        {
            let mut buf = [0u8; 128];
            // skip the preamble
            file.read_exact(&mut buf)?;
        }

        // read metadata header
        let meta = FileMetaTable::from_reader(&mut file)?;

        // read rest of data according to metadata, feed it to object
        let ts = TransferSyntaxRegistry
            .get(&meta.transfer_syntax)
            .ok_or(Error::UnsupportedTransferSyntax)?;
        let cs = SpecificCharacterSet::Default;
        let mut dataset = DataSetReader::new_with_dictionary(file, dict.clone(), ts, cs)?;

        Ok(RootDicomObject {
            meta,
            obj: InMemDicomObject::build_object(&mut dataset, dict, false, Length::UNDEFINED)?,
        })
    }

    /// Create a DICOM object by reading from a byte source.
    ///
    /// This function assumes the standard file encoding structure without the
    /// preamble: file meta group, followed by the rest of the data set.
    pub fn from_reader_with_dict<S>(src: S, dict: D) -> Result<Self>
    where
        S: Read,
    {
        let mut file = BufReader::new(src);

        // read metadata header
        let meta = FileMetaTable::from_reader(&mut file)?;

        // read rest of data according to metadata, feed it to object
        let ts = TransferSyntaxRegistry
            .get(&meta.transfer_syntax)
            .ok_or(Error::UnsupportedTransferSyntax)?;
        let cs = SpecificCharacterSet::Default;
        let mut dataset = DataSetReader::new_with_dictionary(file, dict.clone(), ts, cs)?;
        Ok(RootDicomObject {
            meta,
            obj: InMemDicomObject::build_object(&mut dataset, dict, false, Length::UNDEFINED)?,
        })
    }
}

impl<D> InMemDicomObject<D>
where
    D: DataDictionary,
    D: Clone,
{
    /// Create a new empty object, using the given dictionary for name lookup.
    pub fn new_empty_with_dict(dict: D) -> Self {
        InMemDicomObject {
            entries: BTreeMap::new(),
            dict,
            len: Length::UNDEFINED,
        }
    }

    /// Construct a DICOM object from an iterator of structured elements.
    pub fn from_iter_with_dict<I>(iter: I, dict: D) -> Result<Self>
    where
        I: IntoIterator<Item = Result<InMemElement<D>>>,
    {
        let entries: Result<_> = iter.into_iter().map_results(|e| (e.tag(), e)).collect();
        Ok(InMemDicomObject {
            entries: entries?,
            dict,
            len: Length::UNDEFINED,
        })
    }

    // Standard methods follow. They are not placed as a trait implementation
    // because they may require outputs to reference the lifetime of self,
    // which is not possible without GATs.

    /// Retrieve the object's meta table if available.
    ///
    /// At the moment, this is sure to return `None`, because the meta
    /// table is kept in a separate wrapper value.
    pub fn meta(&self) -> Option<&FileMetaTable> {
        None
    }

    /// Retrieve a particular DICOM element by its tag.
    pub fn element(&self, tag: Tag) -> Result<&InMemElement<D>> {
        self.entries.get(&tag).ok_or(Error::NoSuchDataElement)
    }

    /// Retrieve a particular DICOM element by its name.
    pub fn element_by_name(&self, name: &str) -> Result<&InMemElement<D>> {
        let tag = self.lookup_name(name)?;
        self.element(tag)
    }

    /// Insert a data element to the object, replacing (and returning) any
    /// previous element of the same attribute.
    pub fn put(&mut self, elt: InMemElement<D>) -> Option<InMemElement<D>> {
        self.entries.insert(elt.tag(), elt)
    }

    // private methods

    /// Build an object by consuming a data set parser.
    fn build_object<'s, S: 's, P>(
        dataset: &mut DataSetReader<S, P, D>,
        dict: D,
        in_item: bool,
        len: Length,
    ) -> Result<Self>
    where
        S: Read,
        P: Parse<dyn Read + 's>,
    {
        let mut entries: BTreeMap<Tag, InMemElement<D>> = BTreeMap::new();
        // perform a structured parsing of incoming tokens
        while let Some(token) = dataset.next() {
            let elem = match token? {
                DataToken::ElementHeader(header) => {
                    // fetch respective value, place it in the entries
                    let next_token = dataset.next().ok_or_else(|| Error::MissingElementValue)?;
                    match next_token? {
                        DataToken::PrimitiveValue(v) => {
                            InMemElement::new(header.tag, header.vr, Value::Primitive(v))
                        }
                        token => {
                            return Err(DataSetSyntaxError::UnexpectedToken(token).into());
                        }
                    }
                }
                DataToken::SequenceStart { tag, len } => {
                    // delegate sequence building to another function
                    let items = Self::build_sequence(tag, len, &mut *dataset, &dict)?;
                    DataElement::new(tag, VR::SQ, Value::Sequence { items, size: len })
                }
                DataToken::ItemEnd if in_item => {
                    // end of item, leave now
                    return Ok(InMemDicomObject { entries, dict, len });
                }
                token => return Err(DataSetSyntaxError::UnexpectedToken(token).into()),
            };
            entries.insert(elem.tag(), elem);
        }

        Ok(InMemDicomObject { entries, dict, len })
    }

    /// Build a DICOM sequence by consuming a data set parser.
    fn build_sequence<'s, S: 's, P>(
        _tag: Tag,
        _len: Length,
        dataset: &mut DataSetReader<S, P, D>,
        dict: &D,
    ) -> Result<C<InMemDicomObject<D>>>
    where
        S: Read,
        P: Parse<dyn Read + 's>,
    {
        let mut items: C<_> = SmallVec::new();
        while let Some(token) = dataset.next() {
            match token? {
                DataToken::ItemStart { len } => {
                    // TODO if length is well defined, then it should be
                    // considered instead of finding the item delimiter.
                    items.push(Self::build_object(&mut *dataset, dict.clone(), true, len)?);
                }
                DataToken::SequenceEnd => {
                    return Ok(items);
                }
                token => return Err(DataSetSyntaxError::UnexpectedToken(token).into()),
            };
        }

        // iterator fully consumed without a sequence delimiter
        Err(DataSetSyntaxError::PrematureEnd.into())
    }

    fn lookup_name(&self, name: &str) -> Result<Tag> {
        self.dict
            .by_name(name)
            .ok_or(Error::NoSuchAttributeName)
            .map(|e| e.tag())
    }
}

impl<'a, D> IntoIterator for &'a InMemDicomObject<D> {
    type Item = &'a InMemElement<D>;
    type IntoIter = ::std::collections::btree_map::Values<'a, Tag, InMemElement<D>>;

    fn into_iter(self) -> Self::IntoIter {
        self.entries.values()
    }
}

impl<D> IntoIterator for InMemDicomObject<D> {
    type Item = InMemElement<D>;
    type IntoIter = Iter<D>;

    fn into_iter(self) -> Self::IntoIter {
        Iter {
            inner: self.entries.into_iter(),
        }
    }
}

#[derive(Debug)]
pub struct Iter<D> {
    inner: ::std::collections::btree_map::IntoIter<Tag, InMemElement<D>>,
}

impl<D> Iterator for Iter<D> {
    type Item = InMemElement<D>;

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next().map(|x| x.1)
    }

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

    fn count(self) -> usize {
        self.inner.count()
    }
}

#[cfg(test)]
mod tests {

    use super::*;
    use dicom_core::value::PrimitiveValue;
    use dicom_core::VR;

    #[test]
    fn inmem_object_write() {
        let mut obj1 = InMemDicomObject::create_empty();
        let mut obj2 = InMemDicomObject::create_empty();
        assert_eq!(obj1, obj2);
        let empty_patient_name = DataElement::empty(Tag(0x0010, 0x0010), VR::PN);
        obj1.put(empty_patient_name.clone());
        assert_ne!(obj1, obj2);
        obj2.put(empty_patient_name.clone());
        assert_eq!(obj1, obj2);
    }

    #[test]
    fn inmem_object_get() {
        let another_patient_name = DataElement::new(
            Tag(0x0010, 0x0010),
            VR::PN,
            PrimitiveValue::Str("Doe^John".to_string()).into(),
        );
        let mut obj = InMemDicomObject::create_empty();
        obj.put(another_patient_name.clone());
        let elem1 = (&obj).element(Tag(0x0010, 0x0010)).unwrap();
        assert_eq!(elem1, &another_patient_name);
    }

    #[test]
    fn inmem_object_get_by_name() {
        let another_patient_name = DataElement::new(
            Tag(0x0010, 0x0010),
            VR::PN,
            PrimitiveValue::Str("Doe^John".to_string()).into(),
        );
        let mut obj = InMemDicomObject::create_empty();
        obj.put(another_patient_name.clone());
        let elem1 = (&obj).element_by_name("PatientName").unwrap();
        assert_eq!(elem1, &another_patient_name);
    }
}
<commit_msg>[object] constructors for arbitrary TS index<commit_after>//! This module contains the implementation for an in-memory DICOM object.

use itertools::Itertools;
use smallvec::SmallVec;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::{BufReader, Read};
use std::path::Path;

use crate::meta::FileMetaTable;
use crate::{DicomObject, RootDicomObject};
use dicom_core::dictionary::{DataDictionary, DictionaryEntry};
use dicom_core::header::Header;
use dicom_core::value::{DicomValueType, Value, ValueType, C};
use dicom_core::{DataElement, Length, Tag, VR};
use dicom_dictionary_std::StandardDataDictionary;
use dicom_encoding::text::SpecificCharacterSet;
use dicom_encoding::transfer_syntax::TransferSyntaxIndex;
use dicom_parser::dataset::{DataSetReader, DataToken};
use dicom_parser::error::{DataSetSyntaxError, Error, Result};
use dicom_parser::parser::Parse;
use dicom_transfer_syntax_registry::TransferSyntaxRegistry;

/// A full in-memory DICOM data element.
pub type InMemElement<D> = DataElement<InMemDicomObject<D>>;

/** A DICOM object that is fully contained in memory.
 */
#[derive(Debug, Clone)]
pub struct InMemDicomObject<D> {
    /// the element map
    entries: BTreeMap<Tag, InMemElement<D>>,
    /// the data dictionary
    dict: D,
    /// The length of the DICOM object in bytes.
    /// It is usually undefined, unless it is part of an item
    /// in a sequence with a specified length in its item header.
    len: Length,
}

impl<'s, D> PartialEq for InMemDicomObject<D> {
    // This implementation ignores the data dictionary.
    fn eq(&self, other: &Self) -> bool {
        self.entries == other.entries
    }
}

impl<D> DicomValueType for InMemDicomObject<D> {
    fn value_type(&self) -> ValueType {
        ValueType::Item
    }

    fn size(&self) -> Length {
        self.len
    }
}

impl<'s, D: 's> DicomObject for &'s InMemDicomObject<D>
where
    D: DataDictionary,
    D: Clone,
{
    type Element = &'s InMemElement<D>;

    fn element(&self, tag: Tag) -> Result<Self::Element> {
        self.entries.get(&tag).ok_or(Error::NoSuchDataElement)
    }

    fn element_by_name(&self, name: &str) -> Result<Self::Element> {
        let tag = self.lookup_name(name)?;
        self.element(tag)
    }
}

impl RootDicomObject<InMemDicomObject<StandardDataDictionary>> {
    /// Create a DICOM object by reading from a file.
    ///
    /// This function assumes the standard file encoding structure: 128-byte
    /// preamble, file meta group, and the rest of the data set.
    pub fn open_file<P: AsRef<Path>>(path: P) -> Result<Self> {
        Self::open_file_with_dict(path, StandardDataDictionary)
    }

    /// Create a DICOM object by reading from a byte source.
    ///
    /// This function assumes the standard file encoding structure without the
    /// preamble: file meta group, followed by the rest of the data set.
    pub fn from_reader<S>(src: S) -> Result<Self>
    where
        S: Read,
    {
        Self::from_reader_with_dict(src, StandardDataDictionary)
    }
}

impl InMemDicomObject<StandardDataDictionary> {
    /// Create a new empty DICOM object.
    pub fn create_empty() -> Self {
        InMemDicomObject {
            entries: BTreeMap::new(),
            dict: StandardDataDictionary,
            len: Length::UNDEFINED,
        }
    }

    /// Construct a DICOM object from an iterator of structured elements.
    pub fn from_element_iter<I>(iter: I) -> Result<Self>
    where
        I: IntoIterator<Item = Result<InMemElement<StandardDataDictionary>>>,
    {
        Self::from_iter_with_dict(iter, StandardDataDictionary)
    }
}

impl<D> RootDicomObject<InMemDicomObject<D>>
where
    D: DataDictionary,
    D: Clone,
{
    /// Create a new empty object, using the given dictionary and
    /// file meta table.
    pub fn new_empty_with_dict_and_meta(dict: D, meta: FileMetaTable) -> Self {
        RootDicomObject {
            meta,
            obj: InMemDicomObject {
                entries: BTreeMap::new(),
                dict,
                len: Length::UNDEFINED,
            },
        }
    }

    /// Create a DICOM object by reading from a file.
    ///
    /// This function assumes the standard file encoding structure: 128-byte
    /// preamble, file meta group, and the rest of the data set.
    pub fn open_file_with_dict<P: AsRef<Path>>(path: P, dict: D) -> Result<Self> {
        Self::open_file_with(path, dict, TransferSyntaxRegistry)
    }

    /// Create a DICOM object by reading from a file.
    ///
    /// This function assumes the standard file encoding structure: 128-byte
    /// preamble, file meta group, and the rest of the data set.
    ///
    /// This function allows you to choose a different transfer syntax index,
    /// but its use is only advised when the built-in transfer syntax registry
    /// is insufficient. Otherwise, please use [`open_file_with_dict`] instead.
    ///
    /// [`open_file_with_dict`]: #method.open_file_with_dict
    pub fn open_file_with<P: AsRef<Path>, R>(path: P, dict: D, ts_index: R) -> Result<Self>
    where
        P: AsRef<Path>,
        R: TransferSyntaxIndex,
    {
        let mut file = BufReader::new(File::open(path)?);

        // skip preamble
        {
            let mut buf = [0u8; 128];
            // skip the preamble
            file.read_exact(&mut buf)?;
        }

        // read metadata header
        let meta = FileMetaTable::from_reader(&mut file)?;

        // read rest of data according to metadata, feed it to object
        let ts = ts_index
            .get(&meta.transfer_syntax)
            .ok_or(Error::UnsupportedTransferSyntax)?;
        let cs = SpecificCharacterSet::Default;
        let mut dataset = DataSetReader::new_with_dictionary(file, dict.clone(), ts, cs)?;

        Ok(RootDicomObject {
            meta,
            obj: InMemDicomObject::build_object(&mut dataset, dict, false, Length::UNDEFINED)?,
        })
    }

    /// Create a DICOM object by reading from a byte source.
    ///
    /// This function assumes the standard file encoding structure without the
    /// preamble: file meta group, followed by the rest of the data set.
    pub fn from_reader_with_dict<S>(src: S, dict: D) -> Result<Self>
    where
        S: Read,
    {
        Self::from_reader_with(src, dict, TransferSyntaxRegistry)
    }

    /// Create a DICOM object by reading from a byte source.
    ///
    /// This function assumes the standard file encoding structure without the
    /// preamble: file meta group, followed by the rest of the data set.
    ///
    /// This function allows you to choose a different transfer syntax index,
    /// but its use is only advised when the built-in transfer syntax registry
    /// is insufficient. Otherwise, please use [`from_reader_with_dict`] instead.
    ///
    /// [`from_reader_with_dict`]: #method.from_reader_with_dict
    pub fn from_reader_with<S, R>(src: S, dict: D, ts_index: R) -> Result<Self>
    where
        S: Read,
        R: TransferSyntaxIndex,
    {
        let mut file = BufReader::new(src);

        // read metadata header
        let meta = FileMetaTable::from_reader(&mut file)?;

        // read rest of data according to metadata, feed it to object
        let ts = ts_index
            .get(&meta.transfer_syntax)
            .ok_or(Error::UnsupportedTransferSyntax)?;
        let cs = SpecificCharacterSet::Default;
        let mut dataset = DataSetReader::new_with_dictionary(file, dict.clone(), ts, cs)?;
        Ok(RootDicomObject {
            meta,
            obj: InMemDicomObject::build_object(&mut dataset, dict, false, Length::UNDEFINED)?,
        })
    }
}

impl<D> InMemDicomObject<D>
where
    D: DataDictionary,
    D: Clone,
{
    /// Create a new empty object, using the given dictionary for name lookup.
    pub fn new_empty_with_dict(dict: D) -> Self {
        InMemDicomObject {
            entries: BTreeMap::new(),
            dict,
            len: Length::UNDEFINED,
        }
    }

    /// Construct a DICOM object from an iterator of structured elements.
    pub fn from_iter_with_dict<I>(iter: I, dict: D) -> Result<Self>
    where
        I: IntoIterator<Item = Result<InMemElement<D>>>,
    {
        let entries: Result<_> = iter.into_iter().map_results(|e| (e.tag(), e)).collect();
        Ok(InMemDicomObject {
            entries: entries?,
            dict,
            len: Length::UNDEFINED,
        })
    }

    // Standard methods follow. They are not placed as a trait implementation
    // because they may require outputs to reference the lifetime of self,
    // which is not possible without GATs.

    /// Retrieve the object's meta table if available.
    ///
    /// At the moment, this is sure to return `None`, because the meta
    /// table is kept in a separate wrapper value.
    pub fn meta(&self) -> Option<&FileMetaTable> {
        None
    }

    /// Retrieve a particular DICOM element by its tag.
    pub fn element(&self, tag: Tag) -> Result<&InMemElement<D>> {
        self.entries.get(&tag).ok_or(Error::NoSuchDataElement)
    }

    /// Retrieve a particular DICOM element by its name.
    pub fn element_by_name(&self, name: &str) -> Result<&InMemElement<D>> {
        let tag = self.lookup_name(name)?;
        self.element(tag)
    }

    /// Insert a data element to the object, replacing (and returning) any
    /// previous element of the same attribute.
    pub fn put(&mut self, elt: InMemElement<D>) -> Option<InMemElement<D>> {
        self.entries.insert(elt.tag(), elt)
    }

    // private methods

    /// Build an object by consuming a data set parser.
    fn build_object<'s, S: 's, P>(
        dataset: &mut DataSetReader<S, P, D>,
        dict: D,
        in_item: bool,
        len: Length,
    ) -> Result<Self>
    where
        S: Read,
        P: Parse<dyn Read + 's>,
    {
        let mut entries: BTreeMap<Tag, InMemElement<D>> = BTreeMap::new();
        // perform a structured parsing of incoming tokens
        while let Some(token) = dataset.next() {
            let elem = match token? {
                DataToken::ElementHeader(header) => {
                    // fetch respective value, place it in the entries
                    let next_token = dataset.next().ok_or_else(|| Error::MissingElementValue)?;
                    match next_token? {
                        DataToken::PrimitiveValue(v) => {
                            InMemElement::new(header.tag, header.vr, Value::Primitive(v))
                        }
                        token => {
                            return Err(DataSetSyntaxError::UnexpectedToken(token).into());
                        }
                    }
                }
                DataToken::SequenceStart { tag, len } => {
                    // delegate sequence building to another function
                    let items = Self::build_sequence(tag, len, &mut *dataset, &dict)?;
                    DataElement::new(tag, VR::SQ, Value::Sequence { items, size: len })
                }
                DataToken::ItemEnd if in_item => {
                    // end of item, leave now
                    return Ok(InMemDicomObject { entries, dict, len });
                }
                token => return Err(DataSetSyntaxError::UnexpectedToken(token).into()),
            };
            entries.insert(elem.tag(), elem);
        }

        Ok(InMemDicomObject { entries, dict, len })
    }

    /// Build a DICOM sequence by consuming a data set parser.
    fn build_sequence<'s, S: 's, P>(
        _tag: Tag,
        _len: Length,
        dataset: &mut DataSetReader<S, P, D>,
        dict: &D,
    ) -> Result<C<InMemDicomObject<D>>>
    where
        S: Read,
        P: Parse<dyn Read + 's>,
    {
        let mut items: C<_> = SmallVec::new();
        while let Some(token) = dataset.next() {
            match token? {
                DataToken::ItemStart { len } => {
                    // TODO if length is well defined, then it should be
                    // considered instead of finding the item delimiter.
                    items.push(Self::build_object(&mut *dataset, dict.clone(), true, len)?);
                }
                DataToken::SequenceEnd => {
                    return Ok(items);
                }
                token => return Err(DataSetSyntaxError::UnexpectedToken(token).into()),
            };
        }

        // iterator fully consumed without a sequence delimiter
        Err(DataSetSyntaxError::PrematureEnd.into())
    }

    fn lookup_name(&self, name: &str) -> Result<Tag> {
        self.dict
            .by_name(name)
            .ok_or(Error::NoSuchAttributeName)
            .map(|e| e.tag())
    }
}

impl<'a, D> IntoIterator for &'a InMemDicomObject<D> {
    type Item = &'a InMemElement<D>;
    type IntoIter = ::std::collections::btree_map::Values<'a, Tag, InMemElement<D>>;

    fn into_iter(self) -> Self::IntoIter {
        self.entries.values()
    }
}

impl<D> IntoIterator for InMemDicomObject<D> {
    type Item = InMemElement<D>;
    type IntoIter = Iter<D>;

    fn into_iter(self) -> Self::IntoIter {
        Iter {
            inner: self.entries.into_iter(),
        }
    }
}

/// Base iterator type for an in-memory DICOM object.
#[derive(Debug)]
pub struct Iter<D> {
    inner: ::std::collections::btree_map::IntoIter<Tag, InMemElement<D>>,
}

impl<D> Iterator for Iter<D> {
    type Item = InMemElement<D>;

    fn next(&mut self) -> Option<Self::Item> {
        self.inner.next().map(|x| x.1)
    }

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

    fn count(self) -> usize {
        self.inner.count()
    }
}

#[cfg(test)]
mod tests {

    use super::*;
    use dicom_core::value::PrimitiveValue;
    use dicom_core::VR;

    #[test]
    fn inmem_object_write() {
        let mut obj1 = InMemDicomObject::create_empty();
        let mut obj2 = InMemDicomObject::create_empty();
        assert_eq!(obj1, obj2);
        let empty_patient_name = DataElement::empty(Tag(0x0010, 0x0010), VR::PN);
        obj1.put(empty_patient_name.clone());
        assert_ne!(obj1, obj2);
        obj2.put(empty_patient_name.clone());
        assert_eq!(obj1, obj2);
    }

    #[test]
    fn inmem_object_get() {
        let another_patient_name = DataElement::new(
            Tag(0x0010, 0x0010),
            VR::PN,
            PrimitiveValue::Str("Doe^John".to_string()).into(),
        );
        let mut obj = InMemDicomObject::create_empty();
        obj.put(another_patient_name.clone());
        let elem1 = (&obj).element(Tag(0x0010, 0x0010)).unwrap();
        assert_eq!(elem1, &another_patient_name);
    }

    #[test]
    fn inmem_object_get_by_name() {
        let another_patient_name = DataElement::new(
            Tag(0x0010, 0x0010),
            VR::PN,
            PrimitiveValue::Str("Doe^John".to_string()).into(),
        );
        let mut obj = InMemDicomObject::create_empty();
        obj.put(another_patient_name.clone());
        let elem1 = (&obj).element_by_name("PatientName").unwrap();
        assert_eq!(elem1, &another_patient_name);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::relay_directive::RelayDirective;
use fnv::FnvBuildHasher;
use graphql_ir::{
    FragmentDefinition, FragmentSpread, InlineFragment, Program, ScalarField, Selection,
    Transformed, Transformer, VariableDefinition,
};
use indexmap::{map::Entry, IndexMap};
use interner::StringKey;
use std::ops::RangeFull;
use std::sync::Arc;

/// Transform to inline fragment spreads with @relay(mask:false)
pub fn mask<'s>(program: &Program<'s>) -> Program<'s> {
    let mut transform = Mask::new(program);
    transform
        .transform_program(program)
        .replace_or_else(|| program.clone())
}

type JoinedArguments<'s> = IndexMap<StringKey, &'s VariableDefinition, FnvBuildHasher>;

struct Mask<'s> {
    program: &'s Program<'s>,
    current_reachable_arguments: Vec<&'s VariableDefinition>,
}

impl<'s> Mask<'s> {
    fn new(program: &'s Program<'s>) -> Self {
        Self {
            program,
            current_reachable_arguments: vec![],
        }
    }

    fn join_current_arguments_to_fragment(&mut self, fragment: &mut FragmentDefinition) {
        let mut joined_arguments = JoinedArguments::default();
        for variable in &fragment.used_global_variables {
            joined_arguments.insert(variable.name.item, variable);
        }
        for arg in self.current_reachable_arguments.drain(..) {
            match joined_arguments.entry(arg.name.item) {
                Entry::Vacant(entry) => {
                    entry.insert(arg);
                }
                Entry::Occupied(mut entry) => {
                    let prev_arg = entry.get();
                    if self
                        .program
                        .schema()
                        .is_type_subtype_of(&arg.type_, &prev_arg.type_)
                    {
                        entry.insert(arg);
                    }
                }
            }
        }
        let range = RangeFull;
        fragment.used_global_variables = joined_arguments
            .drain(range)
            .map(|(_, v)| v)
            .cloned()
            .collect();
    }
}

impl<'s> Transformer for Mask<'s> {
    const NAME: &'static str = "MaskTransform";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        let result = self.default_transform_fragment(fragment);
        if self.current_reachable_arguments.is_empty() {
            result
        } else {
            Transformed::Replace(match result {
                Transformed::Keep => {
                    let mut new_fragment = fragment.clone();
                    self.join_current_arguments_to_fragment(&mut new_fragment);
                    new_fragment
                }
                Transformed::Replace(mut new_fragment) => {
                    self.join_current_arguments_to_fragment(&mut new_fragment);
                    new_fragment
                }
                Transformed::Delete => {
                    panic!("Unexpected fragment deletion in mask transform.");
                }
            })
        }
    }

    fn transform_fragment_spread(&mut self, spread: &FragmentSpread) -> Transformed<Selection> {
        if RelayDirective::is_unmasked_fragment_spread(spread) {
            let fragment = self.program.fragment(spread.fragment.item).unwrap();
            self.current_reachable_arguments
                .extend(&fragment.used_global_variables);
            Transformed::Replace(Selection::InlineFragment(Arc::new(InlineFragment {
                type_condition: Some(fragment.type_condition),
                directives: vec![],
                selections: self
                    .transform_selections(&fragment.selections)
                    .replace_or_else(|| fragment.selections.to_vec()),
            })))
        } else {
            Transformed::Keep
        }
    }

    fn transform_scalar_field(&mut self, _field: &ScalarField) -> Transformed<Selection> {
        Transformed::Keep
    }
}
<commit_msg>Fix mask argumentDefinitions<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use crate::relay_directive::RelayDirective;
use fnv::FnvBuildHasher;
use graphql_ir::{
    FragmentDefinition, FragmentSpread, InlineFragment, Program, ScalarField, Selection,
    Transformed, Transformer, VariableDefinition,
};
use indexmap::{map::Entry, IndexMap};
use interner::StringKey;
use std::sync::Arc;

/// Transform to inline fragment spreads with @relay(mask:false)
pub fn mask<'s>(program: &Program<'s>) -> Program<'s> {
    let mut transform = Mask::new(program);
    transform
        .transform_program(program)
        .replace_or_else(|| program.clone())
}

type JoinedArguments<'s> = IndexMap<StringKey, &'s VariableDefinition, FnvBuildHasher>;

struct Mask<'s> {
    program: &'s Program<'s>,
}

impl<'s> Mask<'s> {
    fn new(program: &'s Program<'s>) -> Self {
        Self { program }
    }
}

impl<'s> Transformer for Mask<'s> {
    const NAME: &'static str = "MaskTransform";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        let mut mask_fragment = MaskFragment::new(self.program);
        mask_fragment.transform_fragment(fragment)
    }
}

struct MaskFragment<'s> {
    program: &'s Program<'s>,
    current_reachable_arguments: Vec<&'s VariableDefinition>,
}

impl<'s> MaskFragment<'s> {
    fn new(program: &'s Program<'s>) -> Self {
        Self {
            program,
            current_reachable_arguments: vec![],
        }
    }

    fn join_current_arguments_to_fragment(&mut self, fragment: &mut FragmentDefinition) {
        let mut joined_arguments = JoinedArguments::default();
        for variable in &fragment.used_global_variables {
            joined_arguments.insert(variable.name.item, variable);
        }
        for arg in self.current_reachable_arguments.drain(..) {
            match joined_arguments.entry(arg.name.item) {
                Entry::Vacant(entry) => {
                    entry.insert(arg);
                }
                Entry::Occupied(mut entry) => {
                    let prev_arg = entry.get();
                    if self
                        .program
                        .schema()
                        .is_type_subtype_of(&arg.type_, &prev_arg.type_)
                    {
                        entry.insert(arg);
                    }
                }
            }
        }
        fragment.used_global_variables = joined_arguments
            .into_iter()
            .map(|(_, v)| v)
            .cloned()
            .collect();
    }
}

impl<'s> Transformer for MaskFragment<'s> {
    const NAME: &'static str = "MaskFragmentTransform";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        let result = self.default_transform_fragment(fragment);
        if self.current_reachable_arguments.is_empty() {
            result
        } else {
            Transformed::Replace(match result {
                Transformed::Keep => {
                    let mut new_fragment = fragment.clone();
                    self.join_current_arguments_to_fragment(&mut new_fragment);
                    new_fragment
                }
                Transformed::Replace(mut new_fragment) => {
                    self.join_current_arguments_to_fragment(&mut new_fragment);
                    new_fragment
                }
                Transformed::Delete => {
                    panic!("Unexpected fragment deletion in mask transform.");
                }
            })
        }
    }

    fn transform_fragment_spread(&mut self, spread: &FragmentSpread) -> Transformed<Selection> {
        if RelayDirective::is_unmasked_fragment_spread(spread) {
            let fragment = self.program.fragment(spread.fragment.item).unwrap();
            self.current_reachable_arguments
                .extend(&fragment.used_global_variables);
            Transformed::Replace(Selection::InlineFragment(Arc::new(InlineFragment {
                type_condition: Some(fragment.type_condition),
                directives: vec![],
                selections: self
                    .transform_selections(&fragment.selections)
                    .replace_or_else(|| fragment.selections.to_vec()),
            })))
        } else {
            Transformed::Keep
        }
    }

    fn transform_scalar_field(&mut self, _field: &ScalarField) -> Transformed<Selection> {
        Transformed::Keep
    }
}
<|endoftext|>


<commit_before>use crate::stable_hasher::{HashStable, StableHasher};

use std::iter::FromIterator;

/// A vector type optimized for cases where this size is usually 0 (cf. `SmallVector`).
/// The `Option<Box<..>>` wrapping allows us to represent a zero sized vector with `None`,
/// which uses only a single (null) pointer.
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct ThinVec<T>(Option<Box<Vec<T>>>);

impl<T> ThinVec<T> {
    pub fn new() -> Self {
        ThinVec(None)
    }

    pub fn iter(&self) -> std::slice::Iter<'_, T> {
        self.into_iter()
    }

    pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
        self.into_iter()
    }
}

impl<T> From<Vec<T>> for ThinVec<T> {
    fn from(vec: Vec<T>) -> Self {
        if vec.is_empty() { ThinVec(None) } else { ThinVec(Some(Box::new(vec))) }
    }
}

impl<T> Into<Vec<T>> for ThinVec<T> {
    fn into(self) -> Vec<T> {
        match self {
            ThinVec(None) => Vec::new(),
            ThinVec(Some(vec)) => *vec,
        }
    }
}

impl<T> ::std::ops::Deref for ThinVec<T> {
    type Target = [T];
    fn deref(&self) -> &[T] {
        match *self {
            ThinVec(None) => &[],
            ThinVec(Some(ref vec)) => vec,
        }
    }
}

impl<T> ::std::ops::DerefMut for ThinVec<T> {
    fn deref_mut(&mut self) -> &mut [T] {
        match *self {
            ThinVec(None) => &mut [],
            ThinVec(Some(ref mut vec)) => vec,
        }
    }
}

impl<T> FromIterator<T> for ThinVec<T> {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
        // `Vec::from_iter()` should not allocate if the iterator is empty.
        let vec: Vec<_> = iter.into_iter().collect();
        if vec.is_empty() { ThinVec(None) } else { ThinVec(Some(Box::new(vec))) }
    }
}

impl<T> IntoIterator for ThinVec<T> {
    type Item = T;
    type IntoIter = std::vec::IntoIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        // This is still performant because `Vec::new()` does not allocate.
        self.0.map_or_else(Vec::new, |ptr| *ptr).into_iter()
    }
}

impl<'a, T> IntoIterator for &'a ThinVec<T> {
    type Item = &'a T;
    type IntoIter = std::slice::Iter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.as_ref().iter()
    }
}

impl<'a, T> IntoIterator for &'a mut ThinVec<T> {
    type Item = &'a mut T;
    type IntoIter = std::slice::IterMut<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.as_mut().iter_mut()
    }
}

impl<T> Extend<T> for ThinVec<T> {
    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
        match *self {
            ThinVec(Some(ref mut vec)) => vec.extend(iter),
            ThinVec(None) => *self = iter.into_iter().collect::<Vec<_>>().into(),
        }
    }

    fn extend_one(&mut self, item: T) {
        match *self {
            ThinVec(Some(ref mut vec)) => vec.push(item),
            ThinVec(None) => *self = vec![item].into(),
        }
    }

    fn extend_reserve(&mut self, additional: usize) {
        match *self {
            ThinVec(Some(ref mut vec)) => vec.reserve(additional),
            ThinVec(None) => *self = Vec::with_capacity(additional).into(),
        }
    }
}

impl<T: HashStable<CTX>, CTX> HashStable<CTX> for ThinVec<T> {
    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
        (**self).hash_stable(hcx, hasher)
    }
}

impl<T> Default for ThinVec<T> {
    fn default() -> Self {
        Self(None)
    }
}

#[cfg(test)]
mod tests;
<commit_msg>Remove SmallVector mention<commit_after>use crate::stable_hasher::{HashStable, StableHasher};

use std::iter::FromIterator;

/// A vector type optimized for cases where this size is usually 0 (cf. `SmallVec`).
/// The `Option<Box<..>>` wrapping allows us to represent a zero sized vector with `None`,
/// which uses only a single (null) pointer.
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct ThinVec<T>(Option<Box<Vec<T>>>);

impl<T> ThinVec<T> {
    pub fn new() -> Self {
        ThinVec(None)
    }

    pub fn iter(&self) -> std::slice::Iter<'_, T> {
        self.into_iter()
    }

    pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
        self.into_iter()
    }
}

impl<T> From<Vec<T>> for ThinVec<T> {
    fn from(vec: Vec<T>) -> Self {
        if vec.is_empty() { ThinVec(None) } else { ThinVec(Some(Box::new(vec))) }
    }
}

impl<T> Into<Vec<T>> for ThinVec<T> {
    fn into(self) -> Vec<T> {
        match self {
            ThinVec(None) => Vec::new(),
            ThinVec(Some(vec)) => *vec,
        }
    }
}

impl<T> ::std::ops::Deref for ThinVec<T> {
    type Target = [T];
    fn deref(&self) -> &[T] {
        match *self {
            ThinVec(None) => &[],
            ThinVec(Some(ref vec)) => vec,
        }
    }
}

impl<T> ::std::ops::DerefMut for ThinVec<T> {
    fn deref_mut(&mut self) -> &mut [T] {
        match *self {
            ThinVec(None) => &mut [],
            ThinVec(Some(ref mut vec)) => vec,
        }
    }
}

impl<T> FromIterator<T> for ThinVec<T> {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
        // `Vec::from_iter()` should not allocate if the iterator is empty.
        let vec: Vec<_> = iter.into_iter().collect();
        if vec.is_empty() { ThinVec(None) } else { ThinVec(Some(Box::new(vec))) }
    }
}

impl<T> IntoIterator for ThinVec<T> {
    type Item = T;
    type IntoIter = std::vec::IntoIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        // This is still performant because `Vec::new()` does not allocate.
        self.0.map_or_else(Vec::new, |ptr| *ptr).into_iter()
    }
}

impl<'a, T> IntoIterator for &'a ThinVec<T> {
    type Item = &'a T;
    type IntoIter = std::slice::Iter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.as_ref().iter()
    }
}

impl<'a, T> IntoIterator for &'a mut ThinVec<T> {
    type Item = &'a mut T;
    type IntoIter = std::slice::IterMut<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.as_mut().iter_mut()
    }
}

impl<T> Extend<T> for ThinVec<T> {
    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
        match *self {
            ThinVec(Some(ref mut vec)) => vec.extend(iter),
            ThinVec(None) => *self = iter.into_iter().collect::<Vec<_>>().into(),
        }
    }

    fn extend_one(&mut self, item: T) {
        match *self {
            ThinVec(Some(ref mut vec)) => vec.push(item),
            ThinVec(None) => *self = vec![item].into(),
        }
    }

    fn extend_reserve(&mut self, additional: usize) {
        match *self {
            ThinVec(Some(ref mut vec)) => vec.reserve(additional),
            ThinVec(None) => *self = Vec::with_capacity(additional).into(),
        }
    }
}

impl<T: HashStable<CTX>, CTX> HashStable<CTX> for ThinVec<T> {
    fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
        (**self).hash_stable(hcx, hasher)
    }
}

impl<T> Default for ThinVec<T> {
    fn default() -> Self {
        Self(None)
    }
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>use seed::prelude::*;
use crate::Msg;

mod perfects_utils {
	pub struct Perfect<'a> {
		pub n: u64,
		pub p: u64,
		pub digits: u64,
		pub discovery: &'a str,
	}

	pub fn perfects<'a>() -> Vec<Perfect<'a>> {
        vec![
			Perfect {n: 51, p: 82589934, digits: 49724095, discovery: "2018 Laroche, Woltman, Kurowski, Blosser, et al."},
			Perfect {n: 50, p: 77232917, digits: 46498850, discovery: "2017 Jonathan Pace, George Woltman, Scott Kurowski, Aaron Blosser, et al.." },
			Perfect {n: 49, p: 74207281, digits: 44677235, discovery: "2016 Cooper, Woltman, Kurowski, Blosser et al." },
			Perfect {n: 48, p: 57885161, digits: 34850340, discovery: "2013 Cooper, Woltman, Kurowski, et al." },
			Perfect {n: 47, p: 43112609, digits: 25956377, discovery: "2008 Smith, Woltman, Kurowski, et al." },
			Perfect {n: 46, p: 42643801, digits: 42643801, discovery: "2009 Strindmo, Woltman, Kurowski, et al." },
			Perfect {n: 45, p: 37156667, digits: 22370543, discovery: "2008 Elvenich, Woltman, Kurowski, et al." },
			Perfect {n: 44, p: 32582657, digits: 19616714, discovery: "2006 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 43, p: 30402457, digits: 18304103, discovery: "2005 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 42, p: 25964951, digits: 15632458, discovery: "2005 Nowak, Woltman, Kurowski, et. al." },
			Perfect {n: 41, p: 24036583, digits: 14471465, discovery: "2004 Findley, Woltman, Kurowski, et. al." },
			Perfect {n: 40, p: 20996011, digits: 12640858, discovery: "2003 Shafer, Woltman, Kurowski, et. al." },
			Perfect {n: 39, p: 13466917, digits: 8107892, discovery: "2001 Cameron, Woltman, Kurowski, et. al." },
			Perfect {n: 38, p: 6972593, digits: 4197919, discovery: "1999 Hajratwala, Woltman, Kurowski, et. al." },
			Perfect {n: 37, p: 3021377, digits: 1819050, discovery: "1998 Clarkson, Woltman, Kurowski, et. al." },
			Perfect {n: 36, p: 2976221, digits: 1791864, discovery: "1997 Spence, Woltman, et. al." },
			Perfect {n: 35, p: 1398269, digits: 841842, discovery: "1996 Armengaud, Woltman, et. al." },
			Perfect {n: 34, p: 1257787, digits: 757263, discovery: "1996 Slowinski&Gage" },
			Perfect {n: 33, p: 859433, digits: 517430, discovery: "1994 Slowinski&Gage" },
			Perfect {n: 32, p: 756839, digits: 455663, discovery: "1992 Slowinski&Gage" },
			Perfect {n: 31, p: 216091, digits: 130100, discovery: "1985 Slowinski" },
			Perfect {n: 30, p: 132049, digits: 79502, discovery: "1983 Slowinski" },
			Perfect {n: 29, p: 110503, digits: 66530, discovery: "1988 Colquitt&Welsh" },
			Perfect {n: 28, p: 86243, digits: 51924, discovery: "1982 Slowinski" },
			Perfect {n: 27, p: 44497, digits: 26790, discovery: "1979 Nelson&Slowinski" },
			Perfect {n: 26, p: 23209, digits: 13973, discovery: "1979 Noll" },
			Perfect {n: 25, p: 21701, digits: 13066, discovery: "1978 Noll&Nickel" },
			Perfect {n: 24, p: 19937, digits: 12003, discovery: "1971 Tuckerman" },
			Perfect {n: 23, p: 11213, digits: 6751, discovery: "1963 Gillies" },
			Perfect {n: 22, p: 9941, digits: 5985, discovery: "1963 Gillies" },
			Perfect {n: 21, p: 9689, digits: 5834, discovery: "1963 Gillies" },
			Perfect {n: 20, p: 4423, digits: 2663, discovery: "1961 Hurwitz" },
			Perfect {n: 19, p: 4253, digits: 2561, discovery: "1961 Hurwitz" },
			Perfect {n: 18, p: 3217, digits: 1937, discovery: "1957 Riesel" },
			Perfect {n: 17, p: 2281, digits: 1373, discovery: "1952 Robinson" },
			Perfect {n: 16, p: 2203, digits: 1327, discovery: "1952 Robinson" },
			Perfect {n: 15, p: 1279, digits: 770, discovery: "1952 Robinson" },
			Perfect {n: 14, p: 607, digits: 366, discovery: "1952 Robinson" },
			Perfect {n: 13, p: 521, digits: 314, discovery: "1952 Robinson" },
			Perfect {n: 12, p: 127, digits: 77, discovery: "1876 Lucas" },
			Perfect {n: 11, p: 107, digits: 65, discovery: "1914 Powers" },
			Perfect {n: 10, p: 89, digits: 54, discovery: "1911 Powers" },
			Perfect {n: 9, p: 61, digits: 37, discovery: "1883 Pervushin" },
			Perfect {n: 8, p: 31, digits: 19, discovery: "1772 Euler" },
			Perfect {n: 7, p: 19, digits: 12, discovery: "1588 Cataldi" },
			Perfect {n: 6, p: 17, digits: 10, discovery: "1588 Cataldi" },
			Perfect {n: 5, p: 13, digits: 8, discovery: "1456 ?" },
			Perfect {n: 4, p: 7, digits: 4, discovery: "?" },
			Perfect {n: 3, p: 5, digits: 3, discovery: "?" },
			Perfect {n: 2, p: 3, digits: 2, discovery: "?" },
			Perfect {n: 1, p: 3, digits: 1, discovery: "?" },
		]
	}
}

pub fn render() -> seed::dom_types::Node<Msg> {
    let mut html = vec![];

    let perfects = perfects_utils::perfects();

    for n in 0..perfects.len() {
        let download_txt:String = vec!["https://static.bigprimes.net/archive/perfect/",&perfects[n].n.to_string(),".txt"].into_iter().collect();

		let equation:String = vec!["2",&(perfects[n].p-1).to_string()," × (2",&(perfects[n].p).to_string(),"-1)"].into_iter().collect();

        html.push(
            tr![
                td![perfects[n].n.to_string()],//rank
				td![El::from_html(&equation)],//perfect number as a formula

                td![perfects[n].digits.to_string()],//digits in length
                td![perfects[n].discovery],//disocvery
                a![attrs!{At::Href => download_txt},"TXT"]//downloads
            ]
        );
    }

    div![
        h1!["The Perfect Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "perfecttable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

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

    #[test]
    fn perfect_test<'a>() {
        let mut perfects:Vec<perfects_utils::Perfect<'a>> = perfects_utils::perfects();
		perfects.reverse();
        assert_eq!(perfects[49].digits, 46498850);
        assert_eq!(perfects[39].digits, 12640858);
    }
}<commit_msg>Now using format!()<commit_after>use seed::prelude::*;
use crate::Msg;

mod perfects_utils {
	pub struct Perfect<'a> {
		pub n: u64,
		pub p: u64,
		pub digits: u64,
		pub discovery: &'a str,
	}

	pub fn perfects<'a>() -> Vec<Perfect<'a>> {
        vec![
			Perfect {n: 51, p: 82589934, digits: 49724095, discovery: "2018 Laroche, Woltman, Kurowski, Blosser, et al."},
			Perfect {n: 50, p: 77232917, digits: 46498850, discovery: "2017 Jonathan Pace, George Woltman, Scott Kurowski, Aaron Blosser, et al.." },
			Perfect {n: 49, p: 74207281, digits: 44677235, discovery: "2016 Cooper, Woltman, Kurowski, Blosser et al." },
			Perfect {n: 48, p: 57885161, digits: 34850340, discovery: "2013 Cooper, Woltman, Kurowski, et al." },
			Perfect {n: 47, p: 43112609, digits: 25956377, discovery: "2008 Smith, Woltman, Kurowski, et al." },
			Perfect {n: 46, p: 42643801, digits: 42643801, discovery: "2009 Strindmo, Woltman, Kurowski, et al." },
			Perfect {n: 45, p: 37156667, digits: 22370543, discovery: "2008 Elvenich, Woltman, Kurowski, et al." },
			Perfect {n: 44, p: 32582657, digits: 19616714, discovery: "2006 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 43, p: 30402457, digits: 18304103, discovery: "2005 Cooper, Boone, Woltman, Kurowski, et al." },
			Perfect {n: 42, p: 25964951, digits: 15632458, discovery: "2005 Nowak, Woltman, Kurowski, et. al." },
			Perfect {n: 41, p: 24036583, digits: 14471465, discovery: "2004 Findley, Woltman, Kurowski, et. al." },
			Perfect {n: 40, p: 20996011, digits: 12640858, discovery: "2003 Shafer, Woltman, Kurowski, et. al." },
			Perfect {n: 39, p: 13466917, digits: 8107892, discovery: "2001 Cameron, Woltman, Kurowski, et. al." },
			Perfect {n: 38, p: 6972593, digits: 4197919, discovery: "1999 Hajratwala, Woltman, Kurowski, et. al." },
			Perfect {n: 37, p: 3021377, digits: 1819050, discovery: "1998 Clarkson, Woltman, Kurowski, et. al." },
			Perfect {n: 36, p: 2976221, digits: 1791864, discovery: "1997 Spence, Woltman, et. al." },
			Perfect {n: 35, p: 1398269, digits: 841842, discovery: "1996 Armengaud, Woltman, et. al." },
			Perfect {n: 34, p: 1257787, digits: 757263, discovery: "1996 Slowinski&Gage" },
			Perfect {n: 33, p: 859433, digits: 517430, discovery: "1994 Slowinski&Gage" },
			Perfect {n: 32, p: 756839, digits: 455663, discovery: "1992 Slowinski&Gage" },
			Perfect {n: 31, p: 216091, digits: 130100, discovery: "1985 Slowinski" },
			Perfect {n: 30, p: 132049, digits: 79502, discovery: "1983 Slowinski" },
			Perfect {n: 29, p: 110503, digits: 66530, discovery: "1988 Colquitt&Welsh" },
			Perfect {n: 28, p: 86243, digits: 51924, discovery: "1982 Slowinski" },
			Perfect {n: 27, p: 44497, digits: 26790, discovery: "1979 Nelson&Slowinski" },
			Perfect {n: 26, p: 23209, digits: 13973, discovery: "1979 Noll" },
			Perfect {n: 25, p: 21701, digits: 13066, discovery: "1978 Noll&Nickel" },
			Perfect {n: 24, p: 19937, digits: 12003, discovery: "1971 Tuckerman" },
			Perfect {n: 23, p: 11213, digits: 6751, discovery: "1963 Gillies" },
			Perfect {n: 22, p: 9941, digits: 5985, discovery: "1963 Gillies" },
			Perfect {n: 21, p: 9689, digits: 5834, discovery: "1963 Gillies" },
			Perfect {n: 20, p: 4423, digits: 2663, discovery: "1961 Hurwitz" },
			Perfect {n: 19, p: 4253, digits: 2561, discovery: "1961 Hurwitz" },
			Perfect {n: 18, p: 3217, digits: 1937, discovery: "1957 Riesel" },
			Perfect {n: 17, p: 2281, digits: 1373, discovery: "1952 Robinson" },
			Perfect {n: 16, p: 2203, digits: 1327, discovery: "1952 Robinson" },
			Perfect {n: 15, p: 1279, digits: 770, discovery: "1952 Robinson" },
			Perfect {n: 14, p: 607, digits: 366, discovery: "1952 Robinson" },
			Perfect {n: 13, p: 521, digits: 314, discovery: "1952 Robinson" },
			Perfect {n: 12, p: 127, digits: 77, discovery: "1876 Lucas" },
			Perfect {n: 11, p: 107, digits: 65, discovery: "1914 Powers" },
			Perfect {n: 10, p: 89, digits: 54, discovery: "1911 Powers" },
			Perfect {n: 9, p: 61, digits: 37, discovery: "1883 Pervushin" },
			Perfect {n: 8, p: 31, digits: 19, discovery: "1772 Euler" },
			Perfect {n: 7, p: 19, digits: 12, discovery: "1588 Cataldi" },
			Perfect {n: 6, p: 17, digits: 10, discovery: "1588 Cataldi" },
			Perfect {n: 5, p: 13, digits: 8, discovery: "1456 ?" },
			Perfect {n: 4, p: 7, digits: 4, discovery: "?" },
			Perfect {n: 3, p: 5, digits: 3, discovery: "?" },
			Perfect {n: 2, p: 3, digits: 2, discovery: "?" },
			Perfect {n: 1, p: 3, digits: 1, discovery: "?" },
		]
	}
}

pub fn render() -> seed::dom_types::Node<Msg> {
    let mut html = vec![];

    let perfects = perfects_utils::perfects();

    for n in 0..perfects.len() {
        let download_txt:String = format!("https://static.bigprimes.net/archive/perfect/{}.txt",&perfects[n].n.to_string());

		let equation:String = format!("2{} × (2{}-1)",&(perfects[n].p-1).to_string(),&(perfects[n].p).to_string());

        html.push(
            tr![
                td![perfects[n].n.to_string()],//rank
				td![El::from_html(&equation)],//perfect number as a formula

                td![perfects[n].digits.to_string()],//digits in length
                td![perfects[n].discovery],//disocvery
                a![attrs!{At::Href => download_txt},"TXT"]//downloads
            ]
        );
    }

    div![
        h1!["The Perfect Numbers"],
        br![],
        br![],
        br![],
        table![
            attrs!{At::Class => "perfecttable text"},
            tbody![
                tr![
                    td![
                        b!["No."]
                    ],
                    td![
                        b!["Prime"]
                    ],
                    td![
                        b!["Digits"]
                    ],
                    td![
                        b!["Discovered"]
                    ],
                    td![
                        b!["Download"]
                    ]
                ],
                html
            ]
        ]
    ]
}

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

    #[test]
    fn perfect_test<'a>() {
        let mut perfects:Vec<perfects_utils::Perfect<'a>> = perfects_utils::perfects();
		perfects.reverse();
        assert_eq!(perfects[49].digits, 46498850);
        assert_eq!(perfects[39].digits, 12640858);
    }
}<|endoftext|>


<commit_before>use std::sync::Arc;
use std::path::Path;
use std::fmt::Debug;
use num::Zero;
use std::ops::{AddAssign, Div, Mul};

use {Clampable, Point2i};
use fileutil;
use interaction::SurfaceInteraction;
use imageio::read_image;
use mipmap::{MIPMap, WrapMode};
use spectrum::Spectrum;
use texture::{Texture, TextureMapping2D, UVMapping2D};
use paramset::TextureParams;
use transform::Transform;

#[derive(Debug)]
pub struct ImageTexture<T> {
    mapping: Box<TextureMapping2D>,
    mipmap: Arc<MIPMap<T>>,
}

impl<T> ImageTexture<T>
where
    T: Zero,
    T: Clone,
    T: Copy,
    T: Clampable,
    T: Debug,
    T: AddAssign<T>,
    T: Mul<f32, Output = T>,
    T: Div<f32, Output = T>,
    T: Sized,
    T: Send + Sync,
{
    pub fn new<F: Fn(&Spectrum) -> T>(
        path: &Path,
        wrap_mode: WrapMode,
        trilerp: bool,
        max_aniso: f32,
        scale: f32,
        gamma: bool,
        map: Box<TextureMapping2D>,
        convert: F,
    ) -> ImageTexture<T> {
        debug!("Loading texture {}", path.display());
        let (res, texels) = match read_image(path) {
            Ok((mut pixels, res)) => {
                // Flip image in y; texture coordinate space has (0,0) at the lower
                // left corner.
                for y in 0..res.y / 2 {
                    for x in 0..res.x {
                        let o1 = (y * res.x + x) as usize;
                        let o2 = ((res.y - 1 - y) * res.x + x) as usize;
                        pixels.swap(o1, o2);
                    }
                }

                (res, pixels)
            }
            Err(e) => {
                warn!(
                    "Could not open texture file. Using grey texture instead: {}",
                    e
                );
                (Point2i::new(1, 1), vec![Spectrum::grey(0.18)])
            }
        };

        let converted_texels: Vec<T> = texels
            .iter()
            .map(|p| {
                let s = if gamma {
                    scale * p.inverse_gamma_correct()
                } else {
                    scale * *p
                };
                convert(&s)
            })
            .collect();

        ImageTexture {
            mapping: map,
            mipmap: Arc::new(MIPMap::new(
                &res,
                &converted_texels[..],
                trilerp,
                max_aniso,
                wrap_mode,
            )),
        }
    }
}

impl ImageTexture<Spectrum> {
    pub fn create(_tex2world: &Transform, tp: &TextureParams) -> ImageTexture<Spectrum> {
        let typ = tp.find_string("mapping", "uv");
        let map = if typ == "uv" {
            let su = tp.find_float("uscale", 1.0);
            let sv = tp.find_float("vscale", 1.0);
            let du = tp.find_float("udelta", 0.0);
            let dv = tp.find_float("vdelta", 0.0);

            UVMapping2D::new(su, sv, du, dv)
        } else {
            unimplemented!()
        };
        let max_aniso = tp.find_float("maxanisotropy", 8.0);
        let trilerp = tp.find_bool("trilinear", false);
        let wrap = tp.find_string("wrap", "repeat");
        let wrap_mode = if wrap == "black" {
            WrapMode::Black
        } else if wrap == "clamp" {
            WrapMode::Clamp
        } else {
            WrapMode::Repeat
        };
        let scale = tp.find_float("scale", 1.0);
        let filename = tp.find_filename("filename", "");
        let gamma = tp.find_bool(
            "gamma",
            fileutil::has_extension(&filename, "tga") || fileutil::has_extension(&filename, "png"),
        );

        Self::new(
            Path::new(&filename),
            wrap_mode,
            trilerp,
            max_aniso,
            scale,
            gamma,
            Box::new(map),
            convert_to_spectrum,
        )
    }
}

impl ImageTexture<f32> {
    pub fn create(_tex2world: &Transform, tp: &TextureParams) -> ImageTexture<f32> {
        let typ = tp.find_string("mapping", "uv");
        let map = if typ == "uv" {
            let su = tp.find_float("uscale", 1.0);
            let sv = tp.find_float("vscale", 1.0);
            let du = tp.find_float("udelta", 0.0);
            let dv = tp.find_float("vdelta", 0.0);

            UVMapping2D::new(su, sv, du, dv)
        } else {
            unimplemented!()
        };
        let max_aniso = tp.find_float("maxanisotropy", 8.0);
        let trilerp = tp.find_bool("trilinear", false);
        let wrap = tp.find_string("wrap", "repeat");
        let wrap_mode = if wrap == "black" {
            WrapMode::Black
        } else if wrap == "clamp" {
            WrapMode::Clamp
        } else {
            WrapMode::Repeat
        };
        let scale = tp.find_float("scale", 1.0);
        let filename = tp.find_filename("filename", "");
        let gamma = tp.find_bool(
            "gamma",
            fileutil::has_extension(&filename, "tga") || fileutil::has_extension(&filename, "png"),
        );

        Self::new(
            Path::new(&filename),
            wrap_mode,
            trilerp,
            max_aniso,
            scale,
            gamma,
            Box::new(map),
            convert_to_float,
        )
    }
}
fn convert_to_spectrum(from: &Spectrum) -> Spectrum {
    *from
}

fn convert_to_float(from: &Spectrum) -> f32 {
    from.y()
}

impl<T> Texture<T> for ImageTexture<T>
where
    T: Zero,
    T: Clone,
    T: Copy,
    T: Send,
    T: Sync,
    T: Clampable,
    T: Debug,
    T: AddAssign<T>,
    T: Mul<f32, Output = T>,
    T: Div<f32, Output = T>,
    T: Sized,
{
    fn evaluate(&self, si: &SurfaceInteraction) -> T {
        let (st, dstdx, dstdy) = self.mapping.map(si);
        self.mipmap.lookup_diff(&st, &dstdx, &dstdy)
    }
}
<commit_msg>Add a method to dump a mipmap to disk<commit_after>use std::sync::Arc;
use std::path::Path;
use std::fmt::Debug;
use num::Zero;
use std::ops::{AddAssign, Div, Mul};

use {Clampable, Point2i};
use fileutil;
use bounds::Bounds2i;
use interaction::SurfaceInteraction;
use imageio::read_image;
use mipmap::{MIPMap, WrapMode};
use spectrum::Spectrum;
use texture::{Texture, TextureMapping2D, UVMapping2D};
use paramset::TextureParams;
use transform::Transform;

#[derive(Debug)]
pub struct ImageTexture<T> {
    mapping: Box<TextureMapping2D>,
    mipmap: Arc<MIPMap<T>>,
}

impl<T> ImageTexture<T>
where
    T: Zero,
    T: Clone,
    T: Copy,
    T: Clampable,
    T: Debug,
    T: AddAssign<T>,
    T: Mul<f32, Output = T>,
    T: Div<f32, Output = T>,
    T: Sized,
    T: Send + Sync,
{
    pub fn new<F: Fn(&Spectrum) -> T>(
        path: &Path,
        wrap_mode: WrapMode,
        trilerp: bool,
        max_aniso: f32,
        scale: f32,
        gamma: bool,
        map: Box<TextureMapping2D>,
        convert: F,
    ) -> ImageTexture<T> {
        debug!("Loading texture {}", path.display());
        let (res, texels) = match read_image(path) {
            Ok((mut pixels, res)) => {
                // Flip image in y; texture coordinate space has (0,0) at the lower
                // left corner.
                for y in 0..res.y / 2 {
                    for x in 0..res.x {
                        let o1 = (y * res.x + x) as usize;
                        let o2 = ((res.y - 1 - y) * res.x + x) as usize;
                        pixels.swap(o1, o2);
                    }
                }

                (res, pixels)
            }
            Err(e) => {
                warn!(
                    "Could not open texture file. Using grey texture instead: {}",
                    e
                );
                (Point2i::new(1, 1), vec![Spectrum::grey(0.18)])
            }
        };

        let converted_texels: Vec<T> = texels
            .iter()
            .map(|p| {
                let s = if gamma {
                    scale * p.inverse_gamma_correct()
                } else {
                    scale * *p
                };
                convert(&s)
            })
            .collect();

            let mipmap = Arc::new(MIPMap::new(
                &res,
                &converted_texels[..],
                trilerp,
                max_aniso,
                wrap_mode,
            ));
        ImageTexture {
            mapping: map,
            mipmap: mipmap,
        }
    }
}

impl ImageTexture<Spectrum> {
    pub fn create(_tex2world: &Transform, tp: &TextureParams) -> ImageTexture<Spectrum> {
        let typ = tp.find_string("mapping", "uv");
        let map = if typ == "uv" {
            let su = tp.find_float("uscale", 1.0);
            let sv = tp.find_float("vscale", 1.0);
            let du = tp.find_float("udelta", 0.0);
            let dv = tp.find_float("vdelta", 0.0);

            UVMapping2D::new(su, sv, du, dv)
        } else {
            unimplemented!()
        };
        let max_aniso = tp.find_float("maxanisotropy", 8.0);
        let trilerp = tp.find_bool("trilinear", false);
        let wrap = tp.find_string("wrap", "repeat");
        let wrap_mode = if wrap == "black" {
            WrapMode::Black
        } else if wrap == "clamp" {
            WrapMode::Clamp
        } else {
            WrapMode::Repeat
        };
        let scale = tp.find_float("scale", 1.0);
        let filename = tp.find_filename("filename", "");
        let gamma = tp.find_bool(
            "gamma",
            fileutil::has_extension(&filename, "tga") || fileutil::has_extension(&filename, "png"),
        );

        Self::new(
            Path::new(&filename),
            wrap_mode,
            trilerp,
            max_aniso,
            scale,
            gamma,
            Box::new(map),
            convert_to_spectrum,
        )
    }

    pub fn dump_mipmap(&self) {
        info!("Dumping MIPMap levels for debugging...");
        self.mipmap.pyramid.iter().enumerate().for_each(|(i, level)| {
            let mut buf = Vec::new();
            for y in 0..level.v_size() {
                for x in 0..level.u_size() {
                    let p = level[(x, y)];
                    buf.push(p[0]);
                    buf.push(p[1]);
                    buf.push(p[2]);
                }
            }
            ::imageio::write_image(format!("mipmap_level_{}.png", i), &buf[..], &Bounds2i::from_elements(0, 0, level.u_size() as i32, level.v_size() as i32), &Point2i::new(level.u_size() as i32, level.v_size() as i32)).unwrap();
        });

    }
}

impl ImageTexture<f32> {
    pub fn create(_tex2world: &Transform, tp: &TextureParams) -> ImageTexture<f32> {
        let typ = tp.find_string("mapping", "uv");
        let map = if typ == "uv" {
            let su = tp.find_float("uscale", 1.0);
            let sv = tp.find_float("vscale", 1.0);
            let du = tp.find_float("udelta", 0.0);
            let dv = tp.find_float("vdelta", 0.0);

            UVMapping2D::new(su, sv, du, dv)
        } else {
            unimplemented!()
        };
        let max_aniso = tp.find_float("maxanisotropy", 8.0);
        let trilerp = tp.find_bool("trilinear", false);
        let wrap = tp.find_string("wrap", "repeat");
        let wrap_mode = if wrap == "black" {
            WrapMode::Black
        } else if wrap == "clamp" {
            WrapMode::Clamp
        } else {
            WrapMode::Repeat
        };
        let scale = tp.find_float("scale", 1.0);
        let filename = tp.find_filename("filename", "");
        let gamma = tp.find_bool(
            "gamma",
            fileutil::has_extension(&filename, "tga") || fileutil::has_extension(&filename, "png"),
        );

        Self::new(
            Path::new(&filename),
            wrap_mode,
            trilerp,
            max_aniso,
            scale,
            gamma,
            Box::new(map),
            convert_to_float,
        )
    }
}
fn convert_to_spectrum(from: &Spectrum) -> Spectrum {
    *from
}

fn convert_to_float(from: &Spectrum) -> f32 {
    from.y()
}

impl<T> Texture<T> for ImageTexture<T>
where
    T: Zero,
    T: Clone,
    T: Copy,
    T: Send,
    T: Sync,
    T: Clampable,
    T: Debug,
    T: AddAssign<T>,
    T: Mul<f32, Output = T>,
    T: Div<f32, Output = T>,
    T: Sized,
{
    fn evaluate(&self, si: &SurfaceInteraction) -> T {
        let (st, dstdx, dstdy) = self.mapping.map(si);
        self.mipmap.lookup_diff(&st, &dstdx, &dstdy)
    }
}
<|endoftext|>


<commit_before>use std::io::Cursor;
use std::ops::Deref;
use std::time::{SystemTime, UNIX_EPOCH};

use crate::{
    crypto::{self, double_sha256, Digest, KeyPair},
    serializer::*,
    tx::*,
};

#[derive(Clone, Debug)]
pub struct Block {
    pub previous_hash: Digest,
    pub height: u64,
    pub timestamp: u64,
    pub tx_merkle_root: Digest,
    pub transactions: Vec<TxVariant>,
}

impl Block {
    pub fn sign(self, key_pair: &KeyPair) -> SignedBlock {
        let buf = self.calc_hash();
        SignedBlock {
            base: self,
            sig_pair: key_pair.sign(buf.as_ref()),
        }
    }

    pub fn encode_with_tx(&self, vec: &mut Vec<u8>) {
        self.encode(vec);

        vec.push_u32(self.transactions.len() as u32);
        for tx in &self.transactions {
            tx.encode_with_sigs(vec)
        }
    }

    pub fn decode_with_tx(cur: &mut Cursor<&[u8]>) -> Option<Self> {
        let previous_hash = Digest::from_slice(&cur.take_bytes().ok()?)?;
        let height = cur.take_u64().ok()?;
        let timestamp = cur.take_u64().ok()?;
        let tx_merkle_root = Digest::from_slice(&cur.take_bytes().ok()?)?;

        let len = cur.take_u32().ok()?;
        let mut transactions = Vec::<TxVariant>::with_capacity(len as usize);
        for _ in 0..len {
            transactions.push(TxVariant::decode_with_sigs(cur)?);
        }

        Some(Self {
            previous_hash,
            height,
            timestamp,
            tx_merkle_root,
            transactions,
        })
    }

    fn encode(&self, vec: &mut Vec<u8>) {
        vec.push_bytes(self.previous_hash.as_ref());
        vec.push_u64(self.height);
        vec.push_u64(self.timestamp);
        vec.push_bytes(self.tx_merkle_root.as_ref());
    }

    pub fn verify_tx_merkle_root(&self) -> bool {
        let mut buf = Vec::with_capacity(4096 * self.transactions.len());
        for tx in &self.transactions {
            tx.encode_with_sigs(&mut buf)
        }
        let digest = double_sha256(&buf);
        self.tx_merkle_root == digest
    }

    pub fn calc_hash(&self) -> Digest {
        let mut buf = Vec::with_capacity(1024);
        self.encode(&mut buf);
        double_sha256(&buf)
    }

    pub fn verify_previous_hash(&self, prev_block: &Block) -> bool {
        self.previous_hash == prev_block.calc_hash()
    }
}

#[derive(Clone, Debug)]
pub struct SignedBlock {
    pub base: Block,
    pub sig_pair: crypto::SigPair,
}

impl SignedBlock {
    pub fn new_child(&self, txs: Vec<TxVariant>) -> Block {
        let previous_hash = {
            let mut buf = Vec::with_capacity(1024);
            self.base.encode(&mut buf);
            double_sha256(&buf)
        };
        let tx_merkle_root = {
            let mut buf = Vec::with_capacity(4096 * txs.len());
            for tx in &txs {
                tx.encode_with_sigs(&mut buf)
            }
            double_sha256(&buf)
        };
        let timestamp = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_millis() as u64;
        Block {
            previous_hash,
            height: self.height + 1,
            timestamp,
            tx_merkle_root,
            transactions: txs,
        }
    }

    pub fn encode_with_tx(&self, vec: &mut Vec<u8>) {
        self.base.encode_with_tx(vec);
        vec.push_sig_pair(&self.sig_pair);
    }

    pub fn decode_with_tx(cur: &mut Cursor<&[u8]>) -> Option<Self> {
        let block = Block::decode_with_tx(cur)?;
        let sig_pair = cur.take_sig_pair().ok()?;
        Some(Self {
            base: block,
            sig_pair,
        })
    }
}

impl Deref for SignedBlock {
    type Target = Block;

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

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{asset::Balance, crypto::KeyPair};

    #[test]
    fn test_serialize_block() {
        let keys = KeyPair::gen_keypair();
        let transactions = {
            let mut vec = Vec::new();
            vec.push(TxVariant::RewardTx(RewardTx {
                base: Tx {
                    tx_type: TxType::REWARD,
                    fee: "0 GOLD".parse().unwrap(),
                    timestamp: 1234567890,
                    signature_pairs: Vec::new(),
                },
                to: keys.0.clone().into(),
                rewards: Balance::default(),
            }));
            vec
        };
        let tx_merkle_root = {
            let mut buf = Vec::new();
            for tx in &transactions {
                tx.encode_with_sigs(&mut buf)
            }
            double_sha256(&buf)
        };
        let block = (Block {
            previous_hash: Digest::from_slice(&[0u8; 32]).unwrap(),
            height: 123,
            timestamp: 1532992800,
            tx_merkle_root,
            transactions,
        })
        .sign(&keys);

        let mut buf = Vec::new();
        block.encode_with_tx(&mut buf);

        let mut cur = Cursor::<&[u8]>::new(&buf);
        let dec = SignedBlock::decode_with_tx(&mut cur).unwrap();

        assert_eq!(block.previous_hash, dec.previous_hash);
        assert_eq!(block.height, dec.height);
        assert_eq!(block.timestamp, dec.timestamp);
        assert_eq!(block.tx_merkle_root, dec.tx_merkle_root);
        assert_eq!(block.transactions.len(), dec.transactions.len());
        assert_eq!(block.sig_pair, dec.sig_pair);
    }
}
<commit_msg>SignedBlock and Block can now be compared for equality<commit_after>use std::io::Cursor;
use std::ops::Deref;
use std::time::{SystemTime, UNIX_EPOCH};

use crate::{
    crypto::{self, double_sha256, Digest, KeyPair},
    serializer::*,
    tx::*,
};

#[derive(Clone, Debug, PartialEq)]
pub struct Block {
    pub previous_hash: Digest,
    pub height: u64,
    pub timestamp: u64,
    pub tx_merkle_root: Digest,
    pub transactions: Vec<TxVariant>,
}

impl Block {
    pub fn sign(self, key_pair: &KeyPair) -> SignedBlock {
        let buf = self.calc_hash();
        SignedBlock {
            base: self,
            sig_pair: key_pair.sign(buf.as_ref()),
        }
    }

    pub fn encode_with_tx(&self, vec: &mut Vec<u8>) {
        self.encode(vec);

        vec.push_u32(self.transactions.len() as u32);
        for tx in &self.transactions {
            tx.encode_with_sigs(vec)
        }
    }

    pub fn decode_with_tx(cur: &mut Cursor<&[u8]>) -> Option<Self> {
        let previous_hash = Digest::from_slice(&cur.take_bytes().ok()?)?;
        let height = cur.take_u64().ok()?;
        let timestamp = cur.take_u64().ok()?;
        let tx_merkle_root = Digest::from_slice(&cur.take_bytes().ok()?)?;

        let len = cur.take_u32().ok()?;
        let mut transactions = Vec::<TxVariant>::with_capacity(len as usize);
        for _ in 0..len {
            transactions.push(TxVariant::decode_with_sigs(cur)?);
        }

        Some(Self {
            previous_hash,
            height,
            timestamp,
            tx_merkle_root,
            transactions,
        })
    }

    fn encode(&self, vec: &mut Vec<u8>) {
        vec.push_bytes(self.previous_hash.as_ref());
        vec.push_u64(self.height);
        vec.push_u64(self.timestamp);
        vec.push_bytes(self.tx_merkle_root.as_ref());
    }

    pub fn verify_tx_merkle_root(&self) -> bool {
        let mut buf = Vec::with_capacity(4096 * self.transactions.len());
        for tx in &self.transactions {
            tx.encode_with_sigs(&mut buf)
        }
        let digest = double_sha256(&buf);
        self.tx_merkle_root == digest
    }

    pub fn calc_hash(&self) -> Digest {
        let mut buf = Vec::with_capacity(1024);
        self.encode(&mut buf);
        double_sha256(&buf)
    }

    pub fn verify_previous_hash(&self, prev_block: &Block) -> bool {
        self.previous_hash == prev_block.calc_hash()
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct SignedBlock {
    pub base: Block,
    pub sig_pair: crypto::SigPair,
}

impl SignedBlock {
    pub fn new_child(&self, txs: Vec<TxVariant>) -> Block {
        let previous_hash = {
            let mut buf = Vec::with_capacity(1024);
            self.base.encode(&mut buf);
            double_sha256(&buf)
        };
        let tx_merkle_root = {
            let mut buf = Vec::with_capacity(4096 * txs.len());
            for tx in &txs {
                tx.encode_with_sigs(&mut buf)
            }
            double_sha256(&buf)
        };
        let timestamp = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_millis() as u64;
        Block {
            previous_hash,
            height: self.height + 1,
            timestamp,
            tx_merkle_root,
            transactions: txs,
        }
    }

    pub fn encode_with_tx(&self, vec: &mut Vec<u8>) {
        self.base.encode_with_tx(vec);
        vec.push_sig_pair(&self.sig_pair);
    }

    pub fn decode_with_tx(cur: &mut Cursor<&[u8]>) -> Option<Self> {
        let block = Block::decode_with_tx(cur)?;
        let sig_pair = cur.take_sig_pair().ok()?;
        Some(Self {
            base: block,
            sig_pair,
        })
    }
}

impl Deref for SignedBlock {
    type Target = Block;

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

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{asset::Balance, crypto::KeyPair};

    #[test]
    fn test_serialize_block() {
        let keys = KeyPair::gen_keypair();
        let transactions = {
            let mut vec = Vec::new();
            vec.push(TxVariant::RewardTx(RewardTx {
                base: Tx {
                    tx_type: TxType::REWARD,
                    fee: "0 GOLD".parse().unwrap(),
                    timestamp: 1234567890,
                    signature_pairs: Vec::new(),
                },
                to: keys.0.clone().into(),
                rewards: Balance::default(),
            }));
            vec
        };
        let tx_merkle_root = {
            let mut buf = Vec::new();
            for tx in &transactions {
                tx.encode_with_sigs(&mut buf)
            }
            double_sha256(&buf)
        };
        let block = (Block {
            previous_hash: Digest::from_slice(&[0u8; 32]).unwrap(),
            height: 123,
            timestamp: 1532992800,
            tx_merkle_root,
            transactions,
        })
        .sign(&keys);

        let mut buf = Vec::new();
        block.encode_with_tx(&mut buf);

        let mut cur = Cursor::<&[u8]>::new(&buf);
        let dec = SignedBlock::decode_with_tx(&mut cur).unwrap();

        assert_eq!(block.previous_hash, dec.previous_hash);
        assert_eq!(block.height, dec.height);
        assert_eq!(block.timestamp, dec.timestamp);
        assert_eq!(block.tx_merkle_root, dec.tx_merkle_root);
        assert_eq!(block.transactions.len(), dec.transactions.len());
        assert_eq!(block.sig_pair, dec.sig_pair);

        assert_eq!(block, dec);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 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.

// Make sure Rust generates the correct calling convention for extern
// functions.

#[inline(never)]
pub extern "win64" fn foo(a: int, b: int, c: int, d: int) {
    assert!(a == 1);
    assert!(b == 2);
    assert!(c == 3);
    assert!(d == 4);

    println!("a: {:?}, b: {:?}, c: {:?}, d: {:?}",
             a, b, c, d)
}

fn main() {
    foo(1, 2, 3, 4)
}
<commit_msg>Don't use win64 calling convention on 32-bit machines.<commit_after>// Copyright 2013 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.

// Make sure Rust generates the correct calling convention for extern
// functions.

#[inline(never)]
#[cfg(target_arch = "x86_64")]
pub extern "win64" fn foo(a: int, b: int, c: int, d: int) {
    assert!(a == 1);
    assert!(b == 2);
    assert!(c == 3);
    assert!(d == 4);

    println!("a: {:?}, b: {:?}, c: {:?}, d: {:?}",
             a, b, c, d)
}

#[inline(never)]
#[cfg(target_arch = "x86")]
#[cfg(target_arch = "arm")]
pub extern fn foo(a: int, b: int, c: int, d: int) {
    assert!(a == 1);
    assert!(b == 2);
    assert!(c == 3);
    assert!(d == 4);

    println!("a: {:?}, b: {:?}, c: {:?}, d: {:?}",
             a, b, c, d)
}
<|endoftext|>


<commit_before>mod progress;

use self::progress::Progress;
use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "2c462a2f776b899d46743b1b44eda976e846e61d";

static EXCLUDE: &[&str] = &[
    // TODO: const trait bounds
    // https://github.com/dtolnay/syn/issues/767
    "test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs",
    "test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/syntax.rs",

    // Deprecated placement syntax
    "test/ui/obsolete-in-place/bad.rs",

    // Deprecated anonymous parameter syntax in traits
    "test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs",
    "test/ui/issues/issue-13105.rs",
    "test/ui/issues/issue-13775.rs",
    "test/ui/issues/issue-34074.rs",

    // 2015-style dyn that libsyntax rejects
    "test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs",

    // not actually test cases
    "test/rustdoc-ui/test-compile-fail2.rs",
    "test/rustdoc-ui/test-compile-fail3.rs",
    "test/ui/include-single-expr-helper.rs",
    "test/ui/include-single-expr-helper-1.rs",
    "test/ui/issues/auxiliary/issue-21146-inc.rs",
    "test/ui/json-bom-plus-crlf-multifile-aux.rs",
    "test/ui/macros/auxiliary/macro-comma-support.rs",
    "test/ui/macros/auxiliary/macro-include-items-expr.rs",
];

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }

    let mut path_string = path.to_string_lossy();
    if cfg!(windows) {
        path_string = path_string.replace('\\', "/").into();
    }
    assert!(path_string.starts_with("tests/rust/src/"));
    let path = &path_string["tests/rust/src/".len()..];

    // TODO assert that parsing fails on the parse-fail cases
    if path.starts_with("test/parse-fail")
        || path.starts_with("test/compile-fail")
        || path.starts_with("test/rustfix")
    {
        return false;
    }

    if path.starts_with("test/ui") {
        let stderr_path = entry.path().with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    !EXCLUDE.contains(&path)
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let progress = Progress::new(response);
    let decoder = GzDecoder::new(progress);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<commit_msg>Ensure all excluded test files still exist<commit_after>mod progress;

use self::progress::Progress;
use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "2c462a2f776b899d46743b1b44eda976e846e61d";

static EXCLUDE: &[&str] = &[
    // TODO: const trait bounds
    // https://github.com/dtolnay/syn/issues/767
    "test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs",
    "test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/syntax.rs",

    // Deprecated placement syntax
    "test/ui/obsolete-in-place/bad.rs",

    // Deprecated anonymous parameter syntax in traits
    "test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs",
    "test/ui/issues/issue-13105.rs",
    "test/ui/issues/issue-13775.rs",
    "test/ui/issues/issue-34074.rs",

    // 2015-style dyn that libsyntax rejects
    "test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs",

    // not actually test cases
    "test/rustdoc-ui/test-compile-fail2.rs",
    "test/rustdoc-ui/test-compile-fail3.rs",
    "test/ui/include-single-expr-helper.rs",
    "test/ui/include-single-expr-helper-1.rs",
    "test/ui/issues/auxiliary/issue-21146-inc.rs",
    "test/ui/json-bom-plus-crlf-multifile-aux.rs",
    "test/ui/macros/auxiliary/macro-comma-support.rs",
    "test/ui/macros/auxiliary/macro-include-items-expr.rs",
];

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }

    let mut path_string = path.to_string_lossy();
    if cfg!(windows) {
        path_string = path_string.replace('\\', "/").into();
    }
    assert!(path_string.starts_with("tests/rust/src/"));
    let path = &path_string["tests/rust/src/".len()..];

    // TODO assert that parsing fails on the parse-fail cases
    if path.starts_with("test/parse-fail")
        || path.starts_with("test/compile-fail")
        || path.starts_with("test/rustfix")
    {
        return false;
    }

    if path.starts_with("test/ui") {
        let stderr_path = entry.path().with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    !EXCLUDE.contains(&path)
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
    let test_src = Path::new("tests/rust/src");
    for exclude in EXCLUDE {
        if !test_src.join(exclude).exists() {
            panic!("excluded test file does not exist: tests/rust/src/{}", exclude);
        }
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let progress = Progress::new(response);
    let decoder = GzDecoder::new(progress);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2017 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.

// no-system-llvm
// compile-flags: -O
#![crate_type = "lib"]

fn search<T: Ord + Eq>(arr: &mut [T], a: &T) -> Result<usize, ()> {
    match arr.iter().position(|x| x == a) {
        Some(p) => {
            Ok(p)
        },
        None => Err(()),
    }
}

// CHECK-LABEL: @position_no_bounds_check
#[no_mangle]
pub fn position_no_bounds_check(y: &mut [u32], x: &u32, z: &u32) -> bool {
    // This contains "call assume" so we cannot just rule out all calls
    // CHECK-NOT: panic
    if let Ok(p) = search(y, x) {
      y[p] == *z
    } else {
      false
    }
}
<commit_msg>make sure that the no-panic test tests what it is supposed to test<commit_after>// Copyright 2017 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.

// no-system-llvm
// compile-flags: -O
#![crate_type = "lib"]

fn search<T: Ord + Eq>(arr: &mut [T], a: &T) -> Result<usize, ()> {
    match arr.iter().position(|x| x == a) {
        Some(p) => {
            Ok(p)
        },
        None => Err(()),
    }
}

// CHECK-LABEL: @position_no_bounds_check
#[no_mangle]
pub fn position_no_bounds_check(y: &mut [u32], x: &u32, z: &u32) -> bool {
    // This contains "call assume" so we cannot just rule out all calls
    // CHECK-NOT: panic
    if let Ok(p) = search(y, x) {
      y[p] == *z
    } else {
      false
    }
}

// just to make sure that panicking really emits "panic" somewhere in the IR
// CHECK-LABEL: @test_check
#[no_mangle]
pub fn test_check() {
    // CHECK: panic
    unreachable!()
}
<|endoftext|>