<commit_before>use byteorder::ReadBytesExt;
use error::{Error, Result};
use marker::Marker;
use std::io::Read;
use std::iter::repeat;

const LUT_BITS: u8 = 8;

#[derive(Debug)]
pub struct HuffmanDecoder {
    bits: u32,
    num_bits: u8,
    marker: Option<Marker>,
}

impl HuffmanDecoder {
    pub fn new() -> HuffmanDecoder {
        HuffmanDecoder {
            bits: 0,
            num_bits: 0,
            marker: None,
        }
    }

    // Section F.2.2.3
    // Figure F.16
    pub fn decode<R: Read>(&mut self, reader: &mut R, table: &HuffmanTable) -> Result<u8> {
        if self.num_bits < 16 {
            try!(self.read_bits(reader));
        }

        let (value, size) = table.lut[self.peek_bits(LUT_BITS) as usize];

        if size > 0 {
            self.consume_bits(size);
            Ok(value)
        }
        else {
            let bits = self.peek_bits(16);

            for i in LUT_BITS .. 16 {
                let code = (bits >> (15 - i)) as i32;

                if code <= table.maxcode[i as usize] {
                    self.consume_bits(i + 1);

                    let index = (code + table.delta[i as usize]) as usize;
                    return Ok(table.values[index]);
                }
            }

            Err(Error::Format("failed to decode huffman code".to_owned()))
        }
    }

    pub fn decode_fast_ac<R: Read>(&mut self, reader: &mut R, table: &HuffmanTable) -> Result<Option<(i16, u8)>> {
        if let Some(ref ac_lut) = table.ac_lut {
            if self.num_bits < LUT_BITS {
                try!(self.read_bits(reader));
            }

            let (value, run_size) = ac_lut[self.peek_bits(LUT_BITS) as usize];

            if run_size != 0 {
                let run = run_size >> 4;
                let size = run_size & 0x0f;

                self.consume_bits(size);
                return Ok(Some((value, run)));
            }
        }

        Ok(None)
    }

    #[inline]
    pub fn get_bits<R: Read>(&mut self, reader: &mut R, count: u8) -> Result<u16> {
        if self.num_bits < count {
            try!(self.read_bits(reader));
        }

        let bits = self.peek_bits(count);
        self.consume_bits(count);

        Ok(bits)
    }

    #[inline]
    pub fn receive_extend<R: Read>(&mut self, reader: &mut R, count: u8) -> Result<i16> {
        let value = try!(self.get_bits(reader, count));
        Ok(extend(value, count))
    }

    pub fn reset(&mut self) {
        self.bits = 0;
        self.num_bits = 0;
    }

    pub fn take_marker(&mut self) -> Option<Marker> {
        self.marker.take()
    }

    #[inline]
    fn peek_bits(&mut self, count: u8) -> u16 {
        debug_assert!(count <= 16);
        debug_assert!(self.num_bits >= count);

        ((self.bits >> (32 - count)) & ((1 << count) - 1)) as u16
    }

    #[inline]
    fn consume_bits(&mut self, count: u8) {
        debug_assert!(self.num_bits >= count);

        self.bits <<= count as usize;
        self.num_bits -= count;
    }

    fn read_bits<R: Read>(&mut self, reader: &mut R) -> Result<()> {
        while self.num_bits <= 24 {
            // Fill with zero bits if we have reached the end.
            let byte = match self.marker {
                Some(_) => 0,
                None => try!(reader.read_u8()),
            };

            if byte == 0xFF {
                let mut next_byte = try!(reader.read_u8());

                // Check for byte stuffing.
                if next_byte != 0x00 {
                    // We seem to have reached the end of entropy-coded data and encountered a
                    // marker. Since we can't put data back into the reader, we have to continue
                    // reading to identify the marker so we can pass it on.

                    // Section B.1.1.2
                    // "Any marker may optionally be preceded by any number of fill bytes, which are bytes assigned code X’FF’."
                    while next_byte == 0xFF {
                        next_byte = try!(reader.read_u8());
                    }

                    match next_byte {
                        0x00 => return Err(Error::Format("FF 00 found where marker was expected".to_owned())),
                        _    => self.marker = Some(Marker::from_u8(next_byte).unwrap()),
                    }

                    continue;
                }
            }

            self.bits |= (byte as u32) << (24 - self.num_bits);
            self.num_bits += 8;
        }

        Ok(())
    }
}

