<commit_before>use rand::{Rng, SeedableRng, XorShiftRng};
use std::hash::Hash;
use vec_map::VecMap;
use Deciban;

/// Seed a RNG from any hashable value.
pub fn seeded_rng(seed: &impl Hash) -> XorShiftRng {
    use std::collections::hash_map::DefaultHasher;
    use std::hash::Hasher;

    let mut hasher = DefaultHasher::new();
    seed.hash(&mut hasher);
    let hash = hasher.finish().to_be();
    // XorShift seed mustn't be all-0.
    let hash = if hash == 0 { 1 } else { hash };

    let seed = unsafe { ::std::mem::transmute::<[u64; 2], [u8; 16]>([hash, hash]) };
    SeedableRng::from_seed(seed)
}

/// Additional methods for random number generators.
pub trait RngExt {
    /// Return true with 50 % probability.
    fn coinflip(&mut self) -> bool;

    /// Return true with probability 1 / n.
    fn one_chance_in(&mut self, n: u32) -> bool;

    /// Return true with p probability.
    fn with_chance(&mut self, p: f32) -> bool;

    /// Return true with the probability corresponding to the log odds with
    /// the given deciban value.
    fn with_log_odds(&mut self, db: Deciban) -> bool;
}

impl<T: Rng> RngExt for T {
    fn coinflip(&mut self) -> bool { self.gen_bool(1.0 / 2.0) }

    fn one_chance_in(&mut self, n: u32) -> bool { self.gen_bool(1.0 / n as f64) }

    fn with_chance(&mut self, p: f32) -> bool { self.gen_range(0.0, 1.0) < p }

    fn with_log_odds(&mut self, db: Deciban) -> bool { db > self.gen::<Deciban>() }
}

/// Lazily evaluated random permutation.
pub struct RandomPermutation<'a, R: Rng + 'static> {
    remain: usize,
    shuffle: VecMap<usize>,
    rng: &'a mut R,
}

impl<'a, R: Rng + 'static> RandomPermutation<'a, R> {
    pub fn new(rng: &'a mut R, n: usize) -> RandomPermutation<'a, R> {
        RandomPermutation {
            remain: n,
            shuffle: VecMap::new(),
            rng,
        }
    }
}

impl<'a, R: Rng + 'static> Iterator for RandomPermutation<'a, R> {
    type Item = usize;

    fn next(&mut self) -> Option<usize> {
        if self.remain == 0 {
            return None;
        }

        let swap_idx = self.rng.gen_range(0, self.remain);
        self.remain -= 1;

        let head = *self.shuffle.get(self.remain).unwrap_or(&self.remain);
        Some(self.shuffle.insert(swap_idx, head).unwrap_or(swap_idx))
    }
}
<commit_msg>Rng helpers for picking single values<commit_after>use rand::{seq, Rng, SeedableRng, XorShiftRng};
use std::hash::Hash;
use vec_map::VecMap;
use Deciban;

/// Seed a RNG from any hashable value.
pub fn seeded_rng(seed: &impl Hash) -> XorShiftRng {
    use std::collections::hash_map::DefaultHasher;
    use std::hash::Hasher;

    let mut hasher = DefaultHasher::new();
    seed.hash(&mut hasher);
    let hash = hasher.finish().to_be();
    // XorShift seed mustn't be all-0.
    let hash = if hash == 0 { 1 } else { hash };

    let seed = unsafe { ::std::mem::transmute::<[u64; 2], [u8; 16]>([hash, hash]) };
    SeedableRng::from_seed(seed)
}

/// Additional methods for random number generators.
pub trait RngExt {
    /// Return true with 50 % probability.
    fn coinflip(&mut self) -> bool;

    /// Return true with probability 1 / n.
    fn one_chance_in(&mut self, n: u32) -> bool;

    /// Return true with p probability.
    fn with_chance(&mut self, p: f32) -> bool;

    /// Return true with the probability corresponding to the log odds with
    /// the given deciban value.
    fn with_log_odds(&mut self, db: Deciban) -> bool;

    /// Pick a single random element from a slice.
    fn pick_slice_ref<'a, U>(&mut self, slice: &'a [U]) -> Option<&'a U>;

    /// Pick a single random element from a slice.
    fn pick_slice<'a, U: Clone>(&mut self, slice: &'a [U]) -> Option<U>;

    /// Pick a single random element from an iterator
    fn pick_iter<U>(&mut self, iter: impl IntoIterator<Item = U>) -> Option<U>;
}

impl<T: Rng> RngExt for T {
    fn coinflip(&mut self) -> bool { self.gen_bool(1.0 / 2.0) }

    fn one_chance_in(&mut self, n: u32) -> bool { self.gen_bool(1.0 / n as f64) }

    fn with_chance(&mut self, p: f32) -> bool { self.gen_range(0.0, 1.0) < p }

    fn with_log_odds(&mut self, db: Deciban) -> bool { db > self.gen::<Deciban>() }

    fn pick_slice_ref<'a, U>(&mut self, slice: &'a [U]) -> Option<&'a U> {
        seq::sample_slice_ref(self, slice, 1).pop()
    }

    fn pick_slice<U: Clone>(&mut self, slice: &[U]) -> Option<U> {
        seq::sample_slice(self, slice, 1).pop()
    }

    /// Pick a single random element from an iterator
    fn pick_iter<U>(&mut self, iter: impl IntoIterator<Item = U>) -> Option<U> {
        seq::sample_iter(self, iter, 1).unwrap_or(Vec::new()).pop()
    }
}

/// Lazily evaluated random permutation.
pub struct RandomPermutation<'a, R: Rng + 'static> {
    remain: usize,
    shuffle: VecMap<usize>,
    rng: &'a mut R,
}

impl<'a, R: Rng + 'static> RandomPermutation<'a, R> {
    pub fn new(rng: &'a mut R, n: usize) -> RandomPermutation<'a, R> {
        RandomPermutation {
            remain: n,
            shuffle: VecMap::new(),
            rng,
        }
    }
}

impl<'a, R: Rng + 'static> Iterator for RandomPermutation<'a, R> {
    type Item = usize;

    fn next(&mut self) -> Option<usize> {
        if self.remain == 0 {
            return None;
        }

        let swap_idx = self.rng.gen_range(0, self.remain);
        self.remain -= 1;

        let head = *self.shuffle.get(self.remain).unwrap_or(&self.remain);
        Some(self.shuffle.insert(swap_idx, head).unwrap_or(swap_idx))
    }
}
<|endoftext|>


<commit_before>//! Massage and work the auzten file to make sure we can deal with real data.

extern crate las;

macro_rules! autzen {
    ($name:ident, $major:expr, $minor:expr) => {
        mod $name {
            use std::io::Cursor;

            use las::{Reader, Header, Writer};

            const VERSION: (u8, u8) = ($major, $minor);

            #[test]
            fn read_write() {
                let mut reader = Reader::from_path("tests/data/autzen.las").unwrap();
                let mut writer = Writer::new(Cursor::new(Vec::new()), Header {
                    version: VERSION.into(),
                    ..Default::default()
                }).unwrap();
                for point in reader.points() {
                    writer.write(point.unwrap()).unwrap();
                }
                writer.close().unwrap();
            }
        }
    }
}

autzen!(las_1_0, 1, 0);
autzen!(las_1_1, 1, 1);
autzen!(las_1_2, 1, 2);
autzen!(las_1_3, 1, 3);
autzen!(las_1_4, 1, 4);
<commit_msg>Clean up the autzen test<commit_after>//! Massage and work the auzten file to make sure we can deal with real data.

extern crate las;

macro_rules! autzen {
    ($name:ident, $major:expr, $minor:expr) => {
        mod $name {
            use std::io::Cursor;
            use las::{Version, Reader, Writer};

            #[test]
            fn read_write() {
                let mut reader = Reader::from_path("tests/data/autzen.las").unwrap();
                let mut header = reader.header.clone();
                header.version = Version::new($major, $minor);
                let mut writer = Writer::new(Cursor::new(Vec::new()), header).unwrap();
                for point in reader.points() {
                    writer.write(point.unwrap()).unwrap();
                }
                writer.close().unwrap();
            }
        }
    }
}

autzen!(las_1_0, 1, 0);
autzen!(las_1_1, 1, 1);
autzen!(las_1_2, 1, 2);
autzen!(las_1_3, 1, 3);
autzen!(las_1_4, 1, 4);
<|endoftext|>


<commit_before>#![allow(dead_code)]

/// A Multiboot tag structure is a queryable blob of bytes. The implementation presently
/// assumes that the size is at least 8 bytes (for the end tag), and does not check this.
pub enum TagType {
	EndTag            = 0,
	BootCommandLine   = 1,
	BootLoaderName    = 2,
	Module            = 3,
	MemoryInformation = 4,
	BIOSBootDevice    = 5,
	MemoryMap         = 6,
	VBEInfo           = 7,
	FrameBufferInfo   = 8,
	ElfSymbols        = 9,
	APMTable          = 10,
}

#[repr(C)]
pub struct Tag {
	tag_type: u32,
	size: u32,
	// The tag data follows these two fields.
}

pub struct TagIter {
	current: *const Tag
}

impl Iterator for TagIter {
	type Item = &'static Tag;

	fn next(&mut self) -> Option<&'static Tag> {
		let current = unsafe { &*self.current };
		match current {
			&Tag { tag_type: 0, size: 8 } => None, // End tag.
			tag => {
				// Jump to the next tag.
				let mut tag_address = self.current as usize;
				tag_address += tag.size as usize;
				// Align tag to 64 bit address.
				tag_address = ((tag_address - 1) & !0x07) + 0x08;
				self.current = tag_address as *const Tag;

				Some(tag)
			}
		}
	}
}<commit_msg>Define function to check that a tag is the end tag for a multiboot header.<commit_after>#![allow(dead_code)]

/// A Multiboot tag structure is a queryable blob of bytes. The implementation presently
/// assumes that the size is at least 8 bytes (for the end tag), and does not check this.
pub enum TagType {
	EndTag            = 0,
	BootCommandLine   = 1,
	BootLoaderName    = 2,
	Module            = 3,
	MemoryInformation = 4,
	BIOSBootDevice    = 5,
	MemoryMap         = 6,
	VBEInfo           = 7,
	FrameBufferInfo   = 8,
	ElfSymbols        = 9,
	APMTable          = 10,
}

#[repr(C)]
pub struct Tag {
	tag_type: u32,
	size: u32,
	// The tag data follows these two fields.
}

impl Tag {
	fn is_end_tag(&self) -> bool {
		self.tag_type == TagType::EndTag as u32
	}
}

pub struct TagIter {
	current: *const Tag
}

impl Iterator for TagIter {
	type Item = &'static Tag;