// Section F.2.2.1
// Figure F.12
fn extend(value: u16, count: u8) -> i16 {
    let vt = 1 << (count as u16 - 1);

    if value < vt {
        value as i16 + (-1 << count as i16) + 1
    } else {
        value as i16
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum HuffmanTableClass {
    DC,
    AC,
}

pub struct HuffmanTable {
    values: Vec<u8>,
    delta: [i32; 16],
    maxcode: [i32; 16],

    lut: [(u8, u8); 1 << LUT_BITS],
    ac_lut: Option<[(i16, u8); 1 << LUT_BITS]>,
}

impl HuffmanTable {
    pub fn new(bits: &[u8; 16], values: &[u8], class: HuffmanTableClass) -> Result<HuffmanTable> {
        let (huffcode, huffsize) = try!(derive_huffman_codes(bits));

        // Section F.2.2.3
        // Figure F.15
        // delta[i] is set to VALPTR(I) - MINCODE(I)
        let mut delta = [0i32; 16];
        let mut maxcode = [-1i32; 16];
        let mut j = 0;

        for i in 0 .. 16 {
            if bits[i] != 0 {
                delta[i] = j as i32 - huffcode[j] as i32;
                j += bits[i] as usize;
                maxcode[i] = huffcode[j - 1] as i32;
            }
        }

        // Build a lookup table for faster decoding.
        let mut lut = [(0u8, 0u8); 1 << LUT_BITS];

        for (i, &size) in huffsize.iter().enumerate().filter(|&(_, &size)| size <= LUT_BITS) {
            let bits_remaining = LUT_BITS - size;
            let start = (huffcode[i] << bits_remaining) as usize;

            for j in 0 .. 1 << bits_remaining {
                lut[start + j] = (values[i], size);
            }
        }

        // Build a lookup table for small AC coefficients which both decodes the value and does the
        // equivalent of receive_extend.
        let ac_lut = match class {
            HuffmanTableClass::DC => None,
            HuffmanTableClass::AC => {
                let mut table = [(0i16, 0u8); 1 << LUT_BITS];

                for (i, &(value, size)) in lut.iter().enumerate() {
                    let run_length = value >> 4;
                    let magnitude_category = value & 0x0f;

                    if magnitude_category > 0 && size + magnitude_category <= LUT_BITS {
                        let unextended_ac_value = (((i << size) & ((1 << LUT_BITS) - 1)) >> (LUT_BITS - magnitude_category)) as u16;
                        let ac_value = extend(unextended_ac_value, magnitude_category);

                        table[i] = (ac_value, (run_length << 4) | (size + magnitude_category));
                    }
                }

                Some(table)
            },
        };

        Ok(HuffmanTable {
            values: values.to_vec(),
            delta: delta,
            maxcode: maxcode,
            lut: lut,
            ac_lut: ac_lut,
        })
    }
}

// Section C.2
fn derive_huffman_codes(bits: &[u8; 16]) -> Result<(Vec<u16>, Vec<u8>)> {
    // Figure C.1
    let huffsize = bits.iter()
                       .enumerate()
                       .fold(Vec::new(), |mut acc, (i, &value)| {
                           let mut repeated_size: Vec<u8> = repeat((i + 1) as u8).take(value as usize).collect();
                           acc.append(&mut repeated_size);
                           acc
                       });

    // Figure C.2
    let mut huffcode = vec![0u16; huffsize.len()];
    let mut code_size = huffsize[0];
    let mut code = 0u16;

    for (i, &size) in huffsize.iter().enumerate() {
        while code_size < size {
            code <<= 1;
            code_size += 1;
        }

        if code as u32 >= (1u32 << size) {
            return Err(Error::Format("bad huffman code length".to_owned()));
        }

        huffcode[i] = code;
        code += 1;
    }

    Ok((huffcode, huffsize))
}
<commit_msg>Increase the size of HuffmanDecoder's bitbuffer to 64bits<commit_after>use byteorder::ReadBytesExt;
use error::{Error, Result};
use marker::Marker;
use std::io::Read;
use std::iter::repeat;

const LUT_BITS: u8 = 8;

#[derive(Debug)]
pub struct HuffmanDecoder {
    bits: u64,
    num_bits: u8,
    marker: Option<Marker>,
}

impl HuffmanDecoder {
    pub fn new() -> HuffmanDecoder {
        HuffmanDecoder {
            bits: 0,
            num_bits: 0,
            marker: None,
        }
    }

    // Section F.2.2.3
    // Figure F.16
    pub fn decode<R: Read>(&mut self, reader: &mut R, table: &HuffmanTable) -> Result<u8> {
        if self.num_bits < 16 {
            try!(self.read_bits(reader));
        }

        let (value, size) = table.lut[self.peek_bits(LUT_BITS) as usize];

        if size > 0 {
            self.consume_bits(size);
            Ok(value)
        }
        else {
            let bits = self.peek_bits(16);

            for i in LUT_BITS .. 16 {
                let code = (bits >> (15 - i)) as i32;

                if code <= table.maxcode[i as usize] {
                    self.consume_bits(i + 1);

                    let index = (code + table.delta[i as usize]) as usize;
                    return Ok(table.values[index]);
                }
            }

            Err(Error::Format("failed to decode huffman code".to_owned()))
        }
    }

    pub fn decode_fast_ac<R: Read>(&mut self, reader: &mut R, table: &HuffmanTable) -> Result<Option<(i16, u8)>> {
        if let Some(ref ac_lut) = table.ac_lut {
            if self.num_bits < LUT_BITS {
                try!(self.read_bits(reader));
            }

            let (value, run_size) = ac_lut[self.peek_bits(LUT_BITS) as usize];

            if run_size != 0 {
                let run = run_size >> 4;
                let size = run_size & 0x0f;

                self.consume_bits(size);
                return Ok(Some((value, run)));
            }
        }

        Ok(None)
    }

    #[inline]
    pub fn get_bits<R: Read>(&mut self, reader: &mut R, count: u8) -> Result<u16> {
        if self.num_bits < count {
            try!(self.read_bits(reader));
        }

        let bits = self.peek_bits(count);
        self.consume_bits(count);

        Ok(bits)
    }

    #[inline]
    pub fn receive_extend<R: Read>(&mut self, reader: &mut R, count: u8) -> Result<i16> {
        let value = try!(self.get_bits(reader, count));
        Ok(extend(value, count))
    }

    pub fn reset(&mut self) {
        self.bits = 0;
        self.num_bits = 0;
    }

    pub fn take_marker(&mut self) -> Option<Marker> {
        self.marker.take()
    }

    #[inline]
    fn peek_bits(&mut self, count: u8) -> u16 {
        debug_assert!(count <= 16);
        debug_assert!(self.num_bits >= count);

        ((self.bits >> (64 - count)) & ((1 << count) - 1)) as u16
    }

    #[inline]
    fn consume_bits(&mut self, count: u8) {
        debug_assert!(self.num_bits >= count);

        self.bits <<= count as usize;
        self.num_bits -= count;
    }

    fn read_bits<R: Read>(&mut self, reader: &mut R) -> Result<()> {
        while self.num_bits <= 56 {
            // Fill with zero bits if we have reached the end.
            let byte = match self.marker {
                Some(_) => 0,
                None => try!(reader.read_u8()),
            };

            if byte == 0xFF {
                let mut next_byte = try!(reader.read_u8());

                // Check for byte stuffing.
                if next_byte != 0x00 {
                    // We seem to have reached the end of entropy-coded data and encountered a
                    // marker. Since we can't put data back into the reader, we have to continue
                    // reading to identify the marker so we can pass it on.

                    // Section B.1.1.2
                    // "Any marker may optionally be preceded by any number of fill bytes, which are bytes assigned code X’FF’."
                    while next_byte == 0xFF {
                        next_byte = try!(reader.read_u8());
                    }

                    match next_byte {
                        0x00 => return Err(Error::Format("FF 00 found where marker was expected".to_owned())),
                        _    => self.marker = Some(Marker::from_u8(next_byte).unwrap()),
                    }

                    continue;
                }
            }

            self.bits |= (byte as u64) << (56 - self.num_bits);
            self.num_bits += 8;
        }

        Ok(())
    }
}

// Section F.2.2.1
// Figure F.12
fn extend(value: u16, count: u8) -> i16 {
    let vt = 1 << (count as u16 - 1);

    if value < vt {
        value as i16 + (-1 << count as i16) + 1
    } else {
        value as i16
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum HuffmanTableClass {
    DC,
    AC,
}

pub struct HuffmanTable {
    values: Vec<u8>,
    delta: [i32; 16],
    maxcode: [i32; 16],

    lut: [(u8, u8); 1 << LUT_BITS],
    ac_lut: Option<[(i16, u8); 1 << LUT_BITS]>,
}

impl HuffmanTable {
    pub fn new(bits: &[u8; 16], values: &[u8], class: HuffmanTableClass) -> Result<HuffmanTable> {
        let (huffcode, huffsize) = try!(derive_huffman_codes(bits));

        // Section F.2.2.3
        // Figure F.15
        // delta[i] is set to VALPTR(I) - MINCODE(I)
        let mut delta = [0i32; 16];
        let mut maxcode = [-1i32; 16];
        let mut j = 0;

        for i in 0 .. 16 {
            if bits[i] != 0 {
                delta[i] = j as i32 - huffcode[j] as i32;
                j += bits[i] as usize;
                maxcode[i] = huffcode[j - 1] as i32;
            }
        }

        // Build a lookup table for faster decoding.
        let mut lut = [(0u8, 0u8); 1 << LUT_BITS];

        for (i, &size) in huffsize.iter().enumerate().filter(|&(_, &size)| size <= LUT_BITS) {
            let bits_remaining = LUT_BITS - size;
            let start = (huffcode[i] << bits_remaining) as usize;

            for j in 0 .. 1 << bits_remaining {
                lut[start + j] = (values[i], size);
            }
        }

        // Build a lookup table for small AC coefficients which both decodes the value and does the
        // equivalent of receive_extend.
        let ac_lut = match class {
            HuffmanTableClass::DC => None,
            HuffmanTableClass::AC => {
                let mut table = [(0i16, 0u8); 1 << LUT_BITS];

                for (i, &(value, size)) in lut.iter().enumerate() {
                    let run_length = value >> 4;
                    let magnitude_category = value & 0x0f;

                    if magnitude_category > 0 && size + magnitude_category <= LUT_BITS {
                        let unextended_ac_value = (((i << size) & ((1 << LUT_BITS) - 1)) >> (LUT_BITS - magnitude_category)) as u16;
                        let ac_value = extend(unextended_ac_value, magnitude_category);

                        table[i] = (ac_value, (run_length << 4) | (size + magnitude_category));
                    }
                }

                Some(table)
            },
        };

        Ok(HuffmanTable {
            values: values.to_vec(),
            delta: delta,
            maxcode: maxcode,
            lut: lut,
            ac_lut: ac_lut,
        })
    }
}

// Section C.2
fn derive_huffman_codes(bits: &[u8; 16]) -> Result<(Vec<u16>, Vec<u8>)> {
    // Figure C.1
    let huffsize = bits.iter()
                       .enumerate()
                       .fold(Vec::new(), |mut acc, (i, &value)| {
                           let mut repeated_size: Vec<u8> = repeat((i + 1) as u8).take(value as usize).collect();
                           acc.append(&mut repeated_size);
                           acc
                       });

    // Figure C.2
    let mut huffcode = vec![0u16; huffsize.len()];
    let mut code_size = huffsize[0];
    let mut code = 0u16;

    for (i, &size) in huffsize.iter().enumerate() {
        while code_size < size {
            code <<= 1;
            code_size += 1;
        }

        if code as u32 >= (1u32 << size) {
            return Err(Error::Format("bad huffman code length".to_owned()));
        }

        huffcode[i] = code;
        code += 1;
    }

    Ok((huffcode, huffsize))
}
<|endoftext|>


<commit_before>use crate::StrError;

/// Computes the number of divisions for GridSearch aiming at a square/cubic containers
///
/// Note: **long** means the longest direction whereas
///       **other** corresponds to the `not-long` directions.
///
/// ```text
/// ndiv_other = truncate((delta_other/delta_long) * ndiv_long)
/// ndiv_other = max(ndiv_min, ndiv_other)
/// ```
///
/// # Input
///
/// * `ndiv_min` -- minimum number of divisions for the other directions (≥ 1)
/// * `ndiv_long` -- number of divisions for the longest direction (> ndiv_min)
/// * `xmin` -- min coordinates (len = ndim)
/// * `xmax` -- max coordinates (len = ndim); must be greater than min
///
/// # Output
///
/// * `ndiv` -- the number of divisions along each direction (ndim)
///
/// # Examples
///
/// ```
/// use gemlab::util::num_divisions;
/// use gemlab::StrError;
///
/// fn main() -> Result<(), StrError> {
///     let xmin = &[0.0, 0.0];
///     let xmax = &[1.0, 1.0];
///     let ndiv = num_divisions(2, 5, xmin, xmax)?;
///     assert_eq!(ndiv, &[5, 5]);
///
///     let xmax = &[1.0, 10.0];
///     let ndiv = num_divisions(2, 5, xmin, xmax)?;
///     assert_eq!(ndiv, &[2, 5]);
///     Ok(())
/// }
/// ```
pub fn num_divisions(ndiv_min: usize, ndiv_long: usize, xmin: &[f64], xmax: &[f64]) -> Result<Vec<usize>, StrError> {
    if ndiv_min < 1 {
        return Err("ndiv_min must be ≥ 1");
    }
    if ndiv_long <= ndiv_min {
        return Err("ndiv_long must be > ndiv_min");
    }
    if xmin.len() != xmax.len() {
        return Err("xmin.len() must be equal to xmax.len()");
    }
    let ndim = xmin.len();
    if ndim < 2 {
        return Err("ndim must be ≥ 2");
    }
    let delta: Vec<_> = xmin.iter().zip(xmax).map(|(a, b)| *b - *a).collect();
    let mut index_long = 0;
    let mut delta_long = delta[index_long];
    for i in 1..ndim {
        if delta[i] > delta_long {
            index_long = i;
            delta_long = delta[i];
        }
    }
    let mut ndiv = vec![0; ndim];
    for i in 0..ndim {
        if delta[i] <= 0.0 {
            return Err("xmax must be greater than xmin");
        }
        if i == index_long {
            ndiv[i] = ndiv_long;
        } else {
            ndiv[i] = ((delta[i] / delta_long) * (ndiv_long as f64)) as usize;
            ndiv[i] = usize::max(ndiv_min, ndiv[i]);
        }
    }
    Ok(ndiv)
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::num_divisions;
    use crate::StrError;

    #[test]
    fn num_divisions_fails_on_errors() {
        assert_eq!(
            num_divisions(0, 20, &[0.0, 0.0], &[1.0, 1.0]).err(),
            Some("ndiv_min must be ≥ 1")
        );
        assert_eq!(
            num_divisions(2, 1, &[0.0, 0.0], &[1.0, 1.0]).err(),
            Some("ndiv_long must be > ndiv_min")
        );
        assert_eq!(
            num_divisions(2, 3, &[0.0, 0.0], &[1.0, 1.0, 1.0]).err(),
            Some("xmin.len() must be equal to xmax.len()")
        );
        assert_eq!(num_divisions(2, 3, &[0.0], &[1.0]).err(), Some("ndim must be ≥ 2"));
        assert_eq!(
            num_divisions(2, 20, &[2.0, 2.0], &[0.0, 0.0]).err(),
            Some("xmax must be greater than xmin")
        );
    }

    #[test]
    fn num_divisions_works() -> Result<(), StrError> {
        assert_eq!(num_divisions(1, 10, &[0.0, 0.0], &[1.0, 1.0])?, &[10, 10]);
        assert_eq!(num_divisions(2, 10, &[0.0, 0.0], &[1.0, 1.0])?, &[10, 10]);
        assert_eq!(num_divisions(3, 20, &[0.0, 0.0], &[100.0, 100.0])?, &[20, 20]);
        assert_eq!(num_divisions(3, 20, &[0.0, 0.0], &[1.0, 2.0])?, &[10, 20]);
        assert_eq!(num_divisions(3, 20, &[0.0, 0.0], &[2.0, 1.0])?, &[20, 10]);
        assert_eq!(num_divisions(3, 20, &[0.0, 0.0], &[1.0, 4.0])?, &[5, 20]);
        assert_eq!(num_divisions(3, 20, &[0.0, 0.0], &[1.0, 5.0])?, &[4, 20]);
        assert_eq!(num_divisions(2, 20, &[0.0, 0.0], &[1.0, 10.0])?, &[2, 20]);
        assert_eq!(num_divisions(1, 20, &[0.0, 0.0], &[1.0, 100.0])?, &[1, 20]);
        assert_eq!(num_divisions(2, 20, &[0.0, 0.0], &[1.0, 100.0])?, &[2, 20]);
        assert_eq!(num_divisions(3, 20, &[0.0, 0.0], &[10000.0, 1.0])?, &[20, 3]);
        assert_eq!(num_divisions(3, 20, &[0.0, 0.0], &[10.0, 3.0])?, &[20, 6]);
        assert_eq!(num_divisions(3, 20, &[0.0, 0.0], &[10.0, 3.5])?, &[20, 7]);
        assert_eq!(num_divisions(3, 20, &[-1.0, -2.0], &[1.0, 2.0])?, &[10, 20]);
        Ok(())
    }
}
<commit_msg>Use unwrap in num_divisions test<commit_after>use crate::StrError;

/// Computes the number of divisions for GridSearch aiming at a square/cubic containers
///
/// Note: **long** means the longest direction whereas
///       **other** corresponds to the `not-long` directions.
///
/// ```text
/// ndiv_other = truncate((delta_other/delta_long) * ndiv_long)
/// ndiv_other = max(ndiv_min, ndiv_other)
/// ```
///
/// # Input
///
/// * `ndiv_min` -- minimum number of divisions for the other directions (≥ 1)
/// * `ndiv_long` -- number of divisions for the longest direction (> ndiv_min)
/// * `xmin` -- min coordinates (len = ndim)
/// * `xmax` -- max coordinates (len = ndim); must be greater than min
///
/// # Output
///
/// * `ndiv` -- the number of divisions along each direction (ndim)
///
/// # Examples
///
/// ```
/// use gemlab::util::num_divisions;
/// use gemlab::StrError;
///
/// fn main() -> Result<(), StrError> {
///     let xmin = &[0.0, 0.0];
///     let xmax = &[1.0, 1.0];
///     let ndiv = num_divisions(2, 5, xmin, xmax)?;
///     assert_eq!(ndiv, &[5, 5]);
///
///     let xmax = &[1.0, 10.0];
///     let ndiv = num_divisions(2, 5, xmin, xmax)?;
///     assert_eq!(ndiv, &[2, 5]);
///     Ok(())
/// }
/// ```
pub fn num_divisions(ndiv_min: usize, ndiv_long: usize, xmin: &[f64], xmax: &[f64]) -> Result<Vec<usize>, StrError> {
    if ndiv_min < 1 {
        return Err("ndiv_min must be ≥ 1");
    }
    if ndiv_long <= ndiv_min {
        return Err("ndiv_long must be > ndiv_min");
    }
    if xmin.len() != xmax.len() {
        return Err("xmin.len() must be equal to xmax.len()");
    }
    let ndim = xmin.len();
    if ndim < 2 {
        return Err("ndim must be ≥ 2");
    }
    let delta: Vec<_> = xmin.iter().zip(xmax).map(|(a, b)| *b - *a).collect();
    let mut index_long = 0;
    let mut delta_long = delta[index_long];
    for i in 1..ndim {
        if delta[i] > delta_long {
            index_long = i;
            delta_long = delta[i];
        }
    }
    let mut ndiv = vec![0; ndim];
    for i in 0..ndim {
        if delta[i] <= 0.0 {
            return Err("xmax must be greater than xmin");
        }
        if i == index_long {
            ndiv[i] = ndiv_long;
        } else {
            ndiv[i] = ((delta[i] / delta_long) * (ndiv_long as f64)) as usize;
            ndiv[i] = usize::max(ndiv_min, ndiv[i]);
        }
    }
    Ok(ndiv)
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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

    #[test]
    fn num_divisions_fails_on_errors() {
        assert_eq!(
            num_divisions(0, 20, &[0.0, 0.0], &[1.0, 1.0]).err(),
            Some("ndiv_min must be ≥ 1")
        );
        assert_eq!(
            num_divisions(2, 1, &[0.0, 0.0], &[1.0, 1.0]).err(),
            Some("ndiv_long must be > ndiv_min")
        );
        assert_eq!(
            num_divisions(2, 3, &[0.0, 0.0], &[1.0, 1.0, 1.0]).err(),
            Some("xmin.len() must be equal to xmax.len()")
        );
        assert_eq!(num_divisions(2, 3, &[0.0], &[1.0]).err(), Some("ndim must be ≥ 2"));
        assert_eq!(
            num_divisions(2, 20, &[2.0, 2.0], &[0.0, 0.0]).err(),
            Some("xmax must be greater than xmin")
        );
    }

    #[test]
    fn num_divisions_works() {
        assert_eq!(num_divisions(1, 10, &[0.0, 0.0], &[1.0, 1.0]).unwrap(), &[10, 10]);
        assert_eq!(num_divisions(2, 10, &[0.0, 0.0], &[1.0, 1.0]).unwrap(), &[10, 10]);
        assert_eq!(num_divisions(3, 20, &[0.0, 0.0], &[100.0, 100.0]).unwrap(), &[20, 20]);
        assert_eq!(num_divisions(3, 20, &[0.0, 0.0], &[1.0, 2.0]).unwrap(), &[10, 20]);
        assert_eq!(num_divisions(3, 20, &[0.0, 0.0], &[2.0, 1.0]).unwrap(), &[20, 10]);
        assert_eq!(num_divisions(3, 20, &[0.0, 0.0], &[1.0, 4.0]).unwrap(), &[5, 20]);
        assert_eq!(num_divisions(3, 20, &[0.0, 0.0], &[1.0, 5.0]).unwrap(), &[4, 20]);
        assert_eq!(num_divisions(2, 20, &[0.0, 0.0], &[1.0, 10.0]).unwrap(), &[2, 20]);
        assert_eq!(num_divisions(1, 20, &[0.0, 0.0], &[1.0, 100.0]).unwrap(), &[1, 20]);
        assert_eq!(num_divisions(2, 20, &[0.0, 0.0], &[1.0, 100.0]).unwrap(), &[2, 20]);
        assert_eq!(num_divisions(3, 20, &[0.0, 0.0], &[10000.0, 1.0]).unwrap(), &[20, 3]);
        assert_eq!(num_divisions(3, 20, &[0.0, 0.0], &[10.0, 3.0]).unwrap(), &[20, 6]);
        assert_eq!(num_divisions(3, 20, &[0.0, 0.0], &[10.0, 3.5]).unwrap(), &[20, 7]);
        assert_eq!(num_divisions(3, 20, &[-1.0, -2.0], &[1.0, 2.0]).unwrap(), &[10, 20]);
    }
}
<|endoftext|>


<commit_before>
/// Achitecture-specific code - AMD64 (aka x86-64)
#[macro_use]
#[cfg(arch="amd64")] #[path="amd64/mod.rs"]
#[doc(hidden)]
pub mod imp;	// Needs to be pub for exports to be avaliable

#[macro_use]
#[cfg(arch="armv7")] #[path="armv7/mod.rs"]
#[doc(hidden)]
pub mod imp;

// If on x86/amd64, import ACPI
#[cfg(arch="amd64")]
pub use self::imp::acpi;

pub mod memory {
	pub type PAddr = ::arch::imp::memory::PAddr;
	pub type VAddr = ::arch::imp::memory::VAddr;
	pub const PAGE_SIZE: usize = ::arch::imp::memory::PAGE_SIZE;

	pub mod addresses {
		use arch::imp::memory::addresses as imp;

		pub fn is_global(addr: usize) -> bool {
			imp::is_global(addr)
		}

		pub const STACK_SIZE: usize = imp::STACK_SIZE;

		pub const USER_END: usize = imp::USER_END;

		pub const STACKS_BASE: usize = imp::STACKS_BASE;
		pub const STACKS_END : usize = imp::STACKS_END ;

		pub const TEMP_BASE: usize = imp::TEMP_BASE;
		pub const TEMP_END : usize = imp::TEMP_END ;

		pub const HARDWARE_BASE: usize = imp::HARDWARE_BASE;
		pub const HARDWARE_END : usize = imp::HARDWARE_END ;

		pub const HEAP_START: usize = imp::HEAP_START;
		//pub const HEAP_END : usize = imp::HEAP_END ;
	}
	pub mod virt {
		use arch::imp::memory::virt as imp;

		pub type AddressSpace = imp::AddressSpace;

		pub fn get_phys<T>(p: *const T) -> ::memory::PAddr {
			imp::get_phys(p)
		}
		pub fn is_reserved<T>(p: *const T) -> bool {
			imp::is_reserved(p)
		}
		pub fn get_info<T>(p: *const T) -> Option<(::memory::PAddr,::memory::virt::ProtectionMode)> {
			imp::get_info(p)
		}

		pub fn is_fixed_alloc(addr: *const (), size: usize) -> bool {
			imp::is_fixed_alloc(addr, size)
		}
		pub unsafe fn fixed_alloc(p: ::memory::PAddr, count: usize) -> Option<*mut ()> {
			imp::fixed_alloc(p, count)
		}

		pub unsafe fn map(a: *mut (), p: ::memory::PAddr, mode: ::memory::virt::ProtectionMode) {
			imp::map(a, p, mode)
		}
		pub unsafe fn reprotect(a: *mut (), mode: ::memory::virt::ProtectionMode) {
			imp::reprotect(a, mode)
		}
		pub unsafe fn unmap(a: *mut ()) -> Option<::memory::PAddr> {
			imp::unmap(a)
		}
	}
	pub mod phys {
		use arch::imp::memory::phys as imp;

		pub fn ref_frame(frame_idx: u64) {
			imp::ref_frame(frame_idx)
		}
		pub fn deref_frame(frame_idx: u64) -> u32 {
			imp::deref_frame(frame_idx)
		}
		pub fn get_multiref_count(frame_idx: u64) -> u32 {
			imp::get_multiref_count(frame_idx)
		}

		pub fn mark_free(frame_idx: u64) -> bool {
			imp::mark_free(frame_idx)
		}
		pub fn mark_used(frame_idx: u64) {
			imp::mark_used(frame_idx)
		}
	}
}

pub mod sync {
	use super::imp::sync as imp;
	pub type Spinlock<T> = imp::Spinlock<T>;
	pub type HeldSpinlock<'a, T: 'a> = imp::HeldSpinlock<'a, T>;
	pub type HeldInterrupts = imp::HeldInterrupts;

	pub fn hold_interrupts() -> HeldInterrupts {
		imp::hold_interrupts()
	}
}
pub mod interrupts {
	use super::imp::interrupts as imp;

	pub type BindError = imp::BindError;
	pub type IRQHandle = imp::IRQHandle;

	pub fn bind_gsi(gsi: usize, handler: fn(*const()), info: *const ()) -> Result<IRQHandle, BindError> {
		imp::bind_gsi(gsi, handler, info)
	}
}
pub mod boot {
	use super::imp::boot as imp;

	pub fn get_boot_string() -> &'static str {
		imp::get_boot_string()
	}

	pub fn get_video_mode() -> Option<::metadevs::video::bootvideo::VideoMode> {
		imp::get_video_mode()
	}
	pub fn get_memory_map() -> &'static [::memory::MemoryMapEnt] {
		imp::get_memory_map()
	}
}
pub mod pci {
	use super::imp::pci as imp;

	pub fn read(a: u32) -> u32 {
		imp::read(a)
	}
	pub fn write(a: u32, v: u32) {
		imp::write(a, v)
	}
}
pub mod threads {
	use lib::mem::Box;
	use super::imp::threads as imp;

	pub type State = imp::State;
	pub fn init_tid0_state() -> State {
		imp::init_tid0_state()
	}

	pub fn set_thread_ptr(t: Box<::threads::Thread>) {
		imp::set_thread_ptr(t)
	}
	pub fn get_thread_ptr() -> Option<Box<::threads::Thread>> {
		imp::get_thread_ptr()
	}
	pub fn borrow_thread() -> *const ::threads::Thread {
		imp::borrow_thread()
	}

	pub fn idle() {
		imp::idle()
	}
	pub fn switch_to(t: Box<::threads::Thread>) {
		imp::switch_to(t)
	}

	pub fn start_thread<F: FnOnce()+Send>(thread: &mut ::threads::Thread, code: F) {
		imp::start_thread(thread, code)
	}
}

pub mod x86_io {
	use super::imp::x86_io as imp;

	pub unsafe fn inb(p: u16) -> u8 { imp::inb(p) }
	pub unsafe fn inw(p: u16) -> u16 { imp::inw(p) }
	pub unsafe fn inl(p: u16) -> u32 { imp::inl(p) }
	pub unsafe fn outb(p: u16, v: u8) { imp::outb(p, v) }
	pub unsafe fn outw(p: u16, v: u16) { imp::outw(p, v) }
	pub unsafe fn outl(p: u16, v: u32) { imp::outl(p, v) }
}

#[inline]
pub fn puts(s: &str) {
	imp::puts(s);
}
#[inline]
pub fn puth(v: u64) {
	imp::puth(v)
}

pub fn cur_timestamp() -> u64 {
	imp::cur_timestamp()
}
pub fn print_backtrace() {
	imp::print_backtrace()
}

pub unsafe fn drop_to_user(entry: usize, stack: usize, args_len: usize) -> ! {
	imp::drop_to_user(entry, stack, args_len)
}

<commit_msg>Kernel - Add inline markers on all arch shims<commit_after>//
//
//

/// Achitecture-specific code - AMD64 (aka x86-64)
#[macro_use]
#[cfg(arch="amd64")] #[path="amd64/mod.rs"]
#[doc(hidden)]
pub mod imp;	// Needs to be pub for exports to be avaliable

#[macro_use]
#[cfg(arch="armv7")] #[path="armv7/mod.rs"]
#[doc(hidden)]
pub mod imp;

// If on x86/amd64, import ACPI
#[cfg(arch="amd64")]
pub use self::imp::acpi;

pub mod memory {
	pub type PAddr = ::arch::imp::memory::PAddr;
	pub type VAddr = ::arch::imp::memory::VAddr;
	pub const PAGE_SIZE: usize = ::arch::imp::memory::PAGE_SIZE;

	pub mod addresses {
		use arch::imp::memory::addresses as imp;

		#[inline]
		pub fn is_global(addr: usize) -> bool {
			imp::is_global(addr)
		}

		pub const STACK_SIZE: usize = imp::STACK_SIZE;

		pub const USER_END: usize = imp::USER_END;

		pub const STACKS_BASE: usize = imp::STACKS_BASE;
		pub const STACKS_END : usize = imp::STACKS_END ;

		pub const TEMP_BASE: usize = imp::TEMP_BASE;
		pub const TEMP_END : usize = imp::TEMP_END ;

		pub const HARDWARE_BASE: usize = imp::HARDWARE_BASE;
		pub const HARDWARE_END : usize = imp::HARDWARE_END ;

		pub const HEAP_START: usize = imp::HEAP_START;
		//pub const HEAP_END : usize = imp::HEAP_END ;
	}
	pub mod virt {
		use arch::imp::memory::virt as imp;

		pub type AddressSpace = imp::AddressSpace;

		#[inline]
		pub fn get_phys<T>(p: *const T) -> ::memory::PAddr {
			imp::get_phys(p)
		}
		#[inline]
		pub fn is_reserved<T>(p: *const T) -> bool {
			imp::is_reserved(p)
		}
		#[inline]
		pub fn get_info<T>(p: *const T) -> Option<(::memory::PAddr,::memory::virt::ProtectionMode)> {
			imp::get_info(p)
		}

		#[inline]
		pub fn is_fixed_alloc(addr: *const (), size: usize) -> bool {
			imp::is_fixed_alloc(addr, size)
		}
		#[inline]
		pub unsafe fn fixed_alloc(p: ::memory::PAddr, count: usize) -> Option<*mut ()> {
			imp::fixed_alloc(p, count)
		}

		#[inline]
		pub unsafe fn map(a: *mut (), p: ::memory::PAddr, mode: ::memory::virt::ProtectionMode) {
			imp::map(a, p, mode)
		}
		#[inline]
		pub unsafe fn reprotect(a: *mut (), mode: ::memory::virt::ProtectionMode) {
			imp::reprotect(a, mode)
		}
		#[inline]
		pub unsafe fn unmap(a: *mut ()) -> Option<::memory::PAddr> {
			imp::unmap(a)
		}
	}
	pub mod phys {
		use arch::imp::memory::phys as imp;

		#[inline]
		pub fn ref_frame(frame_idx: u64) {
			imp::ref_frame(frame_idx)
		}
		#[inline]
		pub fn deref_frame(frame_idx: u64) -> u32 {
			imp::deref_frame(frame_idx)
		}
		#[inline]
		pub fn get_multiref_count(frame_idx: u64) -> u32 {
			imp::get_multiref_count(frame_idx)
		}

		#[inline]
		pub fn mark_free(frame_idx: u64) -> bool {
			imp::mark_free(frame_idx)
		}
		#[inline]
		pub fn mark_used(frame_idx: u64) {
			imp::mark_used(frame_idx)
		}
	}
}

pub mod sync {
	use super::imp::sync as imp;
	pub type Spinlock<T> = imp::Spinlock<T>;
	pub type HeldSpinlock<'a, T: 'a> = imp::HeldSpinlock<'a, T>;
	pub type HeldInterrupts = imp::HeldInterrupts;

	#[inline]
	pub fn hold_interrupts() -> HeldInterrupts {
		imp::hold_interrupts()
	}
}
pub mod interrupts {
	use super::imp::interrupts as imp;

	pub type BindError = imp::BindError;
	pub type IRQHandle = imp::IRQHandle;

	#[inline]
	pub fn bind_gsi(gsi: usize, handler: fn(*const()), info: *const ()) -> Result<IRQHandle, BindError> {
		imp::bind_gsi(gsi, handler, info)
	}
}
pub mod boot {
	use super::imp::boot as imp;

	#[inline]
	pub fn get_boot_string() -> &'static str {
		imp::get_boot_string()
	}
	#[inline]
	pub fn get_video_mode() -> Option<::metadevs::video::bootvideo::VideoMode> {
		imp::get_video_mode()
	}
	#[inline]
	pub fn get_memory_map() -> &'static [::memory::MemoryMapEnt] {
		imp::get_memory_map()
	}
}
pub mod pci {
	use super::imp::pci as imp;

	#[inline]
	pub fn read(a: u32) -> u32 {
		imp::read(a)
	}
	#[inline]
	pub fn write(a: u32, v: u32) {
		imp::write(a, v)
	}
}
pub mod threads {
	use lib::mem::Box;
	use super::imp::threads as imp;

	pub type State = imp::State;

	#[inline]
	pub fn init_tid0_state() -> State {
		imp::init_tid0_state()
	}

	#[inline]
	pub fn set_thread_ptr(t: Box<::threads::Thread>) {
		imp::set_thread_ptr(t)
	}
	#[inline]
	pub fn get_thread_ptr() -> Option<Box<::threads::Thread>> {
		imp::get_thread_ptr()
	}
	#[inline]
	pub fn borrow_thread() -> *const ::threads::Thread {
		imp::borrow_thread()
	}

	#[inline]
	pub fn idle() {
		imp::idle()
	}
	#[inline]
	pub fn switch_to(t: Box<::threads::Thread>) {
		imp::switch_to(t)
	}

	#[inline]
	pub fn start_thread<F: FnOnce()+Send>(thread: &mut ::threads::Thread, code: F) {
		imp::start_thread(thread, code)
	}
}

pub mod x86_io {
	use super::imp::x86_io as imp;

	#[inline]
	pub unsafe fn inb(p: u16) -> u8 { imp::inb(p) }
	#[inline]
	pub unsafe fn inw(p: u16) -> u16 { imp::inw(p) }
	#[inline]
	pub unsafe fn inl(p: u16) -> u32 { imp::inl(p) }
	#[inline]
	pub unsafe fn outb(p: u16, v: u8) { imp::outb(p, v) }
	#[inline]
	pub unsafe fn outw(p: u16, v: u16) { imp::outw(p, v) }
	#[inline]
	pub unsafe fn outl(p: u16, v: u32) { imp::outl(p, v) }
}