	fn next(&mut self) -> Option<&'static Tag> {
		let current = unsafe { &*self.current };
		match current {
			&Tag { tag_type: 0, size: 8 } => None, // End tag.
			tag => {
				// Jump to the next tag.
				let mut tag_address = self.current as usize;
				tag_address += tag.size as usize;
				// Align tag to 64 bit address.
				tag_address = ((tag_address - 1) & !0x07) + 0x08;
				self.current = tag_address as *const Tag;

				Some(tag)
			}
		}
	}
}<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! The `ByteString` struct.

use std::ascii::AsciiExt;
use std::borrow::{ToOwned, Cow};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops;
use std::ops::{Deref, DerefMut};
use std::str;
use std::str::{Bytes, FromStr};
use string_cache::Atom;

/// Encapsulates the IDL `ByteString` type.
#[derive(JSTraceable, Clone, Eq, PartialEq, HeapSizeOf)]
pub struct ByteString(Vec<u8>);

impl ByteString {
    /// Creates a new `ByteString`.
    pub fn new(value: Vec<u8>) -> ByteString {
        ByteString(value)
    }

    /// Returns `self` as a string, if it encodes valid UTF-8, and `None`
    /// otherwise.
    pub fn as_str(&self) -> Option<&str> {
        str::from_utf8(&self.0).ok()
    }

    /// Returns the length.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Compare `self` to `other`, matching A–Z and a–z as equal.
    pub fn eq_ignore_case(&self, other: &ByteString) -> bool {
        self.0.eq_ignore_ascii_case(&other.0)
    }

    /// Returns `self` with A–Z replaced by a–z.
    pub fn to_lower(&self) -> ByteString {
        ByteString::new(self.0.to_ascii_lowercase())
    }
}

impl Into<Vec<u8>> for ByteString {
    fn into(self) -> Vec<u8> {
        self.0
    }
}

impl Hash for ByteString {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.hash(state);
    }
}

impl FromStr for ByteString {
    type Err = ();
    fn from_str(s: &str) -> Result<ByteString, ()> {
        Ok(ByteString::new(s.to_owned().into_bytes()))
    }
}

impl ops::Deref for ByteString {
    type Target = [u8];
    fn deref(&self) -> &[u8] {
        &self.0
    }
}

/// A string that is constructed from a UCS-2 buffer by replacing invalid code
/// points with the replacement character.
#[derive(Clone, HeapSizeOf)]
pub struct USVString(pub String);

/// Returns whether `s` is a `token`, as defined by
/// [RFC 2616](http://tools.ietf.org/html/rfc2616#page-17).
pub fn is_token(s: &[u8]) -> bool {
    if s.is_empty() {
        return false; // A token must be at least a single character
    }
    s.iter().all(|&x| {
        // http://tools.ietf.org/html/rfc2616#section-2.2
        match x {
            0...31 | 127 => false, // CTLs
            40 |
            41 |
            60 |
            62 |
            64 |
            44 |
            59 |
            58 |
            92 |
            34 |
            47 |
            91 |
            93 |
            63 |
            61 |
            123 |
            125 |
            32 => false, // separators
            x if x > 127 => false, // non-CHARs
            _ => true,
        }
    })
}

/// A DOMString.
#[derive(Clone, Debug, Eq, Hash, HeapSizeOf, Ord, PartialEq, PartialOrd)]
pub struct DOMString(String);

impl !Send for DOMString {}

impl DOMString {
    /// Creates a new `DOMString`.
    pub fn new() -> DOMString {
        DOMString(String::new())
    }

    /// Creates a new `DOMString` from a `String`.
    pub fn from_string(s: String) -> DOMString {
        DOMString(s)
    }

    /// Appends a given string slice onto the end of this String.
    pub fn push_str(&mut self, string: &str) {
        self.0.push_str(string)
    }

    /// Truncates this `DOMString`, removing all contents.
    pub fn clear(&mut self) {
        self.0.clear()
    }

    /// An iterator over the bytes of this `DOMString`.
    pub fn bytes(&self) -> Bytes {
        self.0.bytes()
    }
}

impl Default for DOMString {
    fn default() -> Self {
        DOMString(String::new())
    }
}

impl Deref for DOMString {
    type Target = str;

    #[inline]
    fn deref(&self) -> &str {
        &self.0
    }
}

impl DerefMut for DOMString {
    #[inline]
    fn deref_mut(&mut self) -> &mut str {
        &mut self.0
    }
}

impl AsRef<str> for DOMString {
    fn as_ref(&self) -> &str {
        &self.0
    }
}

impl fmt::Display for DOMString {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&**self, f)
    }
}

impl PartialEq<str> for DOMString {
    fn eq(&self, other: &str) -> bool {
        &**self == other
    }
}

impl<'a> PartialEq<&'a str> for DOMString {
    fn eq(&self, other: &&'a str) -> bool {
        &**self == *other
    }
}

impl From<String> for DOMString {
    fn from(contents: String) -> DOMString {
        DOMString(contents)
    }
}

impl<'a> From<&'a str> for DOMString {
    fn from(contents: &str) -> DOMString {
        DOMString::from(String::from(contents))
    }
}

impl<'a> From<Cow<'a, str>> for DOMString {
    fn from(contents: Cow<'a, str>) -> DOMString {
        match contents {
            Cow::Owned(s) => DOMString::from(s),
            Cow::Borrowed(s) => DOMString::from(s),
        }
    }
}

impl From<DOMString> for Atom {
    fn from(contents: DOMString) -> Atom {
        Atom::from(contents.0)
    }
}

impl From<DOMString> for String {
    fn from(contents: DOMString) -> String {
        contents.0
    }
}

impl Into<Vec<u8>> for DOMString {
    fn into(self) -> Vec<u8> {
        self.0.into()
    }
}

impl Extend<char> for DOMString {
    fn extend<I>(&mut self, iterable: I) where I: IntoIterator<Item=char> {
        self.0.extend(iterable)
    }
}
<commit_msg>Expand the documentation for DOMString.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! The `ByteString` struct.

use std::ascii::AsciiExt;
use std::borrow::{ToOwned, Cow};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops;
use std::ops::{Deref, DerefMut};
use std::str;
use std::str::{Bytes, FromStr};
use string_cache::Atom;

/// Encapsulates the IDL `ByteString` type.
#[derive(JSTraceable, Clone, Eq, PartialEq, HeapSizeOf)]
pub struct ByteString(Vec<u8>);

impl ByteString {
    /// Creates a new `ByteString`.
    pub fn new(value: Vec<u8>) -> ByteString {
        ByteString(value)
    }

    /// Returns `self` as a string, if it encodes valid UTF-8, and `None`
    /// otherwise.
    pub fn as_str(&self) -> Option<&str> {
        str::from_utf8(&self.0).ok()
    }

    /// Returns the length.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Compare `self` to `other`, matching A–Z and a–z as equal.
    pub fn eq_ignore_case(&self, other: &ByteString) -> bool {
        self.0.eq_ignore_ascii_case(&other.0)
    }

    /// Returns `self` with A–Z replaced by a–z.
    pub fn to_lower(&self) -> ByteString {
        ByteString::new(self.0.to_ascii_lowercase())
    }
}

impl Into<Vec<u8>> for ByteString {
    fn into(self) -> Vec<u8> {
        self.0
    }
}

impl Hash for ByteString {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.0.hash(state);
    }
}

impl FromStr for ByteString {
    type Err = ();
    fn from_str(s: &str) -> Result<ByteString, ()> {
        Ok(ByteString::new(s.to_owned().into_bytes()))
    }
}

impl ops::Deref for ByteString {
    type Target = [u8];
    fn deref(&self) -> &[u8] {
        &self.0
    }
}

/// A string that is constructed from a UCS-2 buffer by replacing invalid code
/// points with the replacement character.
#[derive(Clone, HeapSizeOf)]
pub struct USVString(pub String);

/// Returns whether `s` is a `token`, as defined by
/// [RFC 2616](http://tools.ietf.org/html/rfc2616#page-17).
pub fn is_token(s: &[u8]) -> bool {
    if s.is_empty() {
        return false; // A token must be at least a single character
    }
    s.iter().all(|&x| {
        // http://tools.ietf.org/html/rfc2616#section-2.2
        match x {
            0...31 | 127 => false, // CTLs
            40 |
            41 |
            60 |
            62 |
            64 |
            44 |
            59 |
            58 |
            92 |
            34 |
            47 |
            91 |
            93 |
            63 |
            61 |
            123 |
            125 |
            32 => false, // separators
            x if x > 127 => false, // non-CHARs
            _ => true,
        }
    })
}

/// A DOMString.
///
/// This type corresponds to the [`DOMString`](idl) type in WebIDL.
///
/// [idl]: https://heycam.github.io/webidl/#idl-DOMString
///
/// Cenceptually, a DOMString has the same value space as a JavaScript String,
/// i.e., an array of 16-bit *code units* representing UTF-16, potentially with
/// unpaired surrogates present (also sometimes called WTF-16).
///
/// Currently, this type stores a Rust `String`, in order to avoid issues when
/// integrating with the rest of the Rust ecosystem and even the rest of the
/// browser itself.
///
/// However, Rust `String`s are guaranteed to be valid UTF-8, and as such have
/// a *smaller value space* than WTF-16 (i.e., some JavaScript String values
/// can not be represented as a Rust `String`). This introduces the question of
/// what to do with values being passed from JavaScript to Rust that contain
/// unpaired surrogates.
///
/// The hypothesis is that it does not matter much how exactly those values are
/// transformed, because passing unpaired surrogates into the DOM is very rare.
/// In order to test this hypothesis, Servo will panic when encountering any
/// unpaired surrogates on conversion to `DOMString` by default. (The command
/// line option `-Z replace-surrogates` instead causes Servo to replace the
/// unpaired surrogate by a U+FFFD replacement character.)
///
/// Currently, the lack of crash reports about this issue provides some
/// evidence to support the hypothesis. This evidence will hopefully be used to
/// convince other browser vendors that it would be safe to replace unpaired
/// surrogates at the boundary between JavaScript and native code. (This would
/// unify the `DOMString` and `USVString` types, both in the WebIDL standard
/// and in Servo.)
///
/// This type is currently `!Send`, in order to help with an independent
/// experiment to store `JSString`s rather than Rust `String`s.
#[derive(Clone, Debug, Eq, Hash, HeapSizeOf, Ord, PartialEq, PartialOrd)]
pub struct DOMString(String);

impl !Send for DOMString {}

impl DOMString {
    /// Creates a new `DOMString`.
    pub fn new() -> DOMString {
        DOMString(String::new())
    }

    /// Creates a new `DOMString` from a `String`.
    pub fn from_string(s: String) -> DOMString {
        DOMString(s)
    }

    /// Appends a given string slice onto the end of this String.
    pub fn push_str(&mut self, string: &str) {
        self.0.push_str(string)
    }

    /// Truncates this `DOMString`, removing all contents.
    pub fn clear(&mut self) {
        self.0.clear()
    }

    /// An iterator over the bytes of this `DOMString`.
    pub fn bytes(&self) -> Bytes {
        self.0.bytes()
    }
}

impl Default for DOMString {
    fn default() -> Self {
        DOMString(String::new())
    }
}

impl Deref for DOMString {
    type Target = str;

    #[inline]
    fn deref(&self) -> &str {
        &self.0
    }
}

impl DerefMut for DOMString {
    #[inline]
    fn deref_mut(&mut self) -> &mut str {
        &mut self.0
    }
}

impl AsRef<str> for DOMString {
    fn as_ref(&self) -> &str {
        &self.0
    }
}

impl fmt::Display for DOMString {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&**self, f)
    }
}

impl PartialEq<str> for DOMString {
    fn eq(&self, other: &str) -> bool {
        &**self == other
    }
}

impl<'a> PartialEq<&'a str> for DOMString {
    fn eq(&self, other: &&'a str) -> bool {
        &**self == *other
    }
}

impl From<String> for DOMString {
    fn from(contents: String) -> DOMString {
        DOMString(contents)
    }
}

impl<'a> From<&'a str> for DOMString {
    fn from(contents: &str) -> DOMString {
        DOMString::from(String::from(contents))
    }
}

impl<'a> From<Cow<'a, str>> for DOMString {
    fn from(contents: Cow<'a, str>) -> DOMString {
        match contents {
            Cow::Owned(s) => DOMString::from(s),
            Cow::Borrowed(s) => DOMString::from(s),
        }
    }
}

impl From<DOMString> for Atom {
    fn from(contents: DOMString) -> Atom {
        Atom::from(contents.0)
    }
}

impl From<DOMString> for String {
    fn from(contents: DOMString) -> String {
        contents.0
    }
}

impl Into<Vec<u8>> for DOMString {
    fn into(self) -> Vec<u8> {
        self.0.into()
    }
}

impl Extend<char> for DOMString {
    fn extend<I>(&mut self, iterable: I) where I: IntoIterator<Item=char> {
        self.0.extend(iterable)
    }
}
<|endoftext|>


<commit_before>// Bare MIPS32r2, little endian, softfloat
// can be used for MIPS M4K core (e.g. on PIC32MX devices)

use crate::spec::abi::Abi;
use crate::spec::{LinkerFlavor, LldFlavor, RelocModel};
use crate::spec::{PanicStrategy, Target, TargetOptions};

pub fn target() -> Target {
    Target {
        llvm_target: "mipsel-unknown-none".to_string(),
        target_endian: "little".to_string(),
        pointer_width: 32,
        target_c_int_width: "32".to_string(),
        data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
        arch: "mips".to_string(),
        target_os: "none".to_string(),
        target_env: String::new(),
        target_vendor: String::new(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),

        options: TargetOptions {
            cpu: "mips32r2".to_string(),
            features: "+mips32r2,+soft-float,+noabicalls".to_string(),
            max_atomic_width: Some(32),
            executables: true,
            linker: Some("rust-lld".to_owned()),
            panic_strategy: PanicStrategy::Abort,
            relocation_model: RelocModel::Static,
            unsupported_abis: vec![
                Abi::Stdcall,
                Abi::Fastcall,
                Abi::Vectorcall,
                Abi::Thiscall,
                Abi::Win64,
                Abi::SysV64,
            ],
            emit_debug_gdb_scripts: false,
            ..Default::default()
        },
    }
}
<commit_msg>improve comments<commit_after>//! Bare MIPS32r2, little endian, softfloat
//!
//! Can be used for MIPS M4K core (e.g. on PIC32MX devices)

use crate::spec::abi::Abi;
use crate::spec::{LinkerFlavor, LldFlavor, RelocModel};
use crate::spec::{PanicStrategy, Target, TargetOptions};

pub fn target() -> Target {
    Target {
        llvm_target: "mipsel-unknown-none".to_string(),
        target_endian: "little".to_string(),
        pointer_width: 32,
        target_c_int_width: "32".to_string(),
        data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
        arch: "mips".to_string(),
        target_os: "none".to_string(),
        target_env: String::new(),
        target_vendor: String::new(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),

        options: TargetOptions {
            cpu: "mips32r2".to_string(),
            features: "+mips32r2,+soft-float,+noabicalls".to_string(),
            max_atomic_width: Some(32),
            executables: true,
            linker: Some("rust-lld".to_owned()),
            panic_strategy: PanicStrategy::Abort,
            relocation_model: RelocModel::Static,
            unsupported_abis: vec![
                Abi::Stdcall,
                Abi::Fastcall,
                Abi::Vectorcall,
                Abi::Thiscall,
                Abi::Win64,
                Abi::SysV64,
            ],
            emit_debug_gdb_scripts: false,
            ..Default::default()
        },
    }
}
<|endoftext|>


<commit_before>extern crate imageflow_c_components;

extern "C" {
    pub fn run_c_components_tests() -> std::os::raw::c_int;
    pub fn run_c_components_test_failure() -> std::os::raw::c_int;
    pub fn profile_main();
    pub fn keep1();
    pub fn keep2();
    pub fn keep3();
    pub fn keep6();
    pub fn keep7();
    pub fn keep8();
    pub fn keep9();
    pub fn keep10();
}

#[test]
fn c_catch() {
    unsafe {
        assert_eq!(0, run_c_components_tests());
    }
}
//
//// Uncomment if you're not seeing C test output
//#[test]
//fn test_failure_works() {
//    unsafe {
//        // If no failures are reported, then we're getting false positives
//        assert_eq!(2, run_c_components_test_failure());
//    }
//}
#[test]
fn test_prevent_lto_stripping() {
    unsafe {
        keep1();
        keep2();
        keep3();
        keep6();
        //keep7(); skipping test_simple_fastscaling
        keep8();
        keep9();
        keep10();
    }
}
<commit_msg>Add test of 1x1 IDCT linear function<commit_after>extern crate imageflow_c_components;

extern "C" {
    pub fn run_c_components_tests() -> std::os::raw::c_int;
    pub fn run_c_components_test_failure() -> std::os::raw::c_int;
    pub fn profile_main();
    pub fn keep1();
    pub fn keep2();
    pub fn keep3();
    pub fn keep6();
    pub fn keep7();
    pub fn keep8();
    pub fn keep9();
    pub fn keep10();
}

#[test]
fn c_catch() {
    unsafe {
        assert_eq!(0, run_c_components_tests());
    }
}
//
//// Uncomment if you're not seeing C test output
//#[test]
//fn test_failure_works() {
//    unsafe {
//        // If no failures are reported, then we're getting false positives
//        assert_eq!(2, run_c_components_test_failure());
//    }
//}
#[test]
fn test_prevent_lto_stripping() {
    unsafe {
        keep1();
        keep2();
        keep3();
        keep6();
        //keep7(); skipping test_simple_fastscaling
        keep8();
        keep9();
        keep10();
    }
}

extern "C" {
    fn flow_scale_spatial_srgb_1x1(input: *const u8, output_rows: *mut *mut u8, output_col: u32);
}

#[test]
fn test_spatial_scaling(){

    let mut input: [u8; 64] = [0; 64];
    for x in 0..64{
        input[x] = if x % 2 == 0 {
            0
        }else{
            255
        };
    }

    let mut output: [u8; 1] = [0;1];
    let mut output_rows: [*mut u8;1] = [&mut output[0]];
    let output_col = 0;

    unsafe {
        flow_scale_spatial_srgb_1x1(&mut input[0], &mut output_rows[0], output_col)
    }

    assert_eq!(output[0], 188);

}<|endoftext|>


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

use anyhow::anyhow;
use itertools::Itertools;
use move_command_line_common::env::{read_bool_env_var, read_env_var};
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::process::Command;

/// Default flags passed to boogie. Additional flags will be added to this via the -B option.
const DEFAULT_BOOGIE_FLAGS: &[&str] = &[
    "-doModSetAnalysis",
    "-printVerifiedProceduresCount:0",
    "-printModel:1",
    "-enhancedErrorMessages:1",
    "-monomorphize",
];

const MIN_BOOGIE_VERSION: &str = "2.9.0";
const MIN_Z3_VERSION: &str = "4.8.9";
const EXPECTED_CVC4_VERSION: &str = "aac53f51";

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum VectorTheory {
    BoogieArray,
    BoogieArrayIntern,
    SmtArray,
    SmtArrayExt,
    SmtSeq,
}

impl VectorTheory {
    pub fn is_extensional(&self) -> bool {
        matches!(
            self,
            VectorTheory::BoogieArrayIntern | VectorTheory::SmtArrayExt | VectorTheory::SmtSeq
        )
    }
}

/// Boogie options.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct BoogieOptions {
    /// Path to the boogie executable.
    pub boogie_exe: String,
    /// Use experimental boogie exe found via env var EXP_BOOGIE_EXE.
    pub use_exp_boogie: bool,
    /// Path to the z3 executable.
    pub z3_exe: String,
    /// Whether to use cvc4.
    pub use_cvc4: bool,
    /// Path to the cvc4 executable.
    pub cvc4_exe: String,
    /// Whether to generate debug trace code.
    pub debug_trace: bool,
    /// List of flags to pass on to boogie.
    pub boogie_flags: Vec<String>,
    /// Whether to use native array theory.
    pub use_array_theory: bool,
    /// Whether to produce an SMT file for each verification problem.
    pub generate_smt: bool,
    /// Whether native instead of stratified equality should be used.
    pub native_equality: bool,
    /// A string determining the type of requires used for parameter type checks. Can be
    /// `"requires"` or `"free requires`".
    pub type_requires: String,
    /// The depth until which stratified functions are expanded.
    pub stratification_depth: usize,
    /// A string to be used to inline a function of medium size. Can be empty or `{:inline}`.
    pub aggressive_func_inline: String,
    /// A string to be used to inline a function of small size. Can be empty or `{:inline}`.
    pub func_inline: String,
    /// A bound to apply to the length of serialization results.
    pub serialize_bound: usize,
    /// How many times to call the prover backend for the verification problem. This is used for
    /// benchmarking.
    pub bench_repeat: usize,
    /// Whether to use the sequence theory as the internal representation for $Vector type.
    pub vector_using_sequences: bool,
    /// A seed for the prover.
    pub random_seed: usize,
    /// The number of cores to use for parallel processing of verification conditions.
    pub proc_cores: usize,
    /// A (soft) timeout for the solver, per verification condition, in seconds.
    pub vc_timeout: usize,
    /// Whether Boogie output and log should be saved.
    pub keep_artifacts: bool,
    /// Eager threshold for quantifier instantiation.
    pub eager_threshold: usize,
    /// Lazy threshold for quantifier instantiation.
    pub lazy_threshold: usize,
    /// Whether to use the new Boogie `{:debug ..}` attribute for tracking debug values.
    pub stable_test_output: bool,
    /// Number of Boogie instances to be run concurrently.
    pub num_instances: usize,
    /// Whether to run Boogie instances sequentially.
    pub sequential_task: bool,
    /// A hard timeout for boogie execution; if the process does not terminate within
    /// this time frame, it will be killed. Zero for no timeout.
    pub hard_timeout_secs: u64,
    /// What vector theory to use.
    pub vector_theory: VectorTheory,
    /// Whether to generate a z3 trace file and where to put it.
    pub z3_trace_file: Option<String>,
}