#[inline]
pub fn puts(s: &str) {
	imp::puts(s);
}
#[inline]
pub fn puth(v: u64) {
	imp::puth(v)
}

#[inline]
pub fn cur_timestamp() -> u64 {
	imp::cur_timestamp()
}
#[inline]
pub fn print_backtrace() {
	imp::print_backtrace()
}

#[inline]
pub unsafe fn drop_to_user(entry: usize, stack: usize, args_len: usize) -> ! {
	imp::drop_to_user(entry, stack, args_len)
}

<|endoftext|>


<commit_before>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::ast::*;
use crate::syntax::parse::{parser, token};
use crate::syntax::tokenstream::{ThinTokenStream, TokenStream};
use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg};
use std::borrow::Cow;

/// **What it does:** This lint warns when you use `println!("")` to
/// print a newline.
///
/// **Why is this bad?** You should use `println!()`, which is simpler.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// println!("");
/// ```
declare_clippy_lint! {
    pub PRINTLN_EMPTY_STRING,
    style,
    "using `println!(\"\")` with an empty string"
}

/// **What it does:** This lint warns when you use `print!()` with a format
/// string that
/// ends in a newline.
///
/// **Why is this bad?** You should use `println!()` instead, which appends the
/// newline.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// print!("Hello {}!\n", name);
/// ```
/// use println!() instead
/// ```rust
/// println!("Hello {}!", name);
/// ```
declare_clippy_lint! {
    pub PRINT_WITH_NEWLINE,
    style,
    "using `print!()` with a format string that ends in a single newline"
}

/// **What it does:** Checks for printing on *stdout*. The purpose of this lint
/// is to catch debugging remnants.
///
/// **Why is this bad?** People often print on *stdout* while debugging an
/// application and might forget to remove those prints afterward.
///
/// **Known problems:** Only catches `print!` and `println!` calls.
///
/// **Example:**
/// ```rust
/// println!("Hello world!");
/// ```
declare_clippy_lint! {
    pub PRINT_STDOUT,
    restriction,
    "printing on stdout"
}

/// **What it does:** Checks for use of `Debug` formatting. The purpose of this
/// lint is to catch debugging remnants.
///
/// **Why is this bad?** The purpose of the `Debug` trait is to facilitate
/// debugging Rust code. It should not be used in in user-facing output.
///
/// **Example:**
/// ```rust
/// println!("{:?}", foo);
/// ```
declare_clippy_lint! {
    pub USE_DEBUG,
    restriction,
    "use of `Debug`-based formatting"
}

/// **What it does:** This lint warns about the use of literals as `print!`/`println!` args.
///
/// **Why is this bad?** Using literals as `println!` args is inefficient
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
/// **Known problems:** Will also warn with macro calls as arguments that expand to literals
/// -- e.g., `println!("{}", env!("FOO"))`.
///
/// **Example:**
/// ```rust
/// println!("{}", "foo");
/// ```
/// use the literal without formatting:
/// ```rust
/// println!("foo");
/// ```
declare_clippy_lint! {
    pub PRINT_LITERAL,
    style,
    "printing a literal with a format string"
}

/// **What it does:** This lint warns when you use `writeln!(buf, "")` to
/// print a newline.
///
/// **Why is this bad?** You should use `writeln!(buf)`, which is simpler.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// writeln!("");
/// ```
declare_clippy_lint! {
    pub WRITELN_EMPTY_STRING,
    style,
    "using `writeln!(\"\")` with an empty string"
}

/// **What it does:** This lint warns when you use `write!()` with a format
/// string that
/// ends in a newline.
///
/// **Why is this bad?** You should use `writeln!()` instead, which appends the
/// newline.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// write!(buf, "Hello {}!\n", name);
/// ```
declare_clippy_lint! {
    pub WRITE_WITH_NEWLINE,
    style,
    "using `write!()` with a format string that ends in a single newline"
}

/// **What it does:** This lint warns about the use of literals as `write!`/`writeln!` args.
///
/// **Why is this bad?** Using literals as `writeln!` args is inefficient
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
/// **Known problems:** Will also warn with macro calls as arguments that expand to literals
/// -- e.g., `writeln!(buf, "{}", env!("FOO"))`.
///
/// **Example:**
/// ```rust
/// writeln!(buf, "{}", "foo");
/// ```
declare_clippy_lint! {
    pub WRITE_LITERAL,
    style,
    "writing a literal with a format string"
}

#[derive(Copy, Clone, Debug)]
pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(
            PRINT_WITH_NEWLINE,
            PRINTLN_EMPTY_STRING,
            PRINT_STDOUT,
            USE_DEBUG,
            PRINT_LITERAL,
            WRITE_WITH_NEWLINE,
            WRITELN_EMPTY_STRING,
            WRITE_LITERAL
        )
    }
}

impl EarlyLintPass for Pass {
    fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &Mac) {
        if mac.node.path == "println" {
            span_lint(cx, PRINT_STDOUT, mac.span, "use of `println!`");
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false).0 {
                if fmtstr == "" {
                    span_lint_and_sugg(
                        cx,
                        PRINTLN_EMPTY_STRING,
                        mac.span,
                        "using `println!(\"\")`",
                        "replace it with",
                        "println!()".to_string(),
                        Applicability::MachineApplicable,
                    );
                }
            }
        } else if mac.node.path == "print" {
            span_lint(cx, PRINT_STDOUT, mac.span, "use of `print!`");
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false).0 {
                if check_newlines(&fmtstr) {
                    span_lint(
                        cx,
                        PRINT_WITH_NEWLINE,
                        mac.span,
                        "using `print!()` with a format string that ends in a \
                         single newline, consider using `println!()` instead",
                    );
                }
            }
        } else if mac.node.path == "write" {
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, true).0 {
                if check_newlines(&fmtstr) {
                    span_lint(
                        cx,
                        WRITE_WITH_NEWLINE,
                        mac.span,
                        "using `write!()` with a format string that ends in a \
                         single newline, consider using `writeln!()` instead",
                    );
                }
            }
        } else if mac.node.path == "writeln" {
            let check_tts = check_tts(cx, &mac.node.tts, true);
            if let Some(fmtstr) = check_tts.0 {
                if fmtstr == "" {
                    let mut applicability = Applicability::MachineApplicable;
                    let suggestion = check_tts.1.map_or_else(
                        move || {
                            applicability = Applicability::HasPlaceholders;
                            Cow::Borrowed("v")
                        },
                        move |expr| snippet_with_applicability(cx, expr.span, "v", &mut applicability),
                    );

                    span_lint_and_sugg(
                        cx,
                        WRITELN_EMPTY_STRING,
                        mac.span,
                        format!("using `writeln!({}, \"\")`", suggestion).as_str(),
                        "replace it with",
                        format!("writeln!({})", suggestion),
                        applicability,
                    );
                }
            }
        }
    }
}