impl Default for BoogieOptions {
    fn default() -> Self {
        Self {
            bench_repeat: 1,
            boogie_exe: read_env_var("BOOGIE_EXE"),
            use_exp_boogie: false,
            z3_exe: read_env_var("Z3_EXE"),
            use_cvc4: false,
            cvc4_exe: read_env_var("CVC4_EXE"),
            boogie_flags: vec![],
            debug_trace: false,
            use_array_theory: false,
            generate_smt: false,
            native_equality: false,
            type_requires: "free requires".to_owned(),
            stratification_depth: 6,
            aggressive_func_inline: "".to_owned(),
            func_inline: "{:inline}".to_owned(),
            serialize_bound: 0,
            vector_using_sequences: false,
            random_seed: 1,
            proc_cores: 4,
            vc_timeout: 40,
            keep_artifacts: false,
            eager_threshold: 100,
            lazy_threshold: 100,
            stable_test_output: false,
            num_instances: 1,
            sequential_task: false,
            hard_timeout_secs: 0,
            vector_theory: VectorTheory::BoogieArray,
            z3_trace_file: None,
        }
    }
}

impl BoogieOptions {
    /// Derive options based on other set options.
    pub fn derive_options(&mut self) {
        use VectorTheory::*;
        self.native_equality = self.vector_theory.is_extensional();
        if matches!(self.vector_theory, SmtArray | SmtArrayExt) {
            self.use_array_theory = true;
        }
    }

    /// Returns command line to call boogie.
    pub fn get_boogie_command(&self, boogie_file: &str) -> anyhow::Result<Vec<String>> {
        let mut result = if self.use_exp_boogie {
            // This should have a better ux...
            vec![read_env_var("EXP_BOOGIE_EXE")]
        } else {
            vec![self.boogie_exe.clone()]
        };

        // If we don't have a boogie executable, nothing will work
        if result.iter().all(|path| path.is_empty()) {
            anyhow::bail!("No boogie executable set.  Please set BOOGIE_EXE");
        }

        let mut add = |sl: &[&str]| result.extend(sl.iter().map(|s| (*s).to_string()));
        add(DEFAULT_BOOGIE_FLAGS);
        if self.use_cvc4 {
            add(&[
                "-proverOpt:SOLVER=cvc4",
                &format!("-proverOpt:PROVER_PATH={}", &self.cvc4_exe),
            ]);
        } else {
            add(&[&format!("-proverOpt:PROVER_PATH={}", &self.z3_exe)]);
        }
        if self.use_array_theory {
            add(&["-useArrayTheory"]);
            if matches!(self.vector_theory, VectorTheory::SmtArray) {
                add(&["/proverOpt:O:smt.array.extensional=false"])
            }
        } else {
            add(&[&format!(
                "-proverOpt:O:smt.QI.EAGER_THRESHOLD={}",
                self.eager_threshold
            )]);
            add(&[&format!(
                "-proverOpt:O:smt.QI.LAZY_THRESHOLD={}",
                self.lazy_threshold
            )]);
        }
        add(&[&format!(
            "-vcsCores:{}",
            if self.stable_test_output {
                // Do not use multiple cores if stable test output is requested.
                // Error messages may appear in non-deterministic order otherwise.
                1
            } else {
                self.proc_cores
            }
        )]);

        // TODO: see what we can make out of these flags.
        //add(&["-proverOpt:O:smt.QI.PROFILE=true"]);
        //add(&["-proverOpt:O:trace=true"]);
        //add(&["-proverOpt:VERBOSITY=3"]);
        //add(&["-proverOpt:C:-st"]);

        if let Some(file) = &self.z3_trace_file {
            add(&[
                "-proverOpt:O:trace=true",
                &format!("-proverOpt:O:trace_file_name={}", file),
            ]);
        }
        if self.generate_smt {
            add(&["-proverLog:@PROC@.smt"]);
        }
        for f in &self.boogie_flags {
            add(&[f.as_str()]);
        }
        add(&[boogie_file]);
        Ok(result)
    }

    /// Returns name of file where to log boogie output.
    pub fn get_boogie_log_file(&self, boogie_file: &str) -> String {
        format!("{}.log", boogie_file)
    }

    /// Adjust a timeout value, given in seconds, for the runtime environment.
    pub fn adjust_timeout(&self, time: usize) -> usize {
        // If env var MVP_TEST_ON_CI is set, add 100% to the timeout for added
        // robustness against flakiness.
        if read_bool_env_var("MVP_TEST_ON_CI") {
            usize::saturating_add(time, time)
        } else {
            time
        }
    }

    /// Checks whether the expected tool versions are installed in the environment.
    pub fn check_tool_versions(&self) -> anyhow::Result<()> {
        if !self.boogie_exe.is_empty() {
            let version = Self::get_version(
                "boogie",
                &self.boogie_exe,
                &["-version"],
                r"version ([0-9.]*)",
            )?;
            Self::check_version_is_greater("boogie", &version, MIN_BOOGIE_VERSION)?;
        }
        if !self.z3_exe.is_empty() && !self.use_cvc4 {
            let version =
                Self::get_version("z3", &self.z3_exe, &["--version"], r"version ([0-9.]*)")?;
            Self::check_version_is_greater("z3", &version, MIN_Z3_VERSION)?;
        }
        if !self.cvc4_exe.is_empty() && self.use_cvc4 {
            // Currently there is no metric version but a github hash we need to check
            let version = Self::get_version(
                "cvc4",
                &self.cvc4_exe,
                &["--version"],
                r"git master ([0-9a-f]*)",
            )?;
            if version != EXPECTED_CVC4_VERSION {
                return Err(anyhow!(
                    "expected git hash {} but found {} for `cvc4`",
                    EXPECTED_CVC4_VERSION,
                    version
                ));
            }
        }
        Ok(())
    }

    fn get_version(tool: &str, prog: &str, args: &[&str], regex: &str) -> anyhow::Result<String> {
        let out = match Command::new(prog).args(args).output() {
            Ok(out) => String::from_utf8_lossy(&out.stdout).to_string(),
            Err(msg) => {
                return Err(anyhow!(
                    "cannot execute `{}` to obtain version of `{}`: {}",
                    prog,
                    tool,
                    msg.to_string()
                ))
            }
        };
        if let Some(cap) = Regex::new(regex).unwrap().captures(&out) {
            Ok(cap[1].to_string())
        } else {
            Err(anyhow!("cannot extract version from `{}`", prog))
        }
    }

    fn check_version_is_greater(tool: &str, given: &str, expected: &str) -> anyhow::Result<()> {
        let given_parts = given.split('.').collect_vec();
        let expected_parts = expected.split('.').collect_vec();
        if given_parts.len() < expected_parts.len() {
            return Err(anyhow!(
                "version strings {} and {} for `{}` cannot be compared",
                given,
                expected,
                tool,
            ));
        }
        for (g, e) in given_parts.into_iter().zip(expected_parts.into_iter()) {
            let gn = g.parse::<usize>()?;
            let en = e.parse::<usize>()?;
            if gn < en {
                return Err(anyhow!(
                    "expected at least version {} but found {} for `{}`",
                    expected,
                    given,
                    tool
                ));
            }
        }
        Ok(())
    }
}
<commit_msg>[move-prover] update cvc4 to cvc5 as boogie solver option<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use anyhow::anyhow;
use itertools::Itertools;
use move_command_line_common::env::{read_bool_env_var, read_env_var};
use regex::Regex;
use serde::{Deserialize, Serialize};
use std::process::Command;

/// Default flags passed to boogie. Additional flags will be added to this via the -B option.
const DEFAULT_BOOGIE_FLAGS: &[&str] = &[
    "-doModSetAnalysis",
    "-printVerifiedProceduresCount:0",
    "-printModel:1",
    "-enhancedErrorMessages:1",
    "-monomorphize",
];

const MIN_BOOGIE_VERSION: &str = "2.9.0";
const MIN_Z3_VERSION: &str = "4.8.9";
const EXPECTED_CVC4_VERSION: &str = "aac53f51";

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum VectorTheory {
    BoogieArray,
    BoogieArrayIntern,
    SmtArray,
    SmtArrayExt,
    SmtSeq,
}

impl VectorTheory {
    pub fn is_extensional(&self) -> bool {
        matches!(
            self,
            VectorTheory::BoogieArrayIntern | VectorTheory::SmtArrayExt | VectorTheory::SmtSeq
        )
    }
}

/// Boogie options.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct BoogieOptions {
    /// Path to the boogie executable.
    pub boogie_exe: String,
    /// Use experimental boogie exe found via env var EXP_BOOGIE_EXE.
    pub use_exp_boogie: bool,
    /// Path to the z3 executable.
    pub z3_exe: String,
    /// Whether to use cvc4.
    pub use_cvc4: bool,
    /// Path to the cvc4 executable.
    pub cvc4_exe: String,
    /// Whether to generate debug trace code.
    pub debug_trace: bool,
    /// List of flags to pass on to boogie.
    pub boogie_flags: Vec<String>,
    /// Whether to use native array theory.
    pub use_array_theory: bool,
    /// Whether to produce an SMT file for each verification problem.
    pub generate_smt: bool,
    /// Whether native instead of stratified equality should be used.
    pub native_equality: bool,
    /// A string determining the type of requires used for parameter type checks. Can be
    /// `"requires"` or `"free requires`".
    pub type_requires: String,
    /// The depth until which stratified functions are expanded.
    pub stratification_depth: usize,
    /// A string to be used to inline a function of medium size. Can be empty or `{:inline}`.
    pub aggressive_func_inline: String,
    /// A string to be used to inline a function of small size. Can be empty or `{:inline}`.
    pub func_inline: String,
    /// A bound to apply to the length of serialization results.
    pub serialize_bound: usize,
    /// How many times to call the prover backend for the verification problem. This is used for
    /// benchmarking.
    pub bench_repeat: usize,
    /// Whether to use the sequence theory as the internal representation for $Vector type.
    pub vector_using_sequences: bool,
    /// A seed for the prover.
    pub random_seed: usize,
    /// The number of cores to use for parallel processing of verification conditions.
    pub proc_cores: usize,
    /// A (soft) timeout for the solver, per verification condition, in seconds.
    pub vc_timeout: usize,
    /// Whether Boogie output and log should be saved.
    pub keep_artifacts: bool,
    /// Eager threshold for quantifier instantiation.
    pub eager_threshold: usize,
    /// Lazy threshold for quantifier instantiation.
    pub lazy_threshold: usize,
    /// Whether to use the new Boogie `{:debug ..}` attribute for tracking debug values.
    pub stable_test_output: bool,
    /// Number of Boogie instances to be run concurrently.
    pub num_instances: usize,
    /// Whether to run Boogie instances sequentially.
    pub sequential_task: bool,
    /// A hard timeout for boogie execution; if the process does not terminate within
    /// this time frame, it will be killed. Zero for no timeout.
    pub hard_timeout_secs: u64,
    /// What vector theory to use.
    pub vector_theory: VectorTheory,
    /// Whether to generate a z3 trace file and where to put it.
    pub z3_trace_file: Option<String>,
}

impl Default for BoogieOptions {
    fn default() -> Self {
        Self {
            bench_repeat: 1,
            boogie_exe: read_env_var("BOOGIE_EXE"),
            use_exp_boogie: false,
            z3_exe: read_env_var("Z3_EXE"),
            use_cvc4: false,
            cvc4_exe: read_env_var("CVC4_EXE"),
            boogie_flags: vec![],
            debug_trace: false,
            use_array_theory: false,
            generate_smt: false,
            native_equality: false,
            type_requires: "free requires".to_owned(),
            stratification_depth: 6,
            aggressive_func_inline: "".to_owned(),
            func_inline: "{:inline}".to_owned(),
            serialize_bound: 0,
            vector_using_sequences: false,
            random_seed: 1,
            proc_cores: 4,
            vc_timeout: 40,
            keep_artifacts: false,
            eager_threshold: 100,
            lazy_threshold: 100,
            stable_test_output: false,
            num_instances: 1,
            sequential_task: false,
            hard_timeout_secs: 0,
            vector_theory: VectorTheory::BoogieArray,
            z3_trace_file: None,
        }
    }
}

impl BoogieOptions {
    /// Derive options based on other set options.
    pub fn derive_options(&mut self) {
        use VectorTheory::*;
        self.native_equality = self.vector_theory.is_extensional();
        if matches!(self.vector_theory, SmtArray | SmtArrayExt) {
            self.use_array_theory = true;
        }
    }

    /// Returns command line to call boogie.
    pub fn get_boogie_command(&self, boogie_file: &str) -> anyhow::Result<Vec<String>> {
        let mut result = if self.use_exp_boogie {
            // This should have a better ux...
            vec![read_env_var("EXP_BOOGIE_EXE")]
        } else {
            vec![self.boogie_exe.clone()]
        };

        // If we don't have a boogie executable, nothing will work
        if result.iter().all(|path| path.is_empty()) {
            anyhow::bail!("No boogie executable set.  Please set BOOGIE_EXE");
        }

        let mut add = |sl: &[&str]| result.extend(sl.iter().map(|s| (*s).to_string()));
        add(DEFAULT_BOOGIE_FLAGS);
        if self.use_cvc4 {
            add(&[
                "-proverOpt:SOLVER=cvc5",
                &format!("-proverOpt:PROVER_PATH={}", &self.cvc4_exe),
            ]);
        } else {
            add(&[&format!("-proverOpt:PROVER_PATH={}", &self.z3_exe)]);
        }
        if self.use_array_theory {
            add(&["-useArrayTheory"]);
            if matches!(self.vector_theory, VectorTheory::SmtArray) {
                add(&["/proverOpt:O:smt.array.extensional=false"])
            }
        } else {
            add(&[&format!(
                "-proverOpt:O:smt.QI.EAGER_THRESHOLD={}",
                self.eager_threshold
            )]);
            add(&[&format!(
                "-proverOpt:O:smt.QI.LAZY_THRESHOLD={}",
                self.lazy_threshold
            )]);
        }
        add(&[&format!(
            "-vcsCores:{}",
            if self.stable_test_output {
                // Do not use multiple cores if stable test output is requested.
                // Error messages may appear in non-deterministic order otherwise.
                1
            } else {
                self.proc_cores
            }
        )]);

        // TODO: see what we can make out of these flags.
        //add(&["-proverOpt:O:smt.QI.PROFILE=true"]);
        //add(&["-proverOpt:O:trace=true"]);
        //add(&["-proverOpt:VERBOSITY=3"]);
        //add(&["-proverOpt:C:-st"]);

        if let Some(file) = &self.z3_trace_file {
            add(&[
                "-proverOpt:O:trace=true",
                &format!("-proverOpt:O:trace_file_name={}", file),
            ]);
        }
        if self.generate_smt {
            add(&["-proverLog:@PROC@.smt"]);
        }
        for f in &self.boogie_flags {
            add(&[f.as_str()]);
        }
        add(&[boogie_file]);
        Ok(result)
    }

    /// Returns name of file where to log boogie output.
    pub fn get_boogie_log_file(&self, boogie_file: &str) -> String {
        format!("{}.log", boogie_file)
    }

    /// Adjust a timeout value, given in seconds, for the runtime environment.
    pub fn adjust_timeout(&self, time: usize) -> usize {
        // If env var MVP_TEST_ON_CI is set, add 100% to the timeout for added
        // robustness against flakiness.
        if read_bool_env_var("MVP_TEST_ON_CI") {
            usize::saturating_add(time, time)
        } else {
            time
        }
    }

    /// Checks whether the expected tool versions are installed in the environment.
    pub fn check_tool_versions(&self) -> anyhow::Result<()> {
        if !self.boogie_exe.is_empty() {
            let version = Self::get_version(
                "boogie",
                &self.boogie_exe,
                &["-version"],
                r"version ([0-9.]*)",
            )?;
            Self::check_version_is_greater("boogie", &version, MIN_BOOGIE_VERSION)?;
        }
        if !self.z3_exe.is_empty() && !self.use_cvc4 {
            let version =
                Self::get_version("z3", &self.z3_exe, &["--version"], r"version ([0-9.]*)")?;
            Self::check_version_is_greater("z3", &version, MIN_Z3_VERSION)?;
        }
        if !self.cvc4_exe.is_empty() && self.use_cvc4 {
            // Currently there is no metric version but a github hash we need to check
            let version = Self::get_version(
                "cvc4",
                &self.cvc4_exe,
                &["--version"],
                r"git master ([0-9a-f]*)",
            )?;
            if version != EXPECTED_CVC4_VERSION {
                return Err(anyhow!(
                    "expected git hash {} but found {} for `cvc4`",
                    EXPECTED_CVC4_VERSION,
                    version
                ));
            }
        }
        Ok(())
    }

    fn get_version(tool: &str, prog: &str, args: &[&str], regex: &str) -> anyhow::Result<String> {
        let out = match Command::new(prog).args(args).output() {
            Ok(out) => String::from_utf8_lossy(&out.stdout).to_string(),
            Err(msg) => {
                return Err(anyhow!(
                    "cannot execute `{}` to obtain version of `{}`: {}",
                    prog,
                    tool,
                    msg.to_string()
                ))
            }
        };
        if let Some(cap) = Regex::new(regex).unwrap().captures(&out) {
            Ok(cap[1].to_string())
        } else {
            Err(anyhow!("cannot extract version from `{}`", prog))
        }
    }