/// Checks the arguments of `print[ln]!` and `write[ln]!` calls. It will return a tuple of two
/// options. The first part of the tuple is `format_str` of the macros. The second part of the tuple
/// is in the `write[ln]!` case the expression the `format_str` should be written to.
///
/// Example:
///
/// Calling this function on
/// ```rust,ignore
/// writeln!(buf, "string to write: {}", something)
/// ```
/// will return
/// ```rust,ignore
/// (Some("string to write: {}"), Some(buf))
/// ```
fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> (Option<String>, Option<Expr>) {
    use crate::fmt_macros::*;
    let tts = TokenStream::from(tts.clone());
    let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, None, false, false);
    let mut expr: Option<Expr> = None;
    if is_write {
        expr = match parser.parse_expr().map_err(|mut err| err.cancel()) {
            Ok(p) => Some(p.into_inner()),
            Err(_) => return (None, None),
        };
        // might be `writeln!(foo)`
        if parser.expect(&token::Comma).map_err(|mut err| err.cancel()).is_err() {
            return (None, expr);
        }
    }

    let fmtstr = match parser.parse_str().map_err(|mut err| err.cancel()) {
        Ok(token) => token.0.to_string(),
        Err(_) => return (None, expr),
    };
    let tmp = fmtstr.clone();
    let mut args = vec![];
    let mut fmt_parser = Parser::new(&tmp, None);
    while let Some(piece) = fmt_parser.next() {
        if !fmt_parser.errors.is_empty() {
            return (None, expr);
        }
        if let Piece::NextArgument(arg) = piece {
            if arg.format.ty == "?" {
                // FIXME: modify rustc's fmt string parser to give us the current span
                span_lint(cx, USE_DEBUG, parser.prev_span, "use of `Debug`-based formatting");
            }
            args.push(arg);
        }
    }
    let lint = if is_write { WRITE_LITERAL } else { PRINT_LITERAL };
    let mut idx = 0;
    loop {
        const SIMPLE: FormatSpec<'_> = FormatSpec {
            fill: None,
            align: AlignUnknown,
            flags: 0,
            precision: CountImplied,
            width: CountImplied,
            ty: "",
        };
        if !parser.eat(&token::Comma) {
            return (Some(fmtstr), expr);
        }
        let token_expr = match parser.parse_expr().map_err(|mut err| err.cancel()) {
            Ok(expr) => expr,
            Err(_) => return (Some(fmtstr), None),
        };
        match &token_expr.node {
            ExprKind::Lit(_) => {
                let mut all_simple = true;
                let mut seen = false;
                for arg in &args {
                    match arg.position {
                        ArgumentImplicitlyIs(n) | ArgumentIs(n) => {
                            if n == idx {
                                all_simple &= arg.format == SIMPLE;
                                seen = true;
                            }
                        },
                        ArgumentNamed(_) => {},
                    }
                }
                if all_simple && seen {
                    span_lint(cx, lint, token_expr.span, "literal with an empty format string");
                }
                idx += 1;
            },
            ExprKind::Assign(lhs, rhs) => {
                if let ExprKind::Lit(_) = rhs.node {
                    if let ExprKind::Path(_, p) = &lhs.node {
                        let mut all_simple = true;
                        let mut seen = false;
                        for arg in &args {
                            match arg.position {
                                ArgumentImplicitlyIs(_) | ArgumentIs(_) => {},
                                ArgumentNamed(name) => {
                                    if *p == name {
                                        seen = true;
                                        all_simple &= arg.format == SIMPLE;
                                    }
                                },
                            }
                        }
                        if all_simple && seen {
                            span_lint(cx, lint, rhs.span, "literal with an empty format string");
                        }
                    }
                }
            },
            _ => idx += 1,
        }
    }
}

// Checks if `s` constains a single newline that terminates it
fn check_newlines(s: &str) -> bool {
    if s.len() < 2 {
        return false;
    }

    let bytes = s.as_bytes();
    if bytes[bytes.len() - 2] != b'\\' || bytes[bytes.len() - 1] != b'n' {
        return false;
    }

    let mut escaping = false;
    for (index, &byte) in bytes.iter().enumerate() {
        if escaping {
            if byte == b'n' {
                return index == bytes.len() - 1;
            }
            escaping = false;
        } else if byte == b'\\' {
            escaping = true;
        }
    }

    false
}
<commit_msg>rustup https://github.com/rust-lang/rust/pull/57069<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use crate::rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use crate::rustc::{declare_tool_lint, lint_array};
use crate::rustc_errors::Applicability;
use crate::syntax::ast::*;
use crate::syntax::parse::{parser, token};
use crate::syntax::tokenstream::{ThinTokenStream, TokenStream};
use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_sugg};
use std::borrow::Cow;

/// **What it does:** This lint warns when you use `println!("")` to
/// print a newline.
///
/// **Why is this bad?** You should use `println!()`, which is simpler.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// println!("");
/// ```
declare_clippy_lint! {
    pub PRINTLN_EMPTY_STRING,
    style,
    "using `println!(\"\")` with an empty string"
}

/// **What it does:** This lint warns when you use `print!()` with a format
/// string that
/// ends in a newline.
///
/// **Why is this bad?** You should use `println!()` instead, which appends the
/// newline.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// print!("Hello {}!\n", name);
/// ```
/// use println!() instead
/// ```rust
/// println!("Hello {}!", name);
/// ```
declare_clippy_lint! {
    pub PRINT_WITH_NEWLINE,
    style,
    "using `print!()` with a format string that ends in a single newline"
}

/// **What it does:** Checks for printing on *stdout*. The purpose of this lint
/// is to catch debugging remnants.
///
/// **Why is this bad?** People often print on *stdout* while debugging an
/// application and might forget to remove those prints afterward.
///
/// **Known problems:** Only catches `print!` and `println!` calls.
///
/// **Example:**
/// ```rust
/// println!("Hello world!");
/// ```
declare_clippy_lint! {
    pub PRINT_STDOUT,
    restriction,
    "printing on stdout"
}

/// **What it does:** Checks for use of `Debug` formatting. The purpose of this
/// lint is to catch debugging remnants.
///
/// **Why is this bad?** The purpose of the `Debug` trait is to facilitate
/// debugging Rust code. It should not be used in in user-facing output.
///
/// **Example:**
/// ```rust
/// println!("{:?}", foo);
/// ```
declare_clippy_lint! {
    pub USE_DEBUG,
    restriction,
    "use of `Debug`-based formatting"
}

/// **What it does:** This lint warns about the use of literals as `print!`/`println!` args.
///
/// **Why is this bad?** Using literals as `println!` args is inefficient
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
/// **Known problems:** Will also warn with macro calls as arguments that expand to literals
/// -- e.g., `println!("{}", env!("FOO"))`.
///
/// **Example:**
/// ```rust
/// println!("{}", "foo");
/// ```
/// use the literal without formatting:
/// ```rust
/// println!("foo");
/// ```
declare_clippy_lint! {
    pub PRINT_LITERAL,
    style,
    "printing a literal with a format string"
}

/// **What it does:** This lint warns when you use `writeln!(buf, "")` to
/// print a newline.
///
/// **Why is this bad?** You should use `writeln!(buf)`, which is simpler.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// writeln!("");
/// ```
declare_clippy_lint! {
    pub WRITELN_EMPTY_STRING,
    style,
    "using `writeln!(\"\")` with an empty string"
}

/// **What it does:** This lint warns when you use `write!()` with a format
/// string that
/// ends in a newline.
///
/// **Why is this bad?** You should use `writeln!()` instead, which appends the
/// newline.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// write!(buf, "Hello {}!\n", name);
/// ```
declare_clippy_lint! {
    pub WRITE_WITH_NEWLINE,
    style,
    "using `write!()` with a format string that ends in a single newline"
}

/// **What it does:** This lint warns about the use of literals as `write!`/`writeln!` args.
///
/// **Why is this bad?** Using literals as `writeln!` args is inefficient
/// (c.f., https://github.com/matthiaskrgr/rust-str-bench) and unnecessary
/// (i.e., just put the literal in the format string)
///
/// **Known problems:** Will also warn with macro calls as arguments that expand to literals
/// -- e.g., `writeln!(buf, "{}", env!("FOO"))`.
///
/// **Example:**
/// ```rust
/// writeln!(buf, "{}", "foo");
/// ```
declare_clippy_lint! {
    pub WRITE_LITERAL,
    style,
    "writing a literal with a format string"
}

#[derive(Copy, Clone, Debug)]
pub struct Pass;

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(
            PRINT_WITH_NEWLINE,
            PRINTLN_EMPTY_STRING,
            PRINT_STDOUT,
            USE_DEBUG,
            PRINT_LITERAL,
            WRITE_WITH_NEWLINE,
            WRITELN_EMPTY_STRING,
            WRITE_LITERAL
        )
    }
}

impl EarlyLintPass for Pass {
    fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &Mac) {
        if mac.node.path == "println" {
            span_lint(cx, PRINT_STDOUT, mac.span, "use of `println!`");
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false).0 {
                if fmtstr == "" {
                    span_lint_and_sugg(
                        cx,
                        PRINTLN_EMPTY_STRING,
                        mac.span,
                        "using `println!(\"\")`",
                        "replace it with",
                        "println!()".to_string(),
                        Applicability::MachineApplicable,
                    );
                }
            }
        } else if mac.node.path == "print" {
            span_lint(cx, PRINT_STDOUT, mac.span, "use of `print!`");
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, false).0 {
                if check_newlines(&fmtstr) {
                    span_lint(
                        cx,
                        PRINT_WITH_NEWLINE,
                        mac.span,
                        "using `print!()` with a format string that ends in a \
                         single newline, consider using `println!()` instead",
                    );
                }
            }
        } else if mac.node.path == "write" {
            if let Some(fmtstr) = check_tts(cx, &mac.node.tts, true).0 {
                if check_newlines(&fmtstr) {
                    span_lint(
                        cx,
                        WRITE_WITH_NEWLINE,
                        mac.span,
                        "using `write!()` with a format string that ends in a \
                         single newline, consider using `writeln!()` instead",
                    );
                }
            }
        } else if mac.node.path == "writeln" {
            let check_tts = check_tts(cx, &mac.node.tts, true);
            if let Some(fmtstr) = check_tts.0 {
                if fmtstr == "" {
                    let mut applicability = Applicability::MachineApplicable;
                    let suggestion = check_tts.1.map_or_else(
                        move || {
                            applicability = Applicability::HasPlaceholders;
                            Cow::Borrowed("v")
                        },
                        move |expr| snippet_with_applicability(cx, expr.span, "v", &mut applicability),
                    );

                    span_lint_and_sugg(
                        cx,
                        WRITELN_EMPTY_STRING,
                        mac.span,
                        format!("using `writeln!({}, \"\")`", suggestion).as_str(),
                        "replace it with",
                        format!("writeln!({})", suggestion),
                        applicability,
                    );
                }
            }
        }
    }
}

/// Checks the arguments of `print[ln]!` and `write[ln]!` calls. It will return a tuple of two
/// options. The first part of the tuple is `format_str` of the macros. The second part of the tuple
/// is in the `write[ln]!` case the expression the `format_str` should be written to.
///
/// Example:
///
/// Calling this function on
/// ```rust,ignore
/// writeln!(buf, "string to write: {}", something)
/// ```
/// will return
/// ```rust,ignore
/// (Some("string to write: {}"), Some(buf))
/// ```
fn check_tts<'a>(cx: &EarlyContext<'a>, tts: &ThinTokenStream, is_write: bool) -> (Option<String>, Option<Expr>) {
    use crate::fmt_macros::*;
    let tts = TokenStream::from(tts.clone());
    let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, None, false, false);
    let mut expr: Option<Expr> = None;
    if is_write {
        expr = match parser.parse_expr().map_err(|mut err| err.cancel()) {
            Ok(p) => Some(p.into_inner()),
            Err(_) => return (None, None),
        };
        // might be `writeln!(foo)`
        if parser.expect(&token::Comma).map_err(|mut err| err.cancel()).is_err() {
            return (None, expr);
        }
    }

    let fmtstr = match parser.parse_str().map_err(|mut err| err.cancel()) {
        Ok(token) => token.0.to_string(),
        Err(_) => return (None, expr),
    };
    let tmp = fmtstr.clone();
    let mut args = vec![];
    let mut fmt_parser = Parser::new(&tmp, None, Vec::new(), false);
    while let Some(piece) = fmt_parser.next() {
        if !fmt_parser.errors.is_empty() {
            return (None, expr);
        }
        if let Piece::NextArgument(arg) = piece {
            if arg.format.ty == "?" {
                // FIXME: modify rustc's fmt string parser to give us the current span
                span_lint(cx, USE_DEBUG, parser.prev_span, "use of `Debug`-based formatting");
            }
            args.push(arg);
        }
    }
    let lint = if is_write { WRITE_LITERAL } else { PRINT_LITERAL };
    let mut idx = 0;
    loop {
        const SIMPLE: FormatSpec<'_> = FormatSpec {
            fill: None,
            align: AlignUnknown,
            flags: 0,
            precision: CountImplied,
            width: CountImplied,
            ty: "",
        };
        if !parser.eat(&token::Comma) {
            return (Some(fmtstr), expr);
        }
        let token_expr = match parser.parse_expr().map_err(|mut err| err.cancel()) {
            Ok(expr) => expr,
            Err(_) => return (Some(fmtstr), None),
        };
        match &token_expr.node {
            ExprKind::Lit(_) => {
                let mut all_simple = true;
                let mut seen = false;
                for arg in &args {
                    match arg.position {
                        ArgumentImplicitlyIs(n) | ArgumentIs(n) => {
                            if n == idx {
                                all_simple &= arg.format == SIMPLE;
                                seen = true;
                            }
                        },
                        ArgumentNamed(_) => {},
                    }
                }
                if all_simple && seen {
                    span_lint(cx, lint, token_expr.span, "literal with an empty format string");
                }
                idx += 1;
            },
            ExprKind::Assign(lhs, rhs) => {
                if let ExprKind::Lit(_) = rhs.node {
                    if let ExprKind::Path(_, p) = &lhs.node {
                        let mut all_simple = true;
                        let mut seen = false;
                        for arg in &args {
                            match arg.position {
                                ArgumentImplicitlyIs(_) | ArgumentIs(_) => {},
                                ArgumentNamed(name) => {
                                    if *p == name {
                                        seen = true;
                                        all_simple &= arg.format == SIMPLE;
                                    }
                                },
                            }
                        }
                        if all_simple && seen {
                            span_lint(cx, lint, rhs.span, "literal with an empty format string");
                        }
                    }
                }
            },
            _ => idx += 1,
        }
    }
}

// Checks if `s` constains a single newline that terminates it
fn check_newlines(s: &str) -> bool {
    if s.len() < 2 {
        return false;
    }

    let bytes = s.as_bytes();
    if bytes[bytes.len() - 2] != b'\\' || bytes[bytes.len() - 1] != b'n' {
        return false;
    }

    let mut escaping = false;
    for (index, &byte) in bytes.iter().enumerate() {
        if escaping {
            if byte == b'n' {
                return index == bytes.len() - 1;
            }
            escaping = false;
        } else if byte == b'\\' {
            escaping = true;
        }
    }

    false
}
<|endoftext|>


<commit_before>// Cymbalum, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

//! Saving properties of the simulation to some stream (file or stdout mainly)
use std::io::prelude::*;
use std::io;
use std::fs::File;
use std::path::{Path, PathBuf};

use utils;
use system::System;
use input::{Trajectory, TrajectoryResult};

/// The `Output` trait define the interface for all the quantities outputed by
/// the simulation during the run. An Output can be a text or a binary data
/// file, an image, a text log, …
pub trait Output {
    /// Function called once at the beggining of the simulation, which allow
    /// for some setup of the output if needed.
    fn setup(&mut self, _: &System) {}

    /// Write the output from the system.
    fn write(&mut self, system: &System);

    /// Function called once at the end of the simulation.
    fn finish(&mut self, _: &System) {}
}

/******************************************************************************/
/// The `TrajectoryOutput` allow to write the trajectory of the system to a
/// file, using any format supported by the
/// [Chemfiles](http://chemfiles.readthedocs.org/en/latest/formats.html) library.
pub struct TrajectoryOutput {
    file: Trajectory,
}

impl TrajectoryOutput {
    /// Create a new `TrajectoryOutput` writing to `filename`. The file is
    /// replaced if it already exists.
    pub fn new<'a, S>(filename: S) -> TrajectoryResult<TrajectoryOutput> where S: Into<&'a str> {
        Ok(TrajectoryOutput{
            file: try!(Trajectory::create(filename.into()))
        })
    }
}

impl Output for TrajectoryOutput {
    fn write(&mut self, system: &System) {
        match self.file.write(system) {
            Ok(()) => (),
            Err(err) => {
                fatal_error!("Error in while writing trajectory: {}", err.message());
            }
        }
    }
}

/******************************************************************************/
/// The `CellOutput` write all the components of a cell to a file . The columns
/// in the file contains the following values: `A B C α β γ`.
pub struct CellOutput {
    file: File,
    path: PathBuf
}

impl CellOutput {
    /// Create a new `CellOutput` writing to `filename`. The file is replaced if
    /// it already exists.
    pub fn new<P: AsRef<Path>>(filename: P) -> Result<CellOutput, io::Error> {
        Ok(CellOutput{
            file: try!(File::create(filename.as_ref())),
            path: filename.as_ref().to_owned(),
        })
    }
}