    fn check_version_is_greater(tool: &str, given: &str, expected: &str) -> anyhow::Result<()> {
        let given_parts = given.split('.').collect_vec();
        let expected_parts = expected.split('.').collect_vec();
        if given_parts.len() < expected_parts.len() {
            return Err(anyhow!(
                "version strings {} and {} for `{}` cannot be compared",
                given,
                expected,
                tool,
            ));
        }
        for (g, e) in given_parts.into_iter().zip(expected_parts.into_iter()) {
            let gn = g.parse::<usize>()?;
            let en = e.parse::<usize>()?;
            if gn < en {
                return Err(anyhow!(
                    "expected at least version {} but found {} for `{}`",
                    expected,
                    given,
                    tool
                ));
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before><commit_msg>modified some status flag settings<commit_after><|endoftext|>


<commit_before>use crate::time::driver::{Handle, TimerEntry};
use crate::time::{error::Error, Duration, Instant};

use pin_project_lite::pin_project;
use std::future::Future;
use std::pin::Pin;
use std::task::{self, Poll};

/// Waits until `deadline` is reached.
///
/// No work is performed while awaiting on the sleep future to complete. `Sleep`
/// operates at millisecond granularity and should not be used for tasks that
/// require high-resolution timers.
///
/// # Cancellation
///
/// Canceling a sleep instance is done by dropping the returned future. No additional
/// cleanup work is required.
// Alias for old name in 0.x
#[cfg_attr(docsrs, doc(alias = "delay_until"))]
pub fn sleep_until(deadline: Instant) -> Sleep {
    Sleep::new_timeout(deadline)
}

/// Waits until `duration` has elapsed.
///
/// Equivalent to `sleep_until(Instant::now() + duration)`. An asynchronous
/// analog to `std::thread::sleep`.
///
/// No work is performed while awaiting on the sleep future to complete. `Sleep`
/// operates at millisecond granularity and should not be used for tasks that
/// require high-resolution timers.
///
/// To run something regularly on a schedule, see [`interval`].
///
/// The maximum duration for a sleep is 68719476734 milliseconds (approximately 2.2 years).
///
/// # Cancellation
///
/// Canceling a sleep instance is done by dropping the returned future. No additional
/// cleanup work is required.
///
/// # Examples
///
/// Wait 100ms and print "100 ms have elapsed".
///
/// ```
/// use tokio::time::{sleep, Duration};
///
/// #[tokio::main]
/// async fn main() {
///     sleep(Duration::from_millis(100)).await;
///     println!("100 ms have elapsed");
/// }
/// ```
///
/// [`interval`]: crate::time::interval()
// Alias for old name in 0.x
#[cfg_attr(docsrs, doc(alias = "delay_for"))]
pub fn sleep(duration: Duration) -> Sleep {
    match Instant::now().checked_add(duration) {
        Some(deadline) => sleep_until(deadline),
        None => sleep_until(Instant::far_future()),
    }
}

pin_project! {
    /// Future returned by [`sleep`](sleep) and [`sleep_until`](sleep_until).
    ///
    /// This type does not implement the `Unpin` trait, which means that if you
    /// use it with [`select!`] or by calling `poll`, you have to pin it first.
    /// If you use it with `.await`, this does not apply.
    ///
    /// # Examples
    ///
    /// Wait 100ms and print "100 ms have elapsed".
    ///
    /// ```
    /// use tokio::time::{sleep, Duration};
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     sleep(Duration::from_millis(100)).await;
    ///     println!("100 ms have elapsed");
    /// }
    /// ```
    ///
    /// Use with [`select!`]. Pinning the `Sleep` with [`tokio::pin!`] is
    /// necessary when the same `Sleep` is selected on multiple times.
    /// ```no_run
    /// use tokio::time::{self, Duration, Instant};
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     let sleep = time::sleep(Duration::from_millis(10));
    ///     tokio::pin!(sleep);
    ///
    ///     loop {
    ///         tokio::select! {
    ///             () = &mut sleep => {
    ///                 println!("timer elapsed");
    ///                 sleep.as_mut().reset(Instant::now() + Duration::from_millis(50));
    ///             },
    ///         }
    ///     }
    /// }
    /// ```
    /// Use in a struct with boxing. By pinning the `Sleep` with a `Box`, the
    /// `HasSleep` struct implements `Unpin`, even though `Sleep` does not.
    /// ```
    /// use std::future::Future;
    /// use std::pin::Pin;
    /// use std::task::{Context, Poll};
    /// use tokio::time::Sleep;
    ///
    /// struct HasSleep {
    ///     sleep: Pin<Box<Sleep>>,
    /// }
    ///
    /// impl Future for HasSleep {
    ///     type Output = ();
    ///
    ///     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
    ///         self.sleep.as_mut().poll(cx)
    ///     }
    /// }
    /// ```
    /// Use in a struct with pin projection. This method avoids the `Box`, but
    /// the `HasSleep` struct will not be `Unpin` as a consequence.
    /// ```
    /// use std::future::Future;
    /// use std::pin::Pin;
    /// use std::task::{Context, Poll};
    /// use tokio::time::Sleep;
    /// use pin_project_lite::pin_project;
    ///
    /// pin_project! {
    ///     struct HasSleep {
    ///         #[pin]
    ///         sleep: Sleep,
    ///     }
    /// }
    ///
    /// impl Future for HasSleep {
    ///     type Output = ();
    ///
    ///     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
    ///         self.project().sleep.poll(cx)
    ///     }
    /// }
    /// ```
    ///
    /// [`select!`]: ../macro.select.html
    /// [`tokio::pin!`]: ../macro.pin.html
    #[derive(Debug)]
    #[must_use = "futures do nothing unless you `.await` or poll them"]
    pub struct Sleep {
        deadline: Instant,

        // The link between the `Sleep` instance and the timer that drives it.
        #[pin]
        entry: TimerEntry,
    }
}

impl Sleep {
    pub(crate) fn new_timeout(deadline: Instant) -> Sleep {
        let handle = Handle::current();
        let entry = TimerEntry::new(&handle, deadline);

        Sleep { deadline, entry }
    }

    pub(crate) fn far_future() -> Sleep {
        Self::new_timeout(Instant::far_future())
    }

    /// Returns the instant at which the future will complete.
    pub fn deadline(&self) -> Instant {
        self.deadline
    }

    /// Returns `true` if `Sleep` has elapsed.
    ///
    /// A `Sleep` instance is elapsed when the requested duration has elapsed.
    pub fn is_elapsed(&self) -> bool {
        self.entry.is_elapsed()
    }

    /// Resets the `Sleep` instance to a new deadline.
    ///
    /// Calling this function allows changing the instant at which the `Sleep`
    /// future completes without having to create new associated state.
    ///
    /// This function can be called both before and after the future has
    /// completed.
    ///
    /// To call this method, you will usually combine the call with
    /// [`Pin::as_mut`], which lets you call the method without consuming the
    /// `Sleep` itself.
    ///
    /// # Example
    ///
    /// ```
    /// use tokio::time::{Duration, Instant};
    ///
    /// # #[tokio::main(flavor = "current_thread")]
    /// # async fn main() {
    /// let sleep = tokio::time::sleep(Duration::from_millis(10));
    /// tokio::pin!(sleep);
    ///
    /// sleep.as_mut().reset(Instant::now() + Duration::from_millis(20));
    /// # }
    /// ```
    ///
    /// [`Pin::as_mut`]: fn@std::pin::Pin::as_mut
    pub fn reset(self: Pin<&mut Self>, deadline: Instant) {
        let me = self.project();
        me.entry.reset(deadline);
        *me.deadline = deadline;
    }

    fn poll_elapsed(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Result<(), Error>> {
        let me = self.project();

        // Keep track of task budget
        let coop = ready!(crate::coop::poll_proceed(cx));

        me.entry.poll_elapsed(cx).map(move |r| {
            coop.made_progress();
            r
        })
    }
}

impl Future for Sleep {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
        // `poll_elapsed` can return an error in two cases:
        //
        // - AtCapacity: this is a pathological case where far too many
        //   sleep instances have been scheduled.
        // - Shutdown: No timer has been setup, which is a mis-use error.
        //
        // Both cases are extremely rare, and pretty accurately fit into
        // "logic errors", so we just panic in this case. A user couldn't
        // really do much better if we passed the error onwards.
        match ready!(self.as_mut().poll_elapsed(cx)) {
            Ok(()) => Poll::Ready(()),
            Err(e) => panic!("timer error: {}", e),
        }
    }
}
<commit_msg>doc: alias sleep to delay (#3604)<commit_after>use crate::time::driver::{Handle, TimerEntry};
use crate::time::{error::Error, Duration, Instant};

use pin_project_lite::pin_project;
use std::future::Future;
use std::pin::Pin;
use std::task::{self, Poll};

/// Waits until `deadline` is reached.
///
/// No work is performed while awaiting on the sleep future to complete. `Sleep`
/// operates at millisecond granularity and should not be used for tasks that
/// require high-resolution timers.
///
/// # Cancellation
///
/// Canceling a sleep instance is done by dropping the returned future. No additional
/// cleanup work is required.
// Alias for old name in 0.x
#[cfg_attr(docsrs, doc(alias = "delay_until"))]
pub fn sleep_until(deadline: Instant) -> Sleep {
    Sleep::new_timeout(deadline)
}

/// Waits until `duration` has elapsed.
///
/// Equivalent to `sleep_until(Instant::now() + duration)`. An asynchronous
/// analog to `std::thread::sleep`.
///
/// No work is performed while awaiting on the sleep future to complete. `Sleep`
/// operates at millisecond granularity and should not be used for tasks that
/// require high-resolution timers.
///
/// To run something regularly on a schedule, see [`interval`].
///
/// The maximum duration for a sleep is 68719476734 milliseconds (approximately 2.2 years).
///
/// # Cancellation
///
/// Canceling a sleep instance is done by dropping the returned future. No additional
/// cleanup work is required.
///
/// # Examples
///
/// Wait 100ms and print "100 ms have elapsed".
///
/// ```
/// use tokio::time::{sleep, Duration};
///
/// #[tokio::main]
/// async fn main() {
///     sleep(Duration::from_millis(100)).await;
///     println!("100 ms have elapsed");
/// }
/// ```
///
/// [`interval`]: crate::time::interval()
// Alias for old name in 0.x
#[cfg_attr(docsrs, doc(alias = "delay_for"))]
pub fn sleep(duration: Duration) -> Sleep {
    match Instant::now().checked_add(duration) {
        Some(deadline) => sleep_until(deadline),
        None => sleep_until(Instant::far_future()),
    }
}

pin_project! {
    /// Future returned by [`sleep`](sleep) and [`sleep_until`](sleep_until).
    ///
    /// This type does not implement the `Unpin` trait, which means that if you
    /// use it with [`select!`] or by calling `poll`, you have to pin it first.
    /// If you use it with `.await`, this does not apply.
    ///
    /// # Examples
    ///
    /// Wait 100ms and print "100 ms have elapsed".
    ///
    /// ```
    /// use tokio::time::{sleep, Duration};
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     sleep(Duration::from_millis(100)).await;
    ///     println!("100 ms have elapsed");
    /// }
    /// ```
    ///
    /// Use with [`select!`]. Pinning the `Sleep` with [`tokio::pin!`] is
    /// necessary when the same `Sleep` is selected on multiple times.
    /// ```no_run
    /// use tokio::time::{self, Duration, Instant};
    ///
    /// #[tokio::main]
    /// async fn main() {
    ///     let sleep = time::sleep(Duration::from_millis(10));
    ///     tokio::pin!(sleep);
    ///
    ///     loop {
    ///         tokio::select! {
    ///             () = &mut sleep => {
    ///                 println!("timer elapsed");
    ///                 sleep.as_mut().reset(Instant::now() + Duration::from_millis(50));
    ///             },
    ///         }
    ///     }
    /// }
    /// ```
    /// Use in a struct with boxing. By pinning the `Sleep` with a `Box`, the
    /// `HasSleep` struct implements `Unpin`, even though `Sleep` does not.
    /// ```
    /// use std::future::Future;
    /// use std::pin::Pin;
    /// use std::task::{Context, Poll};
    /// use tokio::time::Sleep;
    ///
    /// struct HasSleep {
    ///     sleep: Pin<Box<Sleep>>,
    /// }
    ///
    /// impl Future for HasSleep {
    ///     type Output = ();
    ///
    ///     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
    ///         self.sleep.as_mut().poll(cx)
    ///     }
    /// }
    /// ```
    /// Use in a struct with pin projection. This method avoids the `Box`, but
    /// the `HasSleep` struct will not be `Unpin` as a consequence.
    /// ```
    /// use std::future::Future;
    /// use std::pin::Pin;
    /// use std::task::{Context, Poll};
    /// use tokio::time::Sleep;
    /// use pin_project_lite::pin_project;
    ///
    /// pin_project! {
    ///     struct HasSleep {
    ///         #[pin]
    ///         sleep: Sleep,
    ///     }
    /// }
    ///
    /// impl Future for HasSleep {
    ///     type Output = ();
    ///
    ///     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
    ///         self.project().sleep.poll(cx)
    ///     }
    /// }
    /// ```
    ///
    /// [`select!`]: ../macro.select.html
    /// [`tokio::pin!`]: ../macro.pin.html
    // Alias for old name in 0.2
    #[cfg_attr(docsrs, doc(alias = "Delay"))]
    #[derive(Debug)]
    #[must_use = "futures do nothing unless you `.await` or poll them"]
    pub struct Sleep {
        deadline: Instant,

        // The link between the `Sleep` instance and the timer that drives it.
        #[pin]
        entry: TimerEntry,
    }
}

impl Sleep {
    pub(crate) fn new_timeout(deadline: Instant) -> Sleep {
        let handle = Handle::current();
        let entry = TimerEntry::new(&handle, deadline);

        Sleep { deadline, entry }
    }

    pub(crate) fn far_future() -> Sleep {
        Self::new_timeout(Instant::far_future())
    }

    /// Returns the instant at which the future will complete.
    pub fn deadline(&self) -> Instant {
        self.deadline
    }

    /// Returns `true` if `Sleep` has elapsed.
    ///
    /// A `Sleep` instance is elapsed when the requested duration has elapsed.
    pub fn is_elapsed(&self) -> bool {
        self.entry.is_elapsed()
    }

    /// Resets the `Sleep` instance to a new deadline.
    ///
    /// Calling this function allows changing the instant at which the `Sleep`
    /// future completes without having to create new associated state.
    ///
    /// This function can be called both before and after the future has
    /// completed.
    ///
    /// To call this method, you will usually combine the call with
    /// [`Pin::as_mut`], which lets you call the method without consuming the
    /// `Sleep` itself.
    ///
    /// # Example
    ///
    /// ```
    /// use tokio::time::{Duration, Instant};
    ///
    /// # #[tokio::main(flavor = "current_thread")]
    /// # async fn main() {
    /// let sleep = tokio::time::sleep(Duration::from_millis(10));
    /// tokio::pin!(sleep);
    ///
    /// sleep.as_mut().reset(Instant::now() + Duration::from_millis(20));
    /// # }
    /// ```
    ///
    /// [`Pin::as_mut`]: fn@std::pin::Pin::as_mut
    pub fn reset(self: Pin<&mut Self>, deadline: Instant) {
        let me = self.project();
        me.entry.reset(deadline);
        *me.deadline = deadline;
    }

    fn poll_elapsed(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Result<(), Error>> {
        let me = self.project();

        // Keep track of task budget
        let coop = ready!(crate::coop::poll_proceed(cx));

        me.entry.poll_elapsed(cx).map(move |r| {
            coop.made_progress();
            r
        })
    }
}

impl Future for Sleep {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
        // `poll_elapsed` can return an error in two cases:
        //
        // - AtCapacity: this is a pathological case where far too many
        //   sleep instances have been scheduled.
        // - Shutdown: No timer has been setup, which is a mis-use error.
        //
        // Both cases are extremely rare, and pretty accurately fit into
        // "logic errors", so we just panic in this case. A user couldn't
        // really do much better if we passed the error onwards.
        match ready!(self.as_mut().poll_elapsed(cx)) {
            Ok(()) => Poll::Ready(()),
            Err(e) => panic!("timer error: {}", e),
        }
    }
}
<|endoftext|>


<commit_before>use super::types::{ShardAndCommittee, ValidatorRecord, ChainConfig};
use super::TransitionError;
use super::shuffle;
use std::cmp::min;

type DelegatedSlot = Vec<ShardAndCommittee>;
type DelegatedCycle = Vec<DelegatedSlot>;

/* Produce a vector of validators indicies where those validators start and end
 * dynasties are within the supplied `dynasty`.
*/
fn active_validator_indicies(
    dynasty: &u64,
    validators: &Vec<ValidatorRecord>)
    -> Vec<usize>
{
    validators.iter()
        .enumerate()
        .filter_map(|(i, validator)| {
            if (validator.start_dynasty >= *dynasty) &
                (validator.end_dynasty < *dynasty)
            {
                Some(i)
            } else {
                None
            }
        })
        .collect()
}

/*
 * splits a vector into chunks of size n. All postive n values are applicable,
 * hence the honey_badger prefix.
 */
fn honey_badger_split<T: Clone>(list: &Vec<T>, n: usize) -> Vec<Vec<T>> {
  let mut split_list: Vec<Vec<T>> = vec![];
  let list_length = list.len();
  for i in 0..n {
    let partition = list.get(list_length*i/n..list_length*(i+1)/n).unwrap(); // cannot go out of bounds
    split_list.push(partition.to_vec());
  }
  split_list
}

/*
 * Delegates active validators into slots for a given cycle, given a random seed.
 * Returns a vector or ShardAndComitte vectors representing the shards and committiees for
 * each slot.
 * References get_new_shuffling (ethereum 2.1 specification)
 */
pub fn delegate_validators(
    seed: &[u8],
    validators: &Vec<ValidatorRecord>,
    dynasty: &u64,
    crosslinking_shard_start: &u16,
    config: &ChainConfig)
    -> Result<DelegatedCycle, TransitionError>
{
    let shuffled_validator_indices = {
        let mut validator_indices = active_validator_indicies(dynasty, validators);
        match shuffle(seed, validator_indices) {
            Ok(shuffled) => shuffled,
            _ => return Err(TransitionError::InvalidInput(
                    String::from("Shuffle list length exceed.")))
        }
    };
    let shard_indices = (0_usize..config.shard_count as usize).into_iter().collect();
    let crosslinking_shard_start = *crosslinking_shard_start as usize;
    let cycle_length = config.cycle_length as usize;
    let min_committee_size = config.min_committee_size as usize;
    generate_cycle(
        &shuffled_validator_indices,
        &shard_indices,
        &crosslinking_shard_start,
        &cycle_length,
        &min_committee_size)
}

/*
 * Given the validator list, delegates the validators into slots and comittees for a given cycle.
 */
fn generate_cycle(
    validator_indices: &Vec<usize>,
    shard_indices: &Vec<usize>,
    crosslinking_shard_start: &usize,
    cycle_length: &usize,
    min_committee_size: &usize)
    -> Result<DelegatedCycle, TransitionError>
{

    let validator_count = validator_indices.len();
    let shard_count = shard_indices.len();

    if shard_count / cycle_length == 0 {
	    return Err(TransitionError::InvalidInput(String::from("Number of
					    shards needs to be greater than
					    cycle length")));

    }

    let (committees_per_slot, slots_per_committee) = {
        if validator_count >= cycle_length * min_committee_size {
            let committees_per_slot = min(validator_count / cycle_length /
			    (min_committee_size * 2) + 1, shard_count /
			    cycle_length);
            let slots_per_committee = 1;
            (committees_per_slot, slots_per_committee)
        } else {
            let committees_per_slot = 1;
            let mut slots_per_committee = 1;
            while (validator_count * slots_per_committee < cycle_length * min_committee_size) &
                (slots_per_committee < *cycle_length) {
                slots_per_committee = slots_per_committee * 2;
            }
            (committees_per_slot, slots_per_committee)
        }
    };

    let cycle = validator_indices
        .chunks(validator_indices.len() / *cycle_length)
        .enumerate()
        .map(|(i, slot_indices)| {
            let shard_id_start = crosslinking_shard_start + i * committees_per_slot / slots_per_committee;
            return slot_indices
                .chunks(slot_indices.len() / committees_per_slot)
                .enumerate()
                .map(|(j, shard_indices)| {
                    return ShardAndCommittee{
                        shard_id: ((shard_id_start + j) % shard_count) as u16,
                        committee: shard_indices.to_vec(),
                    }
                })
                .collect()
        })
        .collect();
    Ok(cycle)
}

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

    fn generate_cycle_helper(
        validator_count: &usize,
        shard_count: &usize,
        crosslinking_shard_start: &usize,
        cycle_length: &usize,
        min_committee_size: &usize)
        -> (Vec<usize>, Vec<usize>, Result<DelegatedCycle, TransitionError>)
    {
        let validator_indices = (0_usize..*validator_count).into_iter().collect();
        let shard_indices = (0_usize..*shard_count).into_iter().collect();
        let result = generate_cycle(
            &validator_indices,
            &shard_indices,
            &crosslinking_shard_start,
            &cycle_length,
            &min_committee_size);
        (validator_indices, shard_indices, result)
    }

    #[allow(dead_code)]
    fn print_cycle(cycle: &DelegatedCycle) {
        cycle.iter()
            .enumerate()
            .for_each(|(i, slot)| {
                println!("slot {:?}", &i);
                slot.iter()
                    .enumerate()
                    .for_each(|(i, sac)| {
                        println!("#{:?}\tshard_id={}\tcommittee.len()={}",
                            &i, &sac.shard_id, &sac.committee.len())
                    })
            });
    }

    fn flatten_validators(cycle: &DelegatedCycle)
        -> Vec<usize>
    {
        let mut flattened = vec![];
        for slot in cycle.iter() {
            for sac in slot.iter() {
                for validator in sac.committee.iter() {
                    flattened.push(*validator);
                }
            }
        }
        flattened
    }

    fn flatten_and_dedup_shards(cycle: &DelegatedCycle)
        -> Vec<usize>
    {
        let mut flattened = vec![];
        for slot in cycle.iter() {
            for sac in slot.iter() {
                flattened.push(sac.shard_id as usize);
            }
        }
        flattened.dedup();
        flattened
    }

    fn flatten_shards_in_slots(cycle: &DelegatedCycle)
        -> Vec<Vec<usize>>
    {
        let mut shards_in_slots: Vec<Vec<usize>> = vec![];
        for slot in cycle.iter() {
            let mut shards: Vec<usize> = vec![];
            for sac in slot.iter() {
                shards.push(sac.shard_id as usize);
            }
            shards_in_slots.push(shards);
        }
        shards_in_slots
    }

    #[test]
    fn test_generate_cycle() {
        let validator_count: usize = 100;
        let shard_count: usize = 10;
        let crosslinking_shard_start: usize = 0;
        let cycle_length: usize = 20;
        let min_committee_size: usize = 10;
        let (validators, shards, result) = generate_cycle_helper(
            &validator_count,
            &shard_count,
            &crosslinking_shard_start,
            &cycle_length,
            &min_committee_size);
        let cycle = result.unwrap();

        let assigned_validators = flatten_validators(&cycle);
        let assigned_shards = flatten_and_dedup_shards(&cycle);
        let shards_in_slots = flatten_shards_in_slots(&cycle);
        assert_eq!(assigned_validators, validators, "Validator assignment incorrect");
        assert_eq!(assigned_shards, shards, "Shard assignment incorrect");

        let expected_shards_in_slots: Vec<Vec<usize>> = vec![
            vec![0], vec![0],   // Each line is 2 slots..
            vec![1], vec![1],
            vec![2], vec![2],
            vec![3], vec![3],
            vec![4], vec![4],
            vec![5], vec![5],
            vec![6], vec![6],
            vec![7], vec![7],
            vec![8], vec![8],
            vec![9], vec![9],
        ];
        // assert!(compare_shards_in_slots(&cycle, &expected_shards_in_slots));
        assert_eq!(expected_shards_in_slots, shards_in_slots, "Shard assignment incorrect.")
    }

    #[test]
    // Check that the committees per slot is upper bounded by shard count
    fn test_generate_cycle_committees_bounded() {
        let validator_count: usize = 101;
        let shard_count: usize = 15;
        let crosslinking_shard_start: usize = 0;
        let cycle_length: usize = 10;
        let min_committee_size: usize = 10;
        let (validators, shards, result) = generate_cycle_helper(
            &validator_count,
            &shard_count,
            &crosslinking_shard_start,
            &cycle_length,
            &min_committee_size);
        let cycle = result.unwrap();

        let assigned_validators = flatten_validators(&cycle);
        let assigned_shards = flatten_and_dedup_shards(&cycle);
        let shards_in_slots = flatten_shards_in_slots(&cycle);
        print_cycle(&cycle);
        assert_eq!(assigned_validators, validators, "Validator assignment incorrect");
        assert_eq!(assigned_shards, shards, "Shard assignment incorrect");

        let expected_shards_in_slots: Vec<Vec<usize>> = vec![
            vec![0], vec![0],   // Each line is 2 slots..
            vec![1], vec![1],
            vec![2], vec![2],
            vec![3], vec![3],
            vec![4], vec![4],
            vec![5], vec![5],
            vec![6], vec![6],
            vec![7], vec![7],
            vec![8], vec![8],
            vec![9], vec![9],
        ];
        // assert!(compare_shards_in_slots(&cycle, &expected_shards_in_slots));
        assert_eq!(expected_shards_in_slots, shards_in_slots, "Shard assignment incorrect.")
    }
}
<commit_msg>Improve split function<commit_after>use super::types::{ShardAndCommittee, ValidatorRecord, ChainConfig};
use super::TransitionError;
use super::shuffle;
use std::cmp::min;

type DelegatedSlot = Vec<ShardAndCommittee>;
type DelegatedCycle = Vec<DelegatedSlot>;

/* Produce a vector of validators indicies where those validators start and end
 * dynasties are within the supplied `dynasty`.
*/
fn active_validator_indicies(
    dynasty: &u64,
    validators: &Vec<ValidatorRecord>)
    -> Vec<usize>
{
    validators.iter()
        .enumerate()
        .filter_map(|(i, validator)| {
            if (validator.start_dynasty >= *dynasty) &
                (validator.end_dynasty < *dynasty)
            {
                Some(i)
            } else {
                None
            }
        })
        .collect()
}

/*
 * splits a vector into chunks of size n. All postive n values are applicable,
 * hence the honey_badger prefix.
 */
fn honey_badger_split<T: Clone>(list: &Vec<T>, n: usize) -> Vec<Vec<T>> {
  let mut split_list: Vec<Vec<T>> = vec![];
  let list_length = list.len();
  for i in 0..n {
    let partition = match list.get(list_length*i/n..list_length*(i+1)/n) {
        Some(v) => v,
        None => unreachable!(),
    };
    split_list.push(partition.to_vec());
  }
  split_list
}

/*
 * Delegates active validators into slots for a given cycle, given a random seed.
 * Returns a vector or ShardAndComitte vectors representing the shards and committiees for
 * each slot.
 * References get_new_shuffling (ethereum 2.1 specification)
 */
pub fn delegate_validators(
    seed: &[u8],
    validators: &Vec<ValidatorRecord>,
    dynasty: &u64,
    crosslinking_shard_start: &u16,
    config: &ChainConfig)
    -> Result<DelegatedCycle, TransitionError>
{
    let shuffled_validator_indices = {
        let mut validator_indices = active_validator_indicies(dynasty, validators);
        match shuffle(seed, validator_indices) {
            Ok(shuffled) => shuffled,
            _ => return Err(TransitionError::InvalidInput(
                    String::from("Shuffle list length exceed.")))
        }
    };
    let shard_indices = (0_usize..config.shard_count as usize).into_iter().collect();
    let crosslinking_shard_start = *crosslinking_shard_start as usize;
    let cycle_length = config.cycle_length as usize;
    let min_committee_size = config.min_committee_size as usize;
    generate_cycle(
        &shuffled_validator_indices,
        &shard_indices,
        &crosslinking_shard_start,
        &cycle_length,
        &min_committee_size)
}

/*
 * Given the validator list, delegates the validators into slots and comittees for a given cycle.
 */
fn generate_cycle(
    validator_indices: &Vec<usize>,
    shard_indices: &Vec<usize>,
    crosslinking_shard_start: &usize,
    cycle_length: &usize,
    min_committee_size: &usize)
    -> Result<DelegatedCycle, TransitionError>
{

    let validator_count = validator_indices.len();
    let shard_count = shard_indices.len();

    if shard_count / cycle_length == 0 {
	    return Err(TransitionError::InvalidInput(String::from("Number of
					    shards needs to be greater than
					    cycle length")));

    }

    let (committees_per_slot, slots_per_committee) = {
        if validator_count >= cycle_length * min_committee_size {
            let committees_per_slot = min(validator_count / cycle_length /
			    (min_committee_size * 2) + 1, shard_count /
			    cycle_length);
            let slots_per_committee = 1;
            (committees_per_slot, slots_per_committee)
        } else {
            let committees_per_slot = 1;
            let mut slots_per_committee = 1;
            while (validator_count * slots_per_committee < cycle_length * min_committee_size) &
                (slots_per_committee < *cycle_length) {
                slots_per_committee = slots_per_committee * 2;
            }
            (committees_per_slot, slots_per_committee)
        }
    };

    let cycle = validator_indices
        .chunks(validator_indices.len() / *cycle_length)
        .enumerate()
        .map(|(i, slot_indices)| {
            let shard_id_start = crosslinking_shard_start + i * committees_per_slot / slots_per_committee;
            return slot_indices
                .chunks(slot_indices.len() / committees_per_slot)
                .enumerate()
                .map(|(j, shard_indices)| {
                    return ShardAndCommittee{
                        shard_id: ((shard_id_start + j) % shard_count) as u16,
                        committee: shard_indices.to_vec(),
                    }
                })
                .collect()
        })
        .collect();
    Ok(cycle)
}

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

    fn generate_cycle_helper(
        validator_count: &usize,
        shard_count: &usize,
        crosslinking_shard_start: &usize,
        cycle_length: &usize,
        min_committee_size: &usize)
        -> (Vec<usize>, Vec<usize>, Result<DelegatedCycle, TransitionError>)
    {
        let validator_indices = (0_usize..*validator_count).into_iter().collect();
        let shard_indices = (0_usize..*shard_count).into_iter().collect();
        let result = generate_cycle(
            &validator_indices,
            &shard_indices,
            &crosslinking_shard_start,
            &cycle_length,
            &min_committee_size);
        (validator_indices, shard_indices, result)
    }

    #[allow(dead_code)]
    fn print_cycle(cycle: &DelegatedCycle) {
        cycle.iter()
            .enumerate()
            .for_each(|(i, slot)| {
                println!("slot {:?}", &i);
                slot.iter()
                    .enumerate()
                    .for_each(|(i, sac)| {
                        println!("#{:?}\tshard_id={}\tcommittee.len()={}",
                            &i, &sac.shard_id, &sac.committee.len())
                    })
            });
    }

    fn flatten_validators(cycle: &DelegatedCycle)
        -> Vec<usize>
    {
        let mut flattened = vec![];
        for slot in cycle.iter() {
            for sac in slot.iter() {
                for validator in sac.committee.iter() {
                    flattened.push(*validator);
                }
            }
        }
        flattened
    }

    fn flatten_and_dedup_shards(cycle: &DelegatedCycle)
        -> Vec<usize>
    {
        let mut flattened = vec![];
        for slot in cycle.iter() {
            for sac in slot.iter() {
                flattened.push(sac.shard_id as usize);
            }
        }
        flattened.dedup();
        flattened
    }

    fn flatten_shards_in_slots(cycle: &DelegatedCycle)
        -> Vec<Vec<usize>>
    {
        let mut shards_in_slots: Vec<Vec<usize>> = vec![];
        for slot in cycle.iter() {
            let mut shards: Vec<usize> = vec![];
            for sac in slot.iter() {
                shards.push(sac.shard_id as usize);
            }
            shards_in_slots.push(shards);
        }
        shards_in_slots
    }

    #[test]
    fn test_generate_cycle() {
        let validator_count: usize = 100;
        let shard_count: usize = 10;
        let crosslinking_shard_start: usize = 0;
        let cycle_length: usize = 20;
        let min_committee_size: usize = 10;
        let (validators, shards, result) = generate_cycle_helper(
            &validator_count,
            &shard_count,
            &crosslinking_shard_start,
            &cycle_length,
            &min_committee_size);
        let cycle = result.unwrap();

        let assigned_validators = flatten_validators(&cycle);
        let assigned_shards = flatten_and_dedup_shards(&cycle);
        let shards_in_slots = flatten_shards_in_slots(&cycle);
        assert_eq!(assigned_validators, validators, "Validator assignment incorrect");
        assert_eq!(assigned_shards, shards, "Shard assignment incorrect");

        let expected_shards_in_slots: Vec<Vec<usize>> = vec![
            vec![0], vec![0],   // Each line is 2 slots..
            vec![1], vec![1],
            vec![2], vec![2],
            vec![3], vec![3],
            vec![4], vec![4],
            vec![5], vec![5],
            vec![6], vec![6],
            vec![7], vec![7],
            vec![8], vec![8],
            vec![9], vec![9],
        ];
        // assert!(compare_shards_in_slots(&cycle, &expected_shards_in_slots));
        assert_eq!(expected_shards_in_slots, shards_in_slots, "Shard assignment incorrect.")
    }

    #[test]
    // Check that the committees per slot is upper bounded by shard count
    fn test_generate_cycle_committees_bounded() {
        let validator_count: usize = 101;
        let shard_count: usize = 15;
        let crosslinking_shard_start: usize = 0;
        let cycle_length: usize = 10;
        let min_committee_size: usize = 10;
        let (validators, shards, result) = generate_cycle_helper(
            &validator_count,
            &shard_count,
            &crosslinking_shard_start,
            &cycle_length,
            &min_committee_size);
        let cycle = result.unwrap();

        let assigned_validators = flatten_validators(&cycle);
        let assigned_shards = flatten_and_dedup_shards(&cycle);
        let shards_in_slots = flatten_shards_in_slots(&cycle);
        print_cycle(&cycle);
        assert_eq!(assigned_validators, validators, "Validator assignment incorrect");
        assert_eq!(assigned_shards, shards, "Shard assignment incorrect");

        let expected_shards_in_slots: Vec<Vec<usize>> = vec![
            vec![0], vec![0],   // Each line is 2 slots..
            vec![1], vec![1],
            vec![2], vec![2],
            vec![3], vec![3],
            vec![4], vec![4],
            vec![5], vec![5],
            vec![6], vec![6],
            vec![7], vec![7],
            vec![8], vec![8],
            vec![9], vec![9],
        ];
        // assert!(compare_shards_in_slots(&cycle, &expected_shards_in_slots));
        assert_eq!(expected_shards_in_slots, shards_in_slots, "Shard assignment incorrect.")
    }
}
<|endoftext|>