impl Output for CellOutput {
    fn setup(&mut self, _: &System) {
        if let Err(err) = writeln!(&mut self.file, "# Unit cell of the simulation") {
            // Do panic in early time
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
        if let Err(err) = writeln!(&mut self.file, "# Step A/Å B/Å C/Å α/deg β/deg γ/deg") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }

    fn write(&mut self, system: &System) {
        let cell = system.cell();
        if let Err(err) = writeln!(
            &mut self.file, "{} {} {} {} {} {} {}",
            system.step(), cell.a(), cell.b(), cell.c(), cell.alpha(), cell.beta(), cell.gamma()
        ) {
            // Do not panic during the simulation
            error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }
}

/******************************************************************************/
/// The `EnergyOutput` write the energy of the system to a text file, organized
/// as: `PotentialEnergy     KineticEnergy     TotalEnergy`.
pub struct EnergyOutput {
    file: File,
    path: PathBuf
}

impl EnergyOutput {
    /// Create a new `EnergyOutput` writing to `filename`. The file is replaced
    /// if it already exists.
    pub fn new<P: AsRef<Path>>(filename: P) -> Result<EnergyOutput, io::Error> {
        Ok(EnergyOutput{
            file: try!(File::create(filename.as_ref())),
            path: filename.as_ref().to_owned(),
        })
    }
}

impl Output for EnergyOutput {
    fn setup(&mut self, _: &System) {
        if let Err(err) = writeln!(&mut self.file, "# Energy of the simulation (kJ/mol)") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
        if let Err(err) = writeln!(&mut self.file, "# Step Potential Kinetic Total") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }

    fn write(&mut self, system: &System) {
        let potential = utils::unit_to(system.potential_energy(), "kJ/mol");
        let kinetic = utils::unit_to(system.kinetic_energy(), "kJ/mol");
        let total = utils::unit_to(system.total_energy(), "kJ/mol");
        if let Err(err) = writeln!(&mut self.file, "{} {} {} {}", system.step(), potential, kinetic, total) {
            error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }
}

/******************************************************************************/
/// The `PropertiesOutput` write various physical properties of the system to
/// a file. These properties are:
///
/// - volume of the unit cell;
/// - instant temperature;
/// - instant pressure;
pub struct PropertiesOutput {
    file: File,
    path: PathBuf,
}

impl PropertiesOutput {
    /// Create a new `PropertiesOutput` writing to `filename`. The file is replaced
    /// if it already exists.
    pub fn new<P: AsRef<Path>>(filename: P) -> Result<PropertiesOutput, io::Error> {
        Ok(PropertiesOutput{
            file: try!(File::create(filename.as_ref())),
            path: filename.as_ref().to_owned(),
        })
    }
}

impl Output for PropertiesOutput {
    fn setup(&mut self, _: &System) {
        if let Err(err) = writeln!(&mut self.file, "# Physical properties of the simulation") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
        if let Err(err) = writeln!(&mut self.file, "# Step Volume/A^3 Temperature/K Pressure/bar") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }

    fn write(&mut self, system: &System) {
        let volume = utils::unit_to(system.volume(), "A^3");
        let temperature = utils::unit_to(system.temperature(), "K");
        let pressure = utils::unit_to(system.pressure(), "bar");
        if let Err(err) = writeln!(&mut self.file, "{} {} {} {}", system.step(), volume, temperature, pressure) {
            error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::prelude::*;
    use std::fs;

    use super::*;
    use system::*;
    use types::*;
    use potentials::*;
    use units;

    fn testing_system() -> System {
        let mut system = System::from_cell(UnitCell::cubic(10.0));;

        system.add_particle(Particle::new("F"));
        system[0].position = Vector3D::zero();

        system.add_particle(Particle::new("F"));
        system[1].position = Vector3D::new(1.3, 0.0, 0.0);

        system.add_pair_interaction("F", "F",
            Box::new(Harmonic{k: units::from(300.0, "kJ/mol/A^2").unwrap(), x0: units::from(1.2, "A").unwrap()}));
        return system;
    }

    fn check_file_content(filename: &str, content: &str) {
        let mut file = fs::File::open(filename).unwrap();
        let mut buffer = String::new();
        let _ = file.read_to_string(&mut buffer).unwrap();

        assert_eq!(buffer, content);
    }

    #[test]
    fn trajectory() {
        let filename = "testing-trajectory-output.xyz";
        let system = testing_system();
        {
            let mut out = TrajectoryOutput::new(filename).unwrap();
            out.setup(&system);
            out.write(&system);
            out.finish(&system);
        }

        let content = "2
Written by the chemfiles library
F 0 0 0
F 1.3 0 0
";

        check_file_content(filename, content);
        fs::remove_file(filename).unwrap();
    }

    #[test]
    fn energy() {
        let filename = "testing-energy-output.dat";
        let system = testing_system();
        {
            let mut out = EnergyOutput::new(filename).unwrap();
            out.setup(&system);
            out.write(&system);
            out.finish(&system);
        }

        let content = "\
# Energy of the simulation (kJ/mol)
# Step Potential Kinetic Total
0 1.5000000000000027 0 1.5000000000000027
";

        check_file_content(filename, content);
        fs::remove_file(filename).unwrap();
    }

    #[test]
    fn cell() {
        let filename = "testing-cell-output.dat";
        let system = testing_system();
        {
            let mut out = CellOutput::new(filename).unwrap();
            out.setup(&system);
            out.write(&system);
            out.finish(&system);
        }

        let content = "\
# Unit cell of the simulation
# Step A/Å B/Å C/Å α/deg β/deg γ/deg
0 10 10 10 90 90 90
";

        check_file_content(filename, content);
        fs::remove_file(filename).unwrap();
    }

    #[test]
    fn properties() {
        let filename = "testing-properties-output.dat";
        let system = testing_system();
        {
            let mut out = PropertiesOutput::new(filename).unwrap();
            out.setup(&system);
            out.write(&system);
            out.finish(&system);
        }

        let content = "\
# Physical properties of the simulation
# Step Volume/A^3 Temperature/K Pressure/bar
0 1000 0 -215.87004181115455
";
        check_file_content(filename, content);
        fs::remove_file(filename).unwrap();
    }
}
<commit_msg>More temporary files in tests<commit_after>// Cymbalum, an extensible molecular simulation engine
// Copyright (C) 2015-2016 G. Fraux — BSD license

//! Saving properties of the simulation to some stream (file or stdout mainly)
use std::io::prelude::*;
use std::io;
use std::fs::File;
use std::path::{Path, PathBuf};

use utils;
use system::System;
use input::{Trajectory, TrajectoryResult};

/// The `Output` trait define the interface for all the quantities outputed by
/// the simulation during the run. An Output can be a text or a binary data
/// file, an image, a text log, …
pub trait Output {
    /// Function called once at the beggining of the simulation, which allow
    /// for some setup of the output if needed.
    fn setup(&mut self, _: &System) {}

    /// Write the output from the system.
    fn write(&mut self, system: &System);

    /// Function called once at the end of the simulation.
    fn finish(&mut self, _: &System) {}
}

/******************************************************************************/
/// The `TrajectoryOutput` allow to write the trajectory of the system to a
/// file, using any format supported by the
/// [Chemfiles](http://chemfiles.readthedocs.org/en/latest/formats.html) library.
pub struct TrajectoryOutput {
    file: Trajectory,
}

impl TrajectoryOutput {
    /// Create a new `TrajectoryOutput` writing to `filename`. The file is
    /// replaced if it already exists.
    pub fn new<'a, P>(path: P) -> TrajectoryResult<TrajectoryOutput> where P: AsRef<Path> {
        Ok(TrajectoryOutput{
            file: try!(Trajectory::create(path))
        })
    }
}

impl Output for TrajectoryOutput {
    fn write(&mut self, system: &System) {
        match self.file.write(system) {
            Ok(()) => (),
            Err(err) => {
                fatal_error!("Error in while writing trajectory: {}", err.message());
            }
        }
    }
}

/******************************************************************************/
/// The `CellOutput` write all the components of a cell to a file . The columns
/// in the file contains the following values: `A B C α β γ`.
pub struct CellOutput {
    file: File,
    path: PathBuf
}

impl CellOutput {
    /// Create a new `CellOutput` writing to `filename`. The file is replaced if
    /// it already exists.
    pub fn new<P: AsRef<Path>>(filename: P) -> Result<CellOutput, io::Error> {
        Ok(CellOutput{
            file: try!(File::create(filename.as_ref())),
            path: filename.as_ref().to_owned(),
        })
    }
}

impl Output for CellOutput {
    fn setup(&mut self, _: &System) {
        if let Err(err) = writeln!(&mut self.file, "# Unit cell of the simulation") {
            // Do panic in early time
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
        if let Err(err) = writeln!(&mut self.file, "# Step A/Å B/Å C/Å α/deg β/deg γ/deg") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }

    fn write(&mut self, system: &System) {
        let cell = system.cell();
        if let Err(err) = writeln!(
            &mut self.file, "{} {} {} {} {} {} {}",
            system.step(), cell.a(), cell.b(), cell.c(), cell.alpha(), cell.beta(), cell.gamma()
        ) {
            // Do not panic during the simulation
            error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }
}

/******************************************************************************/
/// The `EnergyOutput` write the energy of the system to a text file, organized
/// as: `PotentialEnergy     KineticEnergy     TotalEnergy`.
pub struct EnergyOutput {
    file: File,
    path: PathBuf
}

impl EnergyOutput {
    /// Create a new `EnergyOutput` writing to `filename`. The file is replaced
    /// if it already exists.
    pub fn new<P: AsRef<Path>>(filename: P) -> Result<EnergyOutput, io::Error> {
        Ok(EnergyOutput{
            file: try!(File::create(filename.as_ref())),
            path: filename.as_ref().to_owned(),
        })
    }
}

impl Output for EnergyOutput {
    fn setup(&mut self, _: &System) {
        if let Err(err) = writeln!(&mut self.file, "# Energy of the simulation (kJ/mol)") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
        if let Err(err) = writeln!(&mut self.file, "# Step Potential Kinetic Total") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }

    fn write(&mut self, system: &System) {
        let potential = utils::unit_to(system.potential_energy(), "kJ/mol");
        let kinetic = utils::unit_to(system.kinetic_energy(), "kJ/mol");
        let total = utils::unit_to(system.total_energy(), "kJ/mol");
        if let Err(err) = writeln!(&mut self.file, "{} {} {} {}", system.step(), potential, kinetic, total) {
            error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }
}

/******************************************************************************/
/// The `PropertiesOutput` write various physical properties of the system to
/// a file. These properties are:
///
/// - volume of the unit cell;
/// - instant temperature;
/// - instant pressure;
pub struct PropertiesOutput {
    file: File,
    path: PathBuf,
}

impl PropertiesOutput {
    /// Create a new `PropertiesOutput` writing to `filename`. The file is replaced
    /// if it already exists.
    pub fn new<P: AsRef<Path>>(filename: P) -> Result<PropertiesOutput, io::Error> {
        Ok(PropertiesOutput{
            file: try!(File::create(filename.as_ref())),
            path: filename.as_ref().to_owned(),
        })
    }
}

impl Output for PropertiesOutput {
    fn setup(&mut self, _: &System) {
        if let Err(err) = writeln!(&mut self.file, "# Physical properties of the simulation") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
        if let Err(err) = writeln!(&mut self.file, "# Step Volume/A^3 Temperature/K Pressure/bar") {
            fatal_error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }

    fn write(&mut self, system: &System) {
        let volume = utils::unit_to(system.volume(), "A^3");
        let temperature = utils::unit_to(system.temperature(), "K");
        let pressure = utils::unit_to(system.pressure(), "bar");
        if let Err(err) = writeln!(&mut self.file, "{} {} {} {}", system.step(), volume, temperature, pressure) {
            error!("Could not write to file '{}': {:?}", self.path.display(), err);
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate tempfile;
    use self::tempfile::{NamedTempFile, NamedTempFileOptions};

    use std::io::prelude::*;
    use std::fs::File;

    use super::*;
    use system::*;
    use types::*;
    use potentials::*;
    use units;

    fn testing_system() -> System {
        let mut system = System::from_cell(UnitCell::cubic(10.0));;

        system.add_particle(Particle::new("F"));
        system[0].position = Vector3D::zero();

        system.add_particle(Particle::new("F"));
        system[1].position = Vector3D::new(1.3, 0.0, 0.0);

        system.add_pair_interaction("F", "F",
            Box::new(Harmonic{k: units::from(300.0, "kJ/mol/A^2").unwrap(), x0: units::from(1.2, "A").unwrap()}));
        return system;
    }

    fn check_file_content(mut file: File, content: &str) {
        let mut buffer = String::new();
        let _ = file.read_to_string(&mut buffer).unwrap();

        assert_eq!(buffer, content);
    }

    #[test]
    fn trajectory() {
        let tempfile = NamedTempFileOptions::new().suffix(".xyz").create().unwrap();
        let system = testing_system();
        {
            let mut out = TrajectoryOutput::new(tempfile.path()).unwrap();
            out.setup(&system);
            out.write(&system);
            out.finish(&system);
        }

        let content = "2
Written by the chemfiles library
F 0 0 0
F 1.3 0 0
";
        let file = tempfile.reopen().unwrap();
        check_file_content(file, content);
    }

    #[test]
    fn energy() {
        let tempfile = NamedTempFile::new().unwrap();
        let system = testing_system();
        {
            let mut out = EnergyOutput::new(tempfile.path()).unwrap();
            out.setup(&system);
            out.write(&system);
            out.finish(&system);
        }

        let content = "\
# Energy of the simulation (kJ/mol)
# Step Potential Kinetic Total
0 1.5000000000000027 0 1.5000000000000027
";

        let file = tempfile.reopen().unwrap();
        check_file_content(file, content);
    }

    #[test]
    fn cell() {
        let tempfile = NamedTempFile::new().unwrap();
        let system = testing_system();
        {
            let mut out = CellOutput::new(tempfile.path()).unwrap();
            out.setup(&system);
            out.write(&system);
            out.finish(&system);
        }

        let content = "\
# Unit cell of the simulation
# Step A/Å B/Å C/Å α/deg β/deg γ/deg
0 10 10 10 90 90 90
";

        let file = tempfile.reopen().unwrap();
        check_file_content(file, content);
    }

    #[test]
    fn properties() {
        let tempfile = NamedTempFile::new().unwrap();
        let system = testing_system();
        {
            let mut out = PropertiesOutput::new(tempfile.path()).unwrap();
            out.setup(&system);
            out.write(&system);
            out.finish(&system);
        }

        let content = "\
# Physical properties of the simulation
# Step Volume/A^3 Temperature/K Pressure/bar
0 1000 0 -215.87004181115455
";

        let file = tempfile.reopen().unwrap();
        check_file_content(file, content);
    }
}
<|endoftext|>


<commit_before>use std::fmt;

/// The enum represents an error code that are used in `RST_STREAM` and `GOAWAY` frames.
/// These are defined in [Section 7](http://http2.github.io/http2-spec/#ErrorCodes) of the HTTP/2
/// spec.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorCode {
    /// The associated condition is not a result of an error. For example, a GOAWAY might include
    /// this code to indicate graceful shutdown of a connection.
    NoError = 0x0,
    /// The endpoint detected an unspecific protocol error. This error is for use when a more
    /// specific error code is not available.
    ProtocolError = 0x1,
    /// The endpoint encountered an unexpected internal error.
    InternalError = 0x2,
    /// The endpoint detected that its peer violated the flow-control protocol.
    FlowControlError = 0x3,
    /// The endpoint sent a SETTINGS frame but did not receive a response in a timely manner. See
    /// Section 6.5.3 ("Settings Synchronization").
    SettingsTimeout = 0x4,
    /// The endpoint received a frame after a stream was half-closed.
    StreamClosed = 0x5,
    /// The endpoint received a frame with an invalid size.
    FrameSizeError = 0x6,
    /// The endpoint refused the stream prior to performing any application processing (see Section
    /// 8.1.4 for details).
    RefusedStream = 0x7,
    /// Used by the endpoint to indicate that the stream is no longer needed.
    Cancel = 0x8,
    /// The endpoint is unable to maintain the header compression context for the connection.
    CompressionError = 0x9,
    /// The connection established in response to a CONNECT request (Section 8.3) was reset or
    /// abnormally closed.
    ConnectError = 0xa,
    /// The endpoint detected that its peer is exhibiting a behavior that might be generating
    /// excessive load.
    EnhanceYourCalm = 0xb,
    /// The underlying transport has properties that do not meet minimum security requirements (see
    /// Section 9.2).
    InadequateSecurity = 0xc,
    /// The endpoint requires that HTTP/1.1 be used instead of HTTP/2.
    Http11Required = 0xd,
}

impl ErrorCode {
    fn try_from(error_code: u32) -> Result<ErrorCode, u32> {
        Ok(match error_code {
            0x0 => ErrorCode::NoError,
            0x1 => ErrorCode::ProtocolError,
            0x2 => ErrorCode::InternalError,
            0x3 => ErrorCode::FlowControlError,
            0x4 => ErrorCode::SettingsTimeout,
            0x5 => ErrorCode::StreamClosed,
            0x6 => ErrorCode::FrameSizeError,
            0x7 => ErrorCode::RefusedStream,
            0x8 => ErrorCode::Cancel,
            0x9 => ErrorCode::CompressionError,
            0xa => ErrorCode::ConnectError,
            0xb => ErrorCode::EnhanceYourCalm,
            0xc => ErrorCode::InadequateSecurity,
            0xd => ErrorCode::Http11Required,
            // According to the spec, unknown error codes MAY be treated as equivalent to
            // INTERNAL_ERROR.
            _ => return Err(error_code),
        })
    }
}

impl From<u32> for ErrorCode {
    /// Converts the given `u32` number to the appropriate `ErrorCode` variant.
    fn from(code: u32) -> ErrorCode {
        match code {
            0x0 => ErrorCode::NoError,
            0x1 => ErrorCode::ProtocolError,
            0x2 => ErrorCode::InternalError,
            0x3 => ErrorCode::FlowControlError,
            0x4 => ErrorCode::SettingsTimeout,
            0x5 => ErrorCode::StreamClosed,
            0x6 => ErrorCode::FrameSizeError,
            0x7 => ErrorCode::RefusedStream,
            0x8 => ErrorCode::Cancel,
            0x9 => ErrorCode::CompressionError,
            0xa => ErrorCode::ConnectError,
            0xb => ErrorCode::EnhanceYourCalm,
            0xc => ErrorCode::InadequateSecurity,
            0xd => ErrorCode::Http11Required,
            // According to the spec, unknown error codes MAY be treated as equivalent to
            // INTERNAL_ERROR.
            _ => ErrorCode::InternalError,
        }
    }
}

impl From<ErrorCodeOrUnknown> for ErrorCode {
    fn from(e: ErrorCodeOrUnknown) -> Self {
        ErrorCode::from(e.0)
    }
}

impl AsRef<str> for ErrorCode {
    fn as_ref(&self) -> &str {
        match *self {
            ErrorCode::NoError => "NoError",
            ErrorCode::ProtocolError => "ProtocolError",
            ErrorCode::InternalError => "InternalError",
            ErrorCode::FlowControlError => "FlowControlError",
            ErrorCode::SettingsTimeout => "SettingsTimeout",
            ErrorCode::StreamClosed => "StreamClosed",
            ErrorCode::FrameSizeError => "FrameSizeError",
            ErrorCode::RefusedStream => "RefusedStream",
            ErrorCode::Cancel => "Cancel",
            ErrorCode::CompressionError => "CompressionError",
            ErrorCode::ConnectError => "ConnectError",
            ErrorCode::EnhanceYourCalm => "EnhanceYourCalm",
            ErrorCode::InadequateSecurity => "InadequateSecurity",
            ErrorCode::Http11Required => "Http11Required",
        }
    }
}

impl Into<u32> for ErrorCode {
    #[inline]
    fn into(self) -> u32 {
        self as u32
    }
}

/// Unknown error codes are valid in HTTP/2,
/// this struct represents error code when it is unknown
#[derive(Copy, Clone, Eq, PartialEq)]
pub(crate) struct ErrorCodeOrUnknown(pub(crate) u32);

impl ErrorCodeOrUnknown {
    pub fn to_error_code(&self) -> ErrorCode {
        ErrorCode::from(self.0)
    }
}

impl fmt::Debug for ErrorCodeOrUnknown {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match ErrorCode::try_from(self.0) {
            Ok(error_code) => fmt::Debug::fmt(&error_code, f),
            Err(error_code) => fmt::Debug::fmt(&error_code, f),
        }
    }
}

impl From<ErrorCode> for ErrorCodeOrUnknown {
    fn from(e: ErrorCode) -> Self {
        ErrorCodeOrUnknown(e.into())
    }
}
<commit_msg>Unused code warning<commit_after>use std::fmt;

/// The enum represents an error code that are used in `RST_STREAM` and `GOAWAY` frames.
/// These are defined in [Section 7](http://http2.github.io/http2-spec/#ErrorCodes) of the HTTP/2
/// spec.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorCode {
    /// The associated condition is not a result of an error. For example, a GOAWAY might include
    /// this code to indicate graceful shutdown of a connection.
    NoError = 0x0,
    /// The endpoint detected an unspecific protocol error. This error is for use when a more
    /// specific error code is not available.
    ProtocolError = 0x1,
    /// The endpoint encountered an unexpected internal error.
    InternalError = 0x2,
    /// The endpoint detected that its peer violated the flow-control protocol.
    FlowControlError = 0x3,
    /// The endpoint sent a SETTINGS frame but did not receive a response in a timely manner. See
    /// Section 6.5.3 ("Settings Synchronization").
    SettingsTimeout = 0x4,
    /// The endpoint received a frame after a stream was half-closed.
    StreamClosed = 0x5,
    /// The endpoint received a frame with an invalid size.
    FrameSizeError = 0x6,
    /// The endpoint refused the stream prior to performing any application processing (see Section
    /// 8.1.4 for details).
    RefusedStream = 0x7,
    /// Used by the endpoint to indicate that the stream is no longer needed.
    Cancel = 0x8,
    /// The endpoint is unable to maintain the header compression context for the connection.
    CompressionError = 0x9,
    /// The connection established in response to a CONNECT request (Section 8.3) was reset or
    /// abnormally closed.
    ConnectError = 0xa,
    /// The endpoint detected that its peer is exhibiting a behavior that might be generating
    /// excessive load.
    EnhanceYourCalm = 0xb,
    /// The underlying transport has properties that do not meet minimum security requirements (see
    /// Section 9.2).
    InadequateSecurity = 0xc,
    /// The endpoint requires that HTTP/1.1 be used instead of HTTP/2.
    Http11Required = 0xd,
}

impl ErrorCode {
    fn try_from(error_code: u32) -> Result<ErrorCode, u32> {
        Ok(match error_code {
            0x0 => ErrorCode::NoError,
            0x1 => ErrorCode::ProtocolError,
            0x2 => ErrorCode::InternalError,
            0x3 => ErrorCode::FlowControlError,
            0x4 => ErrorCode::SettingsTimeout,
            0x5 => ErrorCode::StreamClosed,
            0x6 => ErrorCode::FrameSizeError,
            0x7 => ErrorCode::RefusedStream,
            0x8 => ErrorCode::Cancel,
            0x9 => ErrorCode::CompressionError,
            0xa => ErrorCode::ConnectError,
            0xb => ErrorCode::EnhanceYourCalm,
            0xc => ErrorCode::InadequateSecurity,
            0xd => ErrorCode::Http11Required,
            // According to the spec, unknown error codes MAY be treated as equivalent to
            // INTERNAL_ERROR.
            _ => return Err(error_code),
        })
    }
}

impl From<u32> for ErrorCode {
    /// Converts the given `u32` number to the appropriate `ErrorCode` variant.
    fn from(code: u32) -> ErrorCode {
        match code {
            0x0 => ErrorCode::NoError,
            0x1 => ErrorCode::ProtocolError,
            0x2 => ErrorCode::InternalError,
            0x3 => ErrorCode::FlowControlError,
            0x4 => ErrorCode::SettingsTimeout,
            0x5 => ErrorCode::StreamClosed,
            0x6 => ErrorCode::FrameSizeError,
            0x7 => ErrorCode::RefusedStream,
            0x8 => ErrorCode::Cancel,
            0x9 => ErrorCode::CompressionError,
            0xa => ErrorCode::ConnectError,
            0xb => ErrorCode::EnhanceYourCalm,
            0xc => ErrorCode::InadequateSecurity,
            0xd => ErrorCode::Http11Required,
            // According to the spec, unknown error codes MAY be treated as equivalent to
            // INTERNAL_ERROR.
            _ => ErrorCode::InternalError,
        }
    }
}

impl From<ErrorCodeOrUnknown> for ErrorCode {
    fn from(e: ErrorCodeOrUnknown) -> Self {
        ErrorCode::from(e.0)
    }
}

impl AsRef<str> for ErrorCode {
    fn as_ref(&self) -> &str {
        match *self {
            ErrorCode::NoError => "NoError",
            ErrorCode::ProtocolError => "ProtocolError",
            ErrorCode::InternalError => "InternalError",
            ErrorCode::FlowControlError => "FlowControlError",
            ErrorCode::SettingsTimeout => "SettingsTimeout",
            ErrorCode::StreamClosed => "StreamClosed",
            ErrorCode::FrameSizeError => "FrameSizeError",
            ErrorCode::RefusedStream => "RefusedStream",
            ErrorCode::Cancel => "Cancel",
            ErrorCode::CompressionError => "CompressionError",
            ErrorCode::ConnectError => "ConnectError",
            ErrorCode::EnhanceYourCalm => "EnhanceYourCalm",
            ErrorCode::InadequateSecurity => "InadequateSecurity",
            ErrorCode::Http11Required => "Http11Required",
        }
    }
}

impl Into<u32> for ErrorCode {
    #[inline]
    fn into(self) -> u32 {
        self as u32
    }
}

/// Unknown error codes are valid in HTTP/2,
/// this struct represents error code when it is unknown
#[derive(Copy, Clone, Eq, PartialEq)]
pub(crate) struct ErrorCodeOrUnknown(pub(crate) u32);

impl ErrorCodeOrUnknown {
    pub fn _to_error_code(&self) -> ErrorCode {
        ErrorCode::from(self.0)
    }
}

impl fmt::Debug for ErrorCodeOrUnknown {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match ErrorCode::try_from(self.0) {
            Ok(error_code) => fmt::Debug::fmt(&error_code, f),
            Err(error_code) => fmt::Debug::fmt(&error_code, f),
        }
    }
}

impl From<ErrorCode> for ErrorCodeOrUnknown {
    fn from(e: ErrorCode) -> Self {
        ErrorCodeOrUnknown(e.into())
    }
}
<|endoftext|>


<commit_before>use super::partial_crosslink_record::PartialCrosslinkRecord;
use super::recent_proposer_record::RecentPropserRecord;
use super::utils::types::*;

pub struct ActiveState {
    pub height: u64,
    pub randao: Sha256Digest,
    pub ffg_voter_bitfield: Bitfield,
    pub recent_attesters: Vec<u32>, // TODO: should be u24
    pub partial_crosslinks: Vec<PartialCrosslinkRecord>,
    pub total_skip_count: u64,
    pub recent_proposers: Vec<RecentPropserRecord>
}

impl ActiveState {
    pub fn new_for_height(height: u64) -> ActiveState {
        ActiveState {
            height: height,
            randao: Sha256Digest::random(),
            ffg_voter_bitfield: Vec::new(),
            recent_attesters: Vec::new(),
            partial_crosslinks: Vec::new(),
            total_skip_count: 0,
            recent_proposers: Vec::new()
        }
    }

    pub fn num_recent_proposers(&self) -> usize {
        self.recent_proposers.len()
    }

    pub fn num_recent_attesters(&self) -> usize {
        self.recent_attesters.len()
    }
}

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

    #[test]
    fn test_new_for_height() {
        let h = 1;
        let a = ActiveState::new_for_height(h);
        assert_eq!(a.height, h);
    }

    #[test]
    fn test_num_recent_proposers() {
        let mut a = ActiveState::new_for_height(1);
        for _ in 1..5 {
            a.recent_proposers.push(RecentPropserRecord::new(
                    1,
                    Sha256Digest::random(),
                    2));
        }
        assert_eq!(a.num_recent_proposers(), 4)
    }

    #[test]
    fn test_num_recent_attesters() {
        let mut a = ActiveState::new_for_height(1);
        for _ in 1..5 {
            a.recent_attesters.push(1);
        }
        assert_eq!(a.num_recent_attesters(), 4)
    }
}
<commit_msg>Add partial rlp encoding to active_state<commit_after>use super::partial_crosslink_record::PartialCrosslinkRecord;
use super::recent_proposer_record::RecentPropserRecord;
use super::rlp::{ RlpStream, Encodable };
use super::utils::types::*;

pub struct ActiveState {
    pub height: u64,
    pub randao: Sha256Digest,
    pub ffg_voter_bitfield: Bitfield,
    pub recent_attesters: Vec<u32>, // TODO: should be u24
    pub partial_crosslinks: Vec<PartialCrosslinkRecord>,
    pub total_skip_count: u64,
    pub recent_proposers: Vec<RecentPropserRecord>
}

impl ActiveState {
    pub fn new_for_height(height: u64) -> ActiveState {
        ActiveState {
            height: height,
            randao: Sha256Digest::random(),
            ffg_voter_bitfield: Vec::new(),
            recent_attesters: Vec::new(),
            partial_crosslinks: Vec::new(),
            total_skip_count: 0,
            recent_proposers: Vec::new()
        }
    }

    pub fn num_recent_proposers(&self) -> usize {
        self.recent_proposers.len()
    }

    pub fn num_recent_attesters(&self) -> usize {
        self.recent_attesters.len()
    }
}

/*
 * RLP Encoding
 */
impl Encodable for ActiveState {
    fn rlp_append(&self, s: &mut RlpStream) {
        s.append(&self.height);
        s.append(&self.randao);
        s.append(&self.ffg_voter_bitfield);
        // s.append(&self.recent_attesters);
        // s.append(&self.partial_crosslinks);
        s.append(&self.total_skip_count);
        // s.append(&self.recent_proposers);
    }
}

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

    #[test]
    fn test_new_for_height() {
        let h = 1;
        let a = ActiveState::new_for_height(h);
        assert_eq!(a.height, h);
    }

    #[test]
    fn test_num_recent_proposers() {
        let mut a = ActiveState::new_for_height(1);
        for _ in 1..5 {
            a.recent_proposers.push(RecentPropserRecord::new(
                    1,
                    Sha256Digest::random(),
                    2));
        }
        assert_eq!(a.num_recent_proposers(), 4)
    }

    #[test]
    fn test_num_recent_attesters() {
        let mut a = ActiveState::new_for_height(1);
        for _ in 1..5 {
            a.recent_attesters.push(1);
        }
        assert_eq!(a.num_recent_attesters(), 4)
    }
}
<|endoftext|>