<commit_before>use std::{cmp, ptr};
use std::io::{self,Write,Read};
use std::iter::repeat;
use pool::Reset;

pub struct Buffer {
  memory:   Vec<u8>,
  capacity: usize,
  position: usize,
  end:      usize
}

impl Buffer {
  pub fn with_capacity(capacity: usize) -> Buffer {
    let mut v = Vec::with_capacity(capacity);
    v.extend(repeat(0).take(capacity));
    Buffer {
      memory:   v,
      capacity: capacity,
      position: 0,
      end:      0
    }
  }

  pub fn available_data(&self) -> usize {
    self.end - self.position
  }

  pub fn available_space(&self) -> usize {
    self.capacity - self.end
  }

  pub fn consume(&mut self, count: usize) -> usize {
    let cnt        = cmp::min(count, self.available_data());
    self.position += cnt;
    if self.position > self.capacity / 2 {
      //trace!("consume shift: pos {}, end {}", self.position, self.end);
      self.shift();
    }
    cnt
  }

  pub fn fill(&mut self, count: usize) -> usize {
    let cnt   = cmp::min(count, self.available_space());
    self.end += cnt;
    if self.available_space() < self.available_data() + cnt {
      //trace!("fill shift: pos {}, end {}", self.position, self.end);
      self.shift();
    }

    cnt
  }

  pub fn reset(&mut self) {
    self.position = 0;
    self.end      = 0;
  }

  pub fn data(&self) -> &[u8] {
    &self.memory[self.position..self.end]
  }

  pub fn space(&mut self) -> &mut[u8] {
    &mut self.memory[self.end..self.capacity]
  }

  pub fn shift(&mut self) {
    if self.position > 0 {
      unsafe {
        let length = self.end - self.position;
        ptr::copy( (&self.memory[self.position..self.end]).as_ptr(), (&mut self.memory[..length]).as_mut_ptr(), length);
        self.position = 0;
        self.end      = length;
      }
    }
  }

  pub fn delete_slice(&mut self, start: usize, length: usize) -> Option<usize> {
    if start + length >= self.available_data() {
      return None
    }

    unsafe {
      let begin    = self.position + start;
      let next_end = self.end - length;
      ptr::copy(
        (&self.memory[begin+length..self.end]).as_ptr(),
        (&mut self.memory[begin..next_end]).as_mut_ptr(),
        self.end - (begin+length)
      );
      self.end = next_end;
    }
    Some(self.available_data())
  }

  pub fn replace_slice(&mut self, data: &[u8], start: usize, length: usize) -> Option<usize> {
    let data_len = data.len();
    if start + length > self.available_data() ||
      self.position + start + data_len > self.capacity {
      return None
    }

    unsafe {
      let begin     = self.position + start;
      let slice_end = begin + data_len;
      // we reduced the data size
      if data_len < length {
        ptr::copy(data.as_ptr(), (&mut self.memory[begin..slice_end]).as_mut_ptr(), data_len);

        ptr::copy((&self.memory[start+length..self.end]).as_ptr(), (&mut self.memory[slice_end..]).as_mut_ptr(), self.end - (start + length));
        self.end = self.end - (length - data_len);

      // we put more data in the buffer
      } else {
        ptr::copy((&self.memory[start+length..self.end]).as_ptr(), (&mut self.memory[start+data_len..]).as_mut_ptr(), self.end - (start + length));
        ptr::copy(data.as_ptr(), (&mut self.memory[begin..slice_end]).as_mut_ptr(), data_len);
        self.end = self.end + data_len - length;
      }
    }
    Some(self.available_data())
  }

  pub fn insert_slice(&mut self, data: &[u8], start: usize) -> Option<usize> {
    let data_len = data.len();
    if start > self.available_data() ||
      self.position + start + data_len > self.capacity {
      return None
    }

    unsafe {
      let begin     = self.position + start;
      let slice_end = begin + data_len;
      ptr::copy((&self.memory[start..self.end]).as_ptr(), (&mut self.memory[start+data_len..]).as_mut_ptr(), self.end - start);
      ptr::copy(data.as_ptr(), (&mut self.memory[begin..slice_end]).as_mut_ptr(), data_len);
      self.end = self.end + data_len;
    }
    Some(self.available_data())
  }
}

impl Write for Buffer {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    match self.space().write(buf) {
      Ok(size) => { self.fill(size); Ok(size) },
      err      => err
    }
  }

  fn flush(&mut self) -> io::Result<()> {
    Ok(())
  }
}

impl Read for Buffer {
  fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
    let len = cmp::min(self.available_data(), buf.len());
    unsafe {
      ptr::copy((&self.memory[self.position..len]).as_ptr(), buf.as_mut_ptr(), len);
      self.position += len;
    }
    Ok(len)
  }
}

impl Reset for Buffer {
  fn reset(&mut self) {
    self.reset();
  }
}

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

  #[test]
  fn fill_and_consume() {
    let mut b = Buffer::with_capacity(10);
    assert_eq!(b.available_data(), 0);
    assert_eq!(b.available_space(), 10);
    let res = b.write(&b"abcd"[..]);
    assert_eq!(res.ok(), Some(4));
    assert_eq!(b.available_data(), 4);
    assert_eq!(b.available_space(), 6);

    assert_eq!(b.data(), &b"abcd"[..]);

    b.consume(2);
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 6);
    assert_eq!(b.data(), &b"cd"[..]);

    b.shift();
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 8);
    assert_eq!(b.data(), &b"cd"[..]);

    assert_eq!(b.write(&b"efghijklmnop"[..]).ok(), Some(8));
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
    b.shift();
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
  }

  #[test]
  fn delete() {
    let mut b = Buffer::with_capacity(10);
    let res = b.write(&b"abcdefgh"[..]);
    assert_eq!(b.available_data(), 8);
    assert_eq!(b.available_space(), 2);

    assert_eq!(b.delete_slice(2, 3), Some(5));
    assert_eq!(b.available_data(), 5);
    assert_eq!(b.available_space(), 5);
    assert_eq!(b.data(), &b"abfgh"[..]);

    assert_eq!(b.delete_slice(5, 2), None);
    assert_eq!(b.delete_slice(4, 2), None);
  }

  #[test]
  fn replace() {
    let mut b = Buffer::with_capacity(10);
    let res = b.write(&b"abcdefgh"[..]);
    assert_eq!(b.available_data(), 8);
    assert_eq!(b.available_space(), 2);

    assert_eq!(b.replace_slice(&b"ABC"[..], 2, 3), Some(8));
    assert_eq!(b.available_data(), 8);
    assert_eq!(b.available_space(), 2);
    assert_eq!(b.data(), &b"abABCfgh"[..]);

    assert_eq!(b.replace_slice(&b"XYZ"[..], 8, 3), None);
    assert_eq!(b.replace_slice(&b"XYZ"[..], 6, 3), None);

    assert_eq!(b.replace_slice(&b"XYZ"[..], 2, 4), Some(7));
    assert_eq!(b.available_data(), 7);
    assert_eq!(b.available_space(), 3);
    assert_eq!(b.data(), &b"abXYZgh"[..]);

    assert_eq!(b.replace_slice(&b"123"[..], 2, 2), Some(8));
    assert_eq!(b.available_data(), 8);
    assert_eq!(b.available_space(), 2);
    assert_eq!(b.data(), &b"ab123Zgh"[..]);
  }
}
<commit_msg>don't accept a slice insertion past the buffer's end<commit_after>use std::{cmp, ptr};
use std::io::{self,Write,Read};
use std::iter::repeat;
use pool::Reset;

pub struct Buffer {
  memory:   Vec<u8>,
  capacity: usize,
  position: usize,
  end:      usize
}

impl Buffer {
  pub fn with_capacity(capacity: usize) -> Buffer {
    let mut v = Vec::with_capacity(capacity);
    v.extend(repeat(0).take(capacity));
    Buffer {
      memory:   v,
      capacity: capacity,
      position: 0,
      end:      0
    }
  }

  pub fn available_data(&self) -> usize {
    self.end - self.position
  }

  pub fn available_space(&self) -> usize {
    self.capacity - self.end
  }

  pub fn consume(&mut self, count: usize) -> usize {
    let cnt        = cmp::min(count, self.available_data());
    self.position += cnt;
    if self.position > self.capacity / 2 {
      //trace!("consume shift: pos {}, end {}", self.position, self.end);
      self.shift();
    }
    cnt
  }

  pub fn fill(&mut self, count: usize) -> usize {
    let cnt   = cmp::min(count, self.available_space());
    self.end += cnt;
    if self.available_space() < self.available_data() + cnt {
      //trace!("fill shift: pos {}, end {}", self.position, self.end);
      self.shift();
    }

    cnt
  }

  pub fn reset(&mut self) {
    self.position = 0;
    self.end      = 0;
  }

  pub fn data(&self) -> &[u8] {
    &self.memory[self.position..self.end]
  }

  pub fn space(&mut self) -> &mut[u8] {
    &mut self.memory[self.end..self.capacity]
  }

  pub fn shift(&mut self) {
    if self.position > 0 {
      unsafe {
        let length = self.end - self.position;
        ptr::copy( (&self.memory[self.position..self.end]).as_ptr(), (&mut self.memory[..length]).as_mut_ptr(), length);
        self.position = 0;
        self.end      = length;
      }
    }
  }

  pub fn delete_slice(&mut self, start: usize, length: usize) -> Option<usize> {
    if start + length >= self.available_data() {
      return None
    }

    unsafe {
      let begin    = self.position + start;
      let next_end = self.end - length;
      ptr::copy(
        (&self.memory[begin+length..self.end]).as_ptr(),
        (&mut self.memory[begin..next_end]).as_mut_ptr(),
        self.end - (begin+length)
      );
      self.end = next_end;
    }
    Some(self.available_data())
  }

  pub fn replace_slice(&mut self, data: &[u8], start: usize, length: usize) -> Option<usize> {
    let data_len = data.len();
    if start + length > self.available_data() ||
      self.position + start + data_len > self.capacity {
      return None
    }

    unsafe {
      let begin     = self.position + start;
      let slice_end = begin + data_len;
      // we reduced the data size
      if data_len < length {
        ptr::copy(data.as_ptr(), (&mut self.memory[begin..slice_end]).as_mut_ptr(), data_len);

        ptr::copy((&self.memory[start+length..self.end]).as_ptr(), (&mut self.memory[slice_end..]).as_mut_ptr(), self.end - (start + length));
        self.end = self.end - (length - data_len);

      // we put more data in the buffer
      } else {
        ptr::copy((&self.memory[start+length..self.end]).as_ptr(), (&mut self.memory[start+data_len..]).as_mut_ptr(), self.end - (start + length));
        ptr::copy(data.as_ptr(), (&mut self.memory[begin..slice_end]).as_mut_ptr(), data_len);
        self.end = self.end + data_len - length;
      }
    }
    Some(self.available_data())
  }

  pub fn insert_slice(&mut self, data: &[u8], start: usize) -> Option<usize> {
    let data_len = data.len();
    if start > self.available_data() ||
      self.position + self.end + data_len > self.capacity {
      return None
    }

    unsafe {
      let begin     = self.position + start;
      let slice_end = begin + data_len;
      ptr::copy((&self.memory[start..self.end]).as_ptr(), (&mut self.memory[start+data_len..]).as_mut_ptr(), self.end - start);
      ptr::copy(data.as_ptr(), (&mut self.memory[begin..slice_end]).as_mut_ptr(), data_len);
      self.end = self.end + data_len;
    }
    Some(self.available_data())
  }
}

impl Write for Buffer {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    match self.space().write(buf) {
      Ok(size) => { self.fill(size); Ok(size) },
      err      => err
    }
  }

  fn flush(&mut self) -> io::Result<()> {
    Ok(())
  }
}

impl Read for Buffer {
  fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
    let len = cmp::min(self.available_data(), buf.len());
    unsafe {
      ptr::copy((&self.memory[self.position..len]).as_ptr(), buf.as_mut_ptr(), len);
      self.position += len;
    }
    Ok(len)
  }
}

impl Reset for Buffer {
  fn reset(&mut self) {
    self.reset();
  }
}

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

  #[test]
  fn fill_and_consume() {
    let mut b = Buffer::with_capacity(10);
    assert_eq!(b.available_data(), 0);
    assert_eq!(b.available_space(), 10);
    let res = b.write(&b"abcd"[..]);
    assert_eq!(res.ok(), Some(4));
    assert_eq!(b.available_data(), 4);
    assert_eq!(b.available_space(), 6);

    assert_eq!(b.data(), &b"abcd"[..]);

    b.consume(2);
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 6);
    assert_eq!(b.data(), &b"cd"[..]);

    b.shift();
    assert_eq!(b.available_data(), 2);
    assert_eq!(b.available_space(), 8);
    assert_eq!(b.data(), &b"cd"[..]);

    assert_eq!(b.write(&b"efghijklmnop"[..]).ok(), Some(8));
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
    b.shift();
    assert_eq!(b.available_data(), 10);
    assert_eq!(b.available_space(), 0);
    assert_eq!(b.data(), &b"cdefghijkl"[..]);
  }

  #[test]
  fn delete() {
    let mut b = Buffer::with_capacity(10);
    let res = b.write(&b"abcdefgh"[..]);
    assert_eq!(b.available_data(), 8);
    assert_eq!(b.available_space(), 2);

    assert_eq!(b.delete_slice(2, 3), Some(5));
    assert_eq!(b.available_data(), 5);
    assert_eq!(b.available_space(), 5);
    assert_eq!(b.data(), &b"abfgh"[..]);

    assert_eq!(b.delete_slice(5, 2), None);
    assert_eq!(b.delete_slice(4, 2), None);
  }

  #[test]
  fn replace() {
    let mut b = Buffer::with_capacity(10);
    let res = b.write(&b"abcdefgh"[..]);
    assert_eq!(b.available_data(), 8);
    assert_eq!(b.available_space(), 2);

    assert_eq!(b.replace_slice(&b"ABC"[..], 2, 3), Some(8));
    assert_eq!(b.available_data(), 8);
    assert_eq!(b.available_space(), 2);
    assert_eq!(b.data(), &b"abABCfgh"[..]);

    assert_eq!(b.replace_slice(&b"XYZ"[..], 8, 3), None);
    assert_eq!(b.replace_slice(&b"XYZ"[..], 6, 3), None);

    assert_eq!(b.replace_slice(&b"XYZ"[..], 2, 4), Some(7));
    assert_eq!(b.available_data(), 7);
    assert_eq!(b.available_space(), 3);
    assert_eq!(b.data(), &b"abXYZgh"[..]);

    assert_eq!(b.replace_slice(&b"123"[..], 2, 2), Some(8));
    assert_eq!(b.available_data(), 8);
    assert_eq!(b.available_space(), 2);
    assert_eq!(b.data(), &b"ab123Zgh"[..]);
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2019 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// spi_24aa1024.rs - Transfers data to a Microchip 24AA1024 serial EEPROM using SPI.

use std::error::Error;

use rppal::spi::{Bus, Mode, SlaveSelect, Spi, TransferSegment};

// Instruction set.
const WRITE: u8 = 0b0010; // Write data, starting at the selected address.
const READ: u8 = 0b0011; // Read data, starting at the selected address.
const RDSR: u8 = 0b0101; // Read the STATUS register.
const WREN: u8 = 0b0110; // Set the write enable latch (enable write operations).

const WIP: u8 = 1; // Write-In-Process bit mask for the STATUS register.

fn main() -> Result<(), Box<dyn Error>> {
    // Configure the SPI peripheral. The 24AA1024 clocks in data on the first
    // rising edge of the clock signal (SPI mode 0). At 3.3 V, clock speeds of up
    // to 10 MHz are supported.
    let mut spi = Spi::new(Bus::Spi0, SlaveSelect::Ss0, 8_000_000, Mode::Mode0)?;

    // Set the write enable latch using the WREN instruction. This is required
    // before any data can be written. The write enable latch is automatically
    // reset after a WRITE instruction is successfully executed.
    spi.write(&[WREN])?;

    // Use the WRITE instruction to select 24-bit memory address 0x00 and write 5
    // bytes (1, 2, 3, 4, 5).
    spi.write(&[WRITE, 0, 0, 0, 1, 2, 3, 4, 5])?;

    // Read the STATUS register by writing the RDSR instruction, and then reading
    // a single byte. Wait until the WIP bit is set to 0, indicating the write
    // operation is completed. transfer_segments() will keep the Slave Select line
    // active until both segments have been transferred.
    let mut buffer = [0u8; 1];
    loop {
        spi.transfer_segments(&[
            TransferSegment::new(None, Some(&[RDSR])),
            TransferSegment::new(Some(&mut buffer), None),
        ])?;

        if buffer[0] & WIP == 0 {
            break;
        }
    }

    // Use the READ instruction to select 24-bit memory address 0x00, and then
    // read 5 bytes.
    let mut buffer = [0u8; 5];
    spi.transfer_segments(&[
        TransferSegment::new(None, Some(&[READ, 0, 0, 0])),
        TransferSegment::new(Some(&mut buffer), None),
    ])?;

    println!("Bytes read: {:?}", buffer);

    Ok(())
}
<commit_msg>Update documentation<commit_after>// Copyright (c) 2017-2019 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// spi_24aa1024.rs - Transfers data to a Microchip 24AA1024 serial EEPROM using SPI.

use std::error::Error;

use rppal::spi::{Bus, Mode, SlaveSelect, Spi, TransferSegment};

// Instruction set.
const WRITE: u8 = 0b0010; // Write data, starting at the selected address.
const READ: u8 = 0b0011; // Read data, starting at the selected address.
const RDSR: u8 = 0b0101; // Read the STATUS register.
const WREN: u8 = 0b0110; // Set the write enable latch (enable write operations).

const WIP: u8 = 1; // Write-In-Process bit mask for the STATUS register.

fn main() -> Result<(), Box<dyn Error>> {
    // Configure the SPI peripheral. The 24AA1024 clocks in data on the first
    // rising edge of the clock signal (SPI mode 0). At 3.3 V, clock speeds of up
    // to 10 MHz are supported.
    let mut spi = Spi::new(Bus::Spi0, SlaveSelect::Ss0, 8_000_000, Mode::Mode0)?;

    // Set the write enable latch using the WREN instruction. This is required
    // before any data can be written. The write enable latch is automatically
    // reset after a WRITE instruction is successfully executed.
    spi.write(&[WREN])?;

    // Use the WRITE instruction to select 24-bit memory address 0x00 and write 5
    // bytes (1, 2, 3, 4, 5).
    spi.write(&[WRITE, 0, 0, 0, 1, 2, 3, 4, 5])?;

    // Read the STATUS register by writing the RDSR instruction, and then reading
    // a single byte. Loop until the WIP bit is set to 0, indicating the write
    // operation is completed. transfer_segments() will keep the Slave Select line
    // active until both segments have been transferred.
    let mut buffer = [0u8; 1];
    loop {
        spi.transfer_segments(&[
            TransferSegment::new(None, Some(&[RDSR])),
            TransferSegment::new(Some(&mut buffer), None),
        ])?;

        if buffer[0] & WIP == 0 {
            break;
        }
    }

    // Use the READ instruction to select 24-bit memory address 0x00, and then
    // read 5 bytes.
    let mut buffer = [0u8; 5];
    spi.transfer_segments(&[
        TransferSegment::new(None, Some(&[READ, 0, 0, 0])),
        TransferSegment::new(Some(&mut buffer), None),
    ])?;

    println!("Bytes read: {:?}", buffer);

    Ok(())
}
<|endoftext|>


<commit_before>macro_rules! newtype_clone (($newtype:ident) => (
        impl Clone for $newtype {
            fn clone(&self) -> $newtype {
                let &$newtype(v) = self;
                $newtype(v)
            }
        }

        ));

macro_rules! newtype_drop (($newtype:ident) => (
        impl Drop for $newtype {
            fn drop(&mut self) {
                use libc::size_t;
                use ffi;
                let &mut $newtype(ref mut v) = self;
                unsafe {
                    ffi::sodium_memzero(v.as_mut_ptr(), v.len() as size_t);
                }
            }
        }
        ));

macro_rules! newtype_impl (($newtype:ident, $len:expr) => (
    impl $newtype {
        /// `from_slice()` creates an object from a byte slice
        ///
        /// This function will fail and return None if the length of
        /// the byte-slice isn't equal to the length of the object
        pub fn from_slice(bs: &[u8]) -> Option<$newtype> {
            if bs.len() != $len {
                return None;
            }
            let mut n = $newtype([0; $len]);
            {
                let $newtype(ref mut b) = n;
                for (bi, &bsi) in b.iter_mut().zip(bs.iter()) {
                    *bi = bsi
                }
            }
            Some(n)
        }
    }
    impl PartialEq for $newtype {
        fn eq(&self, &$newtype(ref other): &$newtype) -> bool {
            use crypto::verify::safe_memcmp;
            let &$newtype(ref this) = self;
            safe_memcmp(this, other)
        }
    }
    impl Eq for $newtype {}
    impl rustc_serialize::Encodable for $newtype {
        fn encode<E: rustc_serialize::Encoder>(&self, encoder: &mut E)
                -> Result<(), E::Error> {
            encoder.emit_seq($len, |encoder| {
                for (i, e) in self[..].iter().enumerate() {
                    try!(encoder.emit_seq_elt(i, |encoder| e.encode(encoder)))
                }
                Ok(())
            })
        }
    }
    impl rustc_serialize::Decodable for $newtype {
        fn decode<D: rustc_serialize::Decoder>(decoder: &mut D)
                -> Result<$newtype, D::Error> {
            decoder.read_seq(|decoder, len| {
                if len != $len {
                    return Err(decoder.error(
                        &format!("Expecting array of length: {}, but found {}",
                                 $len, len)));
                }
                let mut arr = [0u8; $len];
                for (i, val) in arr.iter_mut().enumerate() {
                    *val = try!(decoder.read_seq_elt(i,
                        |decoder| rustc_serialize::Decodable::decode(decoder)));
                }
                Ok($newtype(arr))
            })
        }
    }
    /// Allows a user to access the byte contents of an object as a slice.
    ///
    /// WARNING: it might be tempting to do comparisons on objects
    /// by using `x[a..b] == y[a..b]`. This will open up for timing attacks
    /// when comparing for example authenticator tags. Because of this only
    /// use the comparison functions exposed by the sodiumoxide API.
    impl ::std::ops::Index<::std::ops::Range<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: ::std::ops::Range<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /// Allows a user to access the byte contents of an object as a slice.
    ///
    /// WARNING: it might be tempting to do comparisons on objects
    /// by using `x[..b] == y[..b]`. This will open up for timing attacks
    /// when comparing for example authenticator tags. Because of this only
    /// use the comparison functions exposed by the sodiumoxide API.
    impl ::std::ops::Index<::std::ops::RangeTo<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: ::std::ops::RangeTo<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /// Allows a user to access the byte contents of an object as a slice.
    ///
    /// WARNING: it might be tempting to do comparisons on objects
    /// by using `x[a..] == y[a..]`. This will open up for timing attacks
    /// when comparing for example authenticator tags. Because of this only
    /// use the comparison functions exposed by the sodiumoxide API.
    impl ::std::ops::Index<::std::ops::RangeFrom<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: ::std::ops::RangeFrom<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /// Allows a user to access the byte contents of an object as a slice.
    ///
    /// WARNING: it might be tempting to do comparisons on objects
    /// by using `x[] == y[]`. This will open up for timing attacks
    /// when comparing for example authenticator tags. Because of this only
    /// use the comparison functions exposed by the sodiumoxide API.
    impl ::std::ops::Index<::std::ops::RangeFull> for $newtype {
        type Output = [u8];
        fn index(&self, _index: ::std::ops::RangeFull) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    ));
<commit_msg>Remove potential copy when deserializing newtypes<commit_after>macro_rules! newtype_clone (($newtype:ident) => (
        impl Clone for $newtype {
            fn clone(&self) -> $newtype {
                let &$newtype(v) = self;
                $newtype(v)
            }
        }

        ));

macro_rules! newtype_drop (($newtype:ident) => (
        impl Drop for $newtype {
            fn drop(&mut self) {
                use libc::size_t;
                use ffi;
                let &mut $newtype(ref mut v) = self;
                unsafe {
                    ffi::sodium_memzero(v.as_mut_ptr(), v.len() as size_t);
                }
            }
        }
        ));

macro_rules! newtype_impl (($newtype:ident, $len:expr) => (
    impl $newtype {
        /// `from_slice()` creates an object from a byte slice
        ///
        /// This function will fail and return None if the length of
        /// the byte-slice isn't equal to the length of the object
        pub fn from_slice(bs: &[u8]) -> Option<$newtype> {
            if bs.len() != $len {
                return None;
            }
            let mut n = $newtype([0; $len]);
            {
                let $newtype(ref mut b) = n;
                for (bi, &bsi) in b.iter_mut().zip(bs.iter()) {
                    *bi = bsi
                }
            }
            Some(n)
        }
    }
    impl PartialEq for $newtype {
        fn eq(&self, &$newtype(ref other): &$newtype) -> bool {
            use crypto::verify::safe_memcmp;
            let &$newtype(ref this) = self;
            safe_memcmp(this, other)
        }
    }
    impl Eq for $newtype {}
    impl rustc_serialize::Encodable for $newtype {
        fn encode<E: rustc_serialize::Encoder>(&self, encoder: &mut E)
                -> Result<(), E::Error> {
            encoder.emit_seq($len, |encoder| {
                for (i, e) in self[..].iter().enumerate() {
                    try!(encoder.emit_seq_elt(i, |encoder| e.encode(encoder)))
                }
                Ok(())
            })
        }
    }
    impl rustc_serialize::Decodable for $newtype {
        fn decode<D: rustc_serialize::Decoder>(decoder: &mut D)
                -> Result<$newtype, D::Error> {
            decoder.read_seq(|decoder, len| {
                if len != $len {
                    return Err(decoder.error(
                        &format!("Expecting array of length: {}, but found {}",
                                 $len, len)));
                }
                let mut res = $newtype([0; $len]);
                {
                    let $newtype(ref mut arr) = res;
                    for (i, val) in arr.iter_mut().enumerate() {
                        *val = try!(decoder.read_seq_elt(i,
                            |decoder| rustc_serialize::Decodable::decode(decoder)));
                    }
                }
                Ok(res)
            })
        }
    }
    /// Allows a user to access the byte contents of an object as a slice.
    ///
    /// WARNING: it might be tempting to do comparisons on objects
    /// by using `x[a..b] == y[a..b]`. This will open up for timing attacks
    /// when comparing for example authenticator tags. Because of this only
    /// use the comparison functions exposed by the sodiumoxide API.
    impl ::std::ops::Index<::std::ops::Range<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: ::std::ops::Range<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /// Allows a user to access the byte contents of an object as a slice.
    ///
    /// WARNING: it might be tempting to do comparisons on objects
    /// by using `x[..b] == y[..b]`. This will open up for timing attacks
    /// when comparing for example authenticator tags. Because of this only
    /// use the comparison functions exposed by the sodiumoxide API.
    impl ::std::ops::Index<::std::ops::RangeTo<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: ::std::ops::RangeTo<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /// Allows a user to access the byte contents of an object as a slice.
    ///
    /// WARNING: it might be tempting to do comparisons on objects
    /// by using `x[a..] == y[a..]`. This will open up for timing attacks
    /// when comparing for example authenticator tags. Because of this only
    /// use the comparison functions exposed by the sodiumoxide API.
    impl ::std::ops::Index<::std::ops::RangeFrom<usize>> for $newtype {
        type Output = [u8];
        fn index(&self, _index: ::std::ops::RangeFrom<usize>) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    /// Allows a user to access the byte contents of an object as a slice.
    ///
    /// WARNING: it might be tempting to do comparisons on objects
    /// by using `x[] == y[]`. This will open up for timing attacks
    /// when comparing for example authenticator tags. Because of this only
    /// use the comparison functions exposed by the sodiumoxide API.
    impl ::std::ops::Index<::std::ops::RangeFull> for $newtype {
        type Output = [u8];
        fn index(&self, _index: ::std::ops::RangeFull) -> &[u8] {
            let &$newtype(ref b) = self;
            b.index(_index)
        }
    }
    ));
<|endoftext|>


<commit_before>use std::collections::HashMap;

pub trait StaticSymbolTable<'a>
{
	/// Return all symbols in this table with the specified name (in any namespace)
	fn lookup_by_name(name: &str) -> Vec<Symbol<'a>>;

	/// Return all symbols in this table with the specified namespace
	fn lookup_by_namespace(namespace: &str) -> Vec<Symbol<'a>>;

	/// Lookup a symbol by its name and namespace. Duplicate symbols are not allowed, so the result will be unique
	/// @return the specified symbol or None if the specified symbol is not in this namespace
	fn lookup_variable(namespace: &str, name: &str) -> Option<Symbol<'a>>;

	/// Lookup a symbol by its name and namespace. Duplicate symbols are not allowed, so the result will be unique
	/// If no result is found in the direct namespace, the parent namespaces will be searched
	/// @return the specified symbol or None if the specified symbol is not in this namespace or a parent namespace
	fn lookup_function(namespace: &str, name: &str, argument_types: &Vec<&str>) -> Option<Symbol<'a>>;

	/// Adds a symbol to this table and allocates it's location
	/// Returns true if the symbol could be added; false otherwise
	/// Duplicate symbols are not allowed
	/// TODO: support overloaded methods
	fn add(class: SymbolClass<'a>, namespace: &'a str, name: &'a str) -> bool;
}

pub enum SymbolLocation<'a>
{
	/// Indicates that a register has been reserved for a specific use (e.g. by a variable)
	Register { name: &'a str },

	/// Indicates a location in memory
	Memory { address: MemoryAddress<'a> },

	/// Indicates that the symbol should not be accessed, as it represents a structured entity
	Structured
}

pub enum SymbolClass<'a>
{
	Variable { variable_type: &'a str },

	/// Function signature //TODO: support exceptions
	Function { return_type: &'a str, argument_types: &'a Vec<&'a str> },

	/// Includes class, enum, and interface
	Structure { subtype: &'a str, specification: Structure<'a> },
}

pub struct Structure<'a>
{
	/// Map from memberName -> (mmberType, offset)
	pub members: HashMap<&'a str, (&'a str, u16)>,
}

pub struct Symbol<'a>
{
	/// Namespace of this symbol, without the final "." or the name of this symbol
	pub namespace: &'a str,

	/// Identifier for the symbol (e.g. name of variable, function, class, etc. without it's namespace)
	pub name: &'a str,

	/// What this symbol represents (class, enum, variable, function, etc)
	pub symbol_class: SymbolClass<'a>,

	/// Memory location of this symbol. Methods will always map to a SymbolLocation::Memory label with a 0 offset
	pub location: SymbolLocation<'a>,
}

pub struct MemoryAddress<'a>
{
	/// Label marking the base address where the symbol is stored
	pub label_name: &'a str,

	/// Offset from the base address to access the symbol. Methods will always have an offset of 0
	pub offset: u16,
}
<commit_msg>Add structure lookups to SymbolTable specification<commit_after>use std::collections::HashMap;

pub trait StaticSymbolTable<'a>
{
	/// Return all symbols in this table with the specified name (in any namespace)
	fn lookup_by_name(name: &str) -> Vec<Symbol<'a>>;

	/// Return all symbols in this table with the specified namespace
	fn lookup_by_namespace(namespace: &str) -> Vec<Symbol<'a>>;

	/// Lookup a variable by its name and namespace. Duplicate symbols are not allowed, so the result will be unique
	/// @return the specified symbol or None if the specified symbol is not in this namespace
	fn lookup_variable(namespace: &str, name: &str) -> Option<Symbol<'a>>;

	/// Lookup a function by its name and namespace. Functions with the same signature are not allowed, so the result will be unique
	/// If no result is found in the direct namespace, the parent namespaces will be searched
	/// @return the specified symbol or None if the specified symbol is not in this namespace or a parent namespace
	fn lookup_function(namespace: &str, name: &str, argument_types: &Vec<&str>) -> Option<Symbol<'a>>;

	/// Lookup a structure (class, enum) by its name and namespace.
	/// Duplicate classes in the same namespace are not allowed, so the result will be unique
	/// If no result is found in the direct namespace, the parent namespaces will be searched
	/// @return the specified symbol AND it's specification (unwrapped, for convenience)
	/// or None if the specified symbol is not in this namespace or a parent namespace
	fn lookup_structure(namespace: &str, name: &str) -> Option<(Symbol<'a>, Structure)>;

	/// Adds a symbol to this table and allocates it's location
	/// Returns true if the symbol could be added; false otherwise
	/// Duplicate symbols are not allowed
	/// TODO: support overloaded methods
	fn add(class: SymbolClass<'a>, namespace: &'a str, name: &'a str) -> bool;
}

pub enum SymbolLocation<'a>
{
	/// Indicates that a register has been reserved for a specific use (e.g. by a variable)
	Register { name: &'a str },

	/// Indicates a location in memory
	Memory { address: MemoryAddress<'a> },

	/// Indicates that the symbol should not be accessed, as it represents a structured entity
	Structured
}

pub enum SymbolClass<'a>
{
	Variable { variable_type: &'a str },

	/// Function signature //TODO: support exceptions
	Function { return_type: &'a str, argument_types: &'a Vec<&'a str> },

	/// Includes class, enum, and interface
	Structure { subtype: &'a str, specification: Structure<'a> },
}

pub struct Structure<'a>
{
	/// Map from memberName -> (mmberType, offset)
	pub members: HashMap<&'a str, (&'a str, u16)>,
}

pub struct Symbol<'a>
{
	/// Namespace of this symbol, without the final "." or the name of this symbol
	pub namespace: &'a str,

	/// Identifier for the symbol (e.g. name of variable, function, class, etc. without it's namespace)
	pub name: &'a str,

	/// What this symbol represents (class, enum, variable, function, etc)
	pub symbol_class: SymbolClass<'a>,

	/// Memory location of this symbol. Methods will always map to a SymbolLocation::Memory label with a 0 offset
	pub location: SymbolLocation<'a>,
}

pub struct MemoryAddress<'a>
{
	/// Label marking the base address where the symbol is stored
	pub label_name: &'a str,

	/// Offset from the base address to access the symbol. Methods will always have an offset of 0
	pub offset: u16,
}
<|endoftext|>


<commit_before>use image::{RgbaImage, Rgba, Pixels};
use rand::Rng;
use itertools::Itertools;

use utils::*;

pub fn encode_rgba<R: Rng>(source: &mut RgbaImage, payload: &[u8], mode: RgbaMode, mut rng: R)
{
    // number of pixels per byte
    let ppb = match mode
    {
        // 1 values per pixel = 8 pixels per byte
        RgbaMode::Alpha => 8,
        // 4 values per pixel = 2 pixels per byte
        RgbaMode::Each => 2,
    };

    for (pixels, byte) in source.pixels_mut() // iterate pixels mutably
        .chunks(ppb).into_iter()              // split them into ppb-size chunks
        .map(|ch| ch.collect::<Vec<_>>())     // make them vectors so we can check their lengths later
        .zip(payload.iter().map(|x| *x))      // give each chunk a byte
    {
        // if the pixels don't fit exactly into their chunks,
        // the last chunk will be short. we won't use that chunk
        // (making sure the payload fits into the image is not
        // this functions job!)
        if pixels.len() != ppb
        {
            return;
        }

        match mode
        {
            RgbaMode::Alpha =>
            {
                for (i, px) in pixels.into_iter().enumerate()
                {
                    // a true, or 1 bit
                    if get_bit(byte, i as u8)
                    {
                        // even = 0 bit, so it needs to be changed
                        if px.data[3] % 2 == 0
                        {
                            // special case: if it's zero, we have to go up
                            if px.data[3] == 0
                            {
                                px.data[3] = 1;
                            }
                            else
                            {
                                if rng.gen()
                                {
                                    px.data[3] += 1;
                                }
                                else
                                {
                                    px.data[3] -= 1;
                                }
                            }
                        }
                    }
                    // a false, or 0 bit
                    else
                    {
                        // odd = 1 bit, so it needs to be changed
                        if px.data[3] % 2 == 1
                        {
                            // special case: if it's 255, we have to go down
                            if px.data[3] == 255
                            {
                                px.data[3] = 254;
                            }
                            else
                            {
                                if rng.gen()
                                {
                                    px.data[3] += 1;
                                }
                                else
                                {
                                    px.data[3] -= 1;
                                }
                            }
                        }
                    }
                }
            },
            RgbaMode::Each =>
            {
                unimplemented!()
            },
        }
    }
}

pub fn decode_rbga(source: &RgbaImage, mode: RgbaMode) -> Vec<u8>
{
    unimplemented!();
}

/// The encoding/decoding mode
#[derive(Copy, Clone)]
pub enum RgbaMode
{
    /// encode in alpha even/odd
    Alpha,
    /// encode in each field even/odd
    Each,
}

use std::default::Default;

impl Default for RgbaMode
{
    fn default() -> RgbaMode
    {
        RgbaMode::Alpha
    }
}
<commit_msg>Implemented rgba decoding<commit_after>use image::RgbaImage;
use rand::Rng;
use itertools::Itertools;

use utils::*;

pub fn encode_rgba<R: Rng>(source: &mut RgbaImage, payload: &[u8], mode: RgbaMode, mut rng: R)
{
    // number of pixels per byte
    let ppb = match mode
    {
        // 1 values per pixel = 8 pixels per byte
        RgbaMode::Alpha => 8,
        // 4 values per pixel = 2 pixels per byte
        RgbaMode::Each => 2,
    };

    for (pixels, byte) in source.pixels_mut() // iterate pixels mutably
        .chunks(ppb).into_iter()              // split them into ppb-size chunks
        .map(|ch| ch.collect::<Vec<_>>())     // make them vectors so we can check their lengths later
        .zip(payload.iter().map(|x| *x))      // give each chunk a byte
    {
        // if the pixels don't fit exactly into their chunks,
        // the last chunk will be short. we won't use that chunk
        // (making sure the payload fits into the image is not
        // this functions job!)
        if pixels.len() != ppb
        {
            return;
        }

        match mode
        {
            RgbaMode::Alpha =>
            {
                for (i, px) in pixels.into_iter().enumerate()
                {
                    // a true, or 1 bit
                    if get_bit(byte, i as u8)
                    {
                        // even = 0 bit, so it needs to be changed
                        if px.data[3] % 2 == 0
                        {
                            // special case: if it's zero, we have to go up
                            if px.data[3] == 0
                            {
                                px.data[3] = 1;
                            }
                            else
                            {
                                if rng.gen()
                                {
                                    px.data[3] += 1;
                                }
                                else
                                {
                                    px.data[3] -= 1;
                                }
                            }
                        }
                    }
                    // a false, or 0 bit
                    else
                    {
                        // odd = 1 bit, so it needs to be changed
                        if px.data[3] % 2 == 1
                        {
                            // special case: if it's 255, we have to go down
                            if px.data[3] == 255
                            {
                                px.data[3] = 254;
                            }
                            else
                            {
                                if rng.gen()
                                {
                                    px.data[3] += 1;
                                }
                                else
                                {
                                    px.data[3] -= 1;
                                }
                            }
                        }
                    }
                }
            },
            RgbaMode::Each =>
            {
                unimplemented!()
            },
        }
    }
}

pub fn decode_rbga(source: &RgbaImage, mode: RgbaMode) -> Vec<u8>
{
    // pixels per byte
    let ppb = match mode
    {
        // one value per pixel = 8 pixels per byte
        RgbaMode::Alpha => 8,
        // four values per pixel = 2 pixels per byte
        RgbaMode::Each => 2,
    };

    let mut buf = Vec::new();

    for pixels in source.pixels()         // iterate pixels
        .chunks(ppb).into_iter()          // split into ppb-sized chunks
        .map(|ch| ch.collect::<Vec<_>>()) // make them vectors so we can check their lengths
    {
        // only decode while we have enough data
        if pixels.len() != ppb
        {
            break;
        }

        match mode
        {
            RgbaMode::Alpha =>
            {
                let mut byte = 0u8;

                for (i, px) in pixels.into_iter().enumerate()
                {
                    byte = set_bit(byte, i as u8, px.data[3] % 2 == 1);
                }

                buf.push(byte)
            },
            RgbaMode::Each =>
            {
                unimplemented!()
            }
        }
    }

    buf

}

/// The encoding/decoding mode
#[derive(Copy, Clone)]
pub enum RgbaMode
{
    /// encode in alpha even/odd
    Alpha,
    /// encode in each field even/odd
    Each,
}

use std::default::Default;

impl Default for RgbaMode
{
    fn default() -> RgbaMode
    {
        RgbaMode::Alpha
    }
}
<|endoftext|>


<commit_before>use derivative::Derivative;
use std::cmp::Reverse;
use std::collections::hash_map::Entry;
use std::collections::{BinaryHeap, HashMap, HashSet};

use crate::entity::storage::AsStorage;
use crate::entity::traverse::Adjacency;
use crate::entity::view::{Bind, Unbind};
use crate::geometry::Metric;

#[derivative(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
#[derive(Derivative)]
struct KeyedMetric<K, Q>(
    #[derivative(Ord = "ignore", PartialEq = "ignore", PartialOrd = "ignore")] K,
    Q,
)
where
    Q: Eq + Ord;

// TODO: This may become part of the public API.
#[allow(dead_code)]
pub fn metrics<'a, M, T>(from: T, to: Option<T::Key>) -> HashMap<T::Key, (Option<T::Key>, usize)>
where
    M: 'a + AsStorage<T::Entity>,
    T: Adjacency + Bind<&'a M> + Copy + Unbind<&'a M>,
{
    metrics_with(from, to, |_, _| 1usize)
}

pub fn metrics_with<'a, M, T, Q, F>(
    from: T,
    to: Option<T::Key>,
    f: F,
) -> HashMap<T::Key, (Option<T::Key>, Q)>
where
    M: 'a + AsStorage<T::Entity>,
    T: Adjacency + Bind<&'a M> + Copy + Unbind<&'a M>,
    Q: Copy + Metric,
    F: Fn(T, T) -> Q,
{
    let (storage, from) = from.unbind();
    let capacity = if to.is_some() {
        0
    }
    else {
        storage.as_storage().len()
    };
    let mut buffer = BinaryHeap::new();
    let mut breadcrumbs = HashSet::with_capacity(capacity);
    let mut metrics = HashMap::with_capacity(capacity);

    metrics.insert(from, (None, Q::zero()));
    buffer.push(KeyedMetric(from, Reverse(Q::zero())));
    while let Some(KeyedMetric(key, Reverse(metric))) = buffer.pop() {
        if Some(key) == to {
            break;
        }
        let entity = T::bind(storage, key).unwrap();
        if breadcrumbs.insert(entity.key()) {
            for adjacent in entity
                .adjacency()
                .into_iter()
                .map(|key| T::bind(storage, key).unwrap())
            {
                // TODO: Consider returning an error if the output of `f` is
                //       less than zero.
                let metric = metric + f(entity, adjacent);
                match metrics.entry(adjacent.key()) {
                    Entry::Occupied(entry) => {
                        if metric < entry.get().1 {
                            entry.into_mut().1 = metric;
                        }
                    }
                    Entry::Vacant(entry) => {
                        entry.insert((Some(entity.key()), metric));
                    }
                }
                buffer.push(KeyedMetric(adjacent.key(), Reverse(metric)));
            }
        }
    }
    metrics
}

#[cfg(test)]
mod tests {
    use decorum::R64;
    use nalgebra::Point2;
    use theon::space::InnerSpace;

    use crate::entity::dijkstra;
    use crate::graph::MeshGraph;
    use crate::prelude::*;
    use crate::primitive::{Tetragon, Trigon};

    #[test]
    fn logical_metrics() {
        let graph = MeshGraph::<()>::from_raw_buffers(vec![Trigon::new(0usize, 1, 2)], vec![(); 3])
            .unwrap();
        let vertex = graph.vertices().nth(0).unwrap();
        let metrics = dijkstra::metrics(vertex, None);
        let a = vertex.key();
        let b = vertex.outgoing_arc().destination_vertex().key();
        let c = vertex.outgoing_arc().next_arc().destination_vertex().key();
        let aq = *metrics.get(&a).unwrap();
        let bq = *metrics.get(&b).unwrap();
        let cq = *metrics.get(&c).unwrap();

        assert_eq!(aq, (None, 0));
        assert_eq!(bq, (Some(a), 1));
        assert_eq!(cq, (Some(a), 1));
    }

    #[allow(clippy::float_cmp)]
    #[test]
    fn euclidean_distance_metrics() {
        let graph = MeshGraph::<Point2<f64>>::from_raw_buffers(
            vec![Tetragon::new(0usize, 1, 2, 3)],
            vec![(-1.0, -1.0), (1.0, -1.0), (1.0, 1.0), (-1.0, 1.0)],
        )
        .unwrap();
        let vertex = graph.vertices().nth(0).unwrap();
        let metrics = dijkstra::metrics_with(vertex, None, |from, to| {
            R64::from((to.position() - from.position()).magnitude())
        });
        let a = vertex.key();
        let b = vertex.outgoing_arc().destination_vertex().key();
        let c = vertex.outgoing_arc().next_arc().destination_vertex().key();
        let d = vertex
            .outgoing_arc()
            .next_arc()
            .next_arc()
            .destination_vertex()
            .key();
        let aq = *metrics.get(&a).unwrap();
        let bq = *metrics.get(&b).unwrap();
        let cq = *metrics.get(&c).unwrap();
        let dq = *metrics.get(&d).unwrap();

        assert_eq!(aq, (None, 0.0.into()));
        assert_eq!(bq, (Some(a), 2.0.into()));
        assert_eq!(cq, (Some(b), 4.0.into()));
        assert_eq!(dq, (Some(a), 2.0.into()));
    }
}
<commit_msg>Remove unused `metrics` function.<commit_after>use derivative::Derivative;
use std::cmp::Reverse;
use std::collections::hash_map::Entry;
use std::collections::{BinaryHeap, HashMap, HashSet};

use crate::entity::storage::AsStorage;
use crate::entity::traverse::Adjacency;
use crate::entity::view::{Bind, Unbind};
use crate::geometry::Metric;

#[derivative(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
#[derive(Derivative)]
struct KeyedMetric<K, Q>(
    #[derivative(Ord = "ignore", PartialEq = "ignore", PartialOrd = "ignore")] K,
    Q,
)
where
    Q: Eq + Ord;

pub fn metrics_with<'a, M, T, Q, F>(
    from: T,
    to: Option<T::Key>,
    f: F,
) -> HashMap<T::Key, (Option<T::Key>, Q)>
where
    M: 'a + AsStorage<T::Entity>,
    T: Adjacency + Bind<&'a M> + Copy + Unbind<&'a M>,
    Q: Copy + Metric,
    F: Fn(T, T) -> Q,
{
    let (storage, from) = from.unbind();
    let capacity = if to.is_some() {
        0
    }
    else {
        storage.as_storage().len()
    };
    let mut buffer = BinaryHeap::new();
    let mut breadcrumbs = HashSet::with_capacity(capacity);
    let mut metrics = HashMap::with_capacity(capacity);

    metrics.insert(from, (None, Q::zero()));
    buffer.push(KeyedMetric(from, Reverse(Q::zero())));
    while let Some(KeyedMetric(key, Reverse(metric))) = buffer.pop() {
        if Some(key) == to {
            break;
        }
        let entity = T::bind(storage, key).unwrap();
        if breadcrumbs.insert(entity.key()) {
            for adjacent in entity
                .adjacency()
                .into_iter()
                .map(|key| T::bind(storage, key).unwrap())
            {
                // TODO: Consider returning an error if the output of `f` is
                //       less than zero.
                let metric = metric + f(entity, adjacent);
                match metrics.entry(adjacent.key()) {
                    Entry::Occupied(entry) => {
                        if metric < entry.get().1 {
                            entry.into_mut().1 = metric;
                        }
                    }
                    Entry::Vacant(entry) => {
                        entry.insert((Some(entity.key()), metric));
                    }
                }
                buffer.push(KeyedMetric(adjacent.key(), Reverse(metric)));
            }
        }
    }
    metrics
}

#[cfg(test)]
mod tests {
    use decorum::R64;
    use nalgebra::Point2;
    use theon::space::InnerSpace;

    use crate::entity::dijkstra;
    use crate::graph::MeshGraph;
    use crate::prelude::*;
    use crate::primitive::{Tetragon, Trigon};

    #[test]
    fn logical_metrics() {
        let graph = MeshGraph::<()>::from_raw_buffers(vec![Trigon::new(0usize, 1, 2)], vec![(); 3])
            .unwrap();
        let vertex = graph.vertices().nth(0).unwrap();
        let metrics = dijkstra::metrics_with(vertex, None, |_, _| 1usize);
        let a = vertex.key();
        let b = vertex.outgoing_arc().destination_vertex().key();
        let c = vertex.outgoing_arc().next_arc().destination_vertex().key();
        let aq = *metrics.get(&a).unwrap();
        let bq = *metrics.get(&b).unwrap();
        let cq = *metrics.get(&c).unwrap();

        assert_eq!(aq, (None, 0));
        assert_eq!(bq, (Some(a), 1));
        assert_eq!(cq, (Some(a), 1));
    }

    #[allow(clippy::float_cmp)]
    #[test]
    fn euclidean_distance_metrics() {
        let graph = MeshGraph::<Point2<f64>>::from_raw_buffers(
            vec![Tetragon::new(0usize, 1, 2, 3)],
            vec![(-1.0, -1.0), (1.0, -1.0), (1.0, 1.0), (-1.0, 1.0)],
        )
        .unwrap();
        let vertex = graph.vertices().nth(0).unwrap();
        let metrics = dijkstra::metrics_with(vertex, None, |from, to| {
            R64::from((to.position() - from.position()).magnitude())
        });
        let a = vertex.key();
        let b = vertex.outgoing_arc().destination_vertex().key();
        let c = vertex.outgoing_arc().next_arc().destination_vertex().key();
        let d = vertex
            .outgoing_arc()
            .next_arc()
            .next_arc()
            .destination_vertex()
            .key();
        let aq = *metrics.get(&a).unwrap();
        let bq = *metrics.get(&b).unwrap();
        let cq = *metrics.get(&c).unwrap();
        let dq = *metrics.get(&d).unwrap();

        assert_eq!(aq, (None, 0.0.into()));
        assert_eq!(bq, (Some(a), 2.0.into()));
        assert_eq!(cq, (Some(b), 4.0.into()));
        assert_eq!(dq, (Some(a), 2.0.into()));
    }
}
<|endoftext|>


<commit_before>//! Helpers to program the task state segment.
//! See Intel 3a, Chapter 7

use core::arch::asm;
pub use crate::segmentation;

/// Returns the current value of the task register.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn tr() -> segmentation::SegmentSelector {
    let segment: u16;
    asm!("str {0:x}",
        out(reg) segment,
        options(att_syntax, nostack, nomem, preserves_flags));
    segmentation::SegmentSelector::from_raw(segment)
}

/// Loads the task register.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn load_tr(sel: segmentation::SegmentSelector) {
    asm!("ltr {0:x}",
        in(reg) sel.bits(),
        options(att_syntax, nostack, nomem, preserves_flags));
}
<commit_msg>Cargo fmt.<commit_after>//! Helpers to program the task state segment.
//! See Intel 3a, Chapter 7

pub use crate::segmentation;
use core::arch::asm;

/// Returns the current value of the task register.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn tr() -> segmentation::SegmentSelector {
    let segment: u16;
    asm!("str {0:x}",
        out(reg) segment,
        options(att_syntax, nostack, nomem, preserves_flags));
    segmentation::SegmentSelector::from_raw(segment)
}

/// Loads the task register.
///
/// # Safety
/// Needs CPL 0.
pub unsafe fn load_tr(sel: segmentation::SegmentSelector) {
    asm!("ltr {0:x}",
        in(reg) sel.bits(),
        options(att_syntax, nostack, nomem, preserves_flags));
}
<|endoftext|>


<commit_before>use mockito;
use errors::*;
use providers::ec2;

pub(crate) const URL: &'static str = ::mockito::SERVER_URL;

#[test]
fn test_ec2_basic() {
    let ep = "/meta-data/public-keys";
    let client = ::retry::Client::new()
        .chain_err(|| "failed to create http client")
        .unwrap()
        .max_attempts(1)
        .return_on_404(true);

    ec2::fetch_ssh_keys(&client).unwrap_err();

    let _m = mockito::mock("GET", ep)
        .with_status(503)
        .create();
    ec2::fetch_ssh_keys(&client).unwrap_err();

    let _m = mockito::mock("GET", ep)
        .with_status(200)
        .create();
    let v = ec2::fetch_ssh_keys(&client).unwrap();
    assert_eq!(v.len(), 0);

    let _m = mockito::mock("GET", ep)
        .with_status(404)
        .create();
    let v = ec2::fetch_ssh_keys(&client).unwrap();
    assert_eq!(v.len(), 0);
}
<commit_msg>providers/ec2: use Ec2Provider in mock tests<commit_after>use mockito;
use errors::*;
use providers::ec2;

pub(crate) const URL: &'static str = ::mockito::SERVER_URL;

#[test]
fn test_ec2_basic() {
    let ep = "/meta-data/public-keys";
    let client = ::retry::Client::new()
        .chain_err(|| "failed to create http client")
        .unwrap()
        .max_attempts(1)
        .return_on_404(true);
    let provider = ec2::Ec2Provider { client };

    provider.fetch_ssh_keys().unwrap_err();

    let _m = mockito::mock("GET", ep)
        .with_status(503)
        .create();
    provider.fetch_ssh_keys().unwrap_err();

    let _m = mockito::mock("GET", ep)
        .with_status(200)
        .create();
    let v = provider.fetch_ssh_keys().unwrap();
    assert_eq!(v.len(), 0);

    let _m = mockito::mock("GET", ep)
        .with_status(404)
        .create();
    let v = provider.fetch_ssh_keys().unwrap();
    assert_eq!(v.len(), 0);
}
<|endoftext|>


<commit_before>use crate::decor::InternalString;
use crate::parser::errors::CustomError;
use crate::parser::trivia::{newline, ws, ws_newlines};
use combine::char::char;
use combine::error::{Consumed, Info};
use combine::range::{range, take, take_while};
use combine::stream::RangeStream;
use combine::*;
use std::char;

// ;; String

// string = ml-basic-string / basic-string / ml-literal-string / literal-string
parse!(string() -> InternalString, {
    choice((
        ml_basic_string(),
        basic_string(),
        ml_literal_string(),
        literal_string().map(|s: &'a str| s.into()),
    ))
});

// basic-unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
#[inline]
fn is_basic_unescaped(c: char) -> bool {
    matches!(c, '\u{20}'..='\u{21}' | '\u{23}'..='\u{5B}' | '\u{5D}'..='\u{10FFFF}')
}

// escaped = escape ( %x22 /          ; "    quotation mark  U+0022
//                    %x5C /          ; \    reverse solidus U+005C
//                    %x2F /          ; /    solidus         U+002F
//                    %x62 /          ; b    backspace       U+0008
//                    %x66 /          ; f    form feed       U+000C
//                    %x6E /          ; n    line feed       U+000A
//                    %x72 /          ; r    carriage return U+000D
//                    %x74 /          ; t    tab             U+0009
//                    %x75 4HEXDIG /  ; uXXXX                U+XXXX
//                    %x55 8HEXDIG )  ; UXXXXXXXX            U+XXXXXXXX
#[inline]
fn is_escape_char(c: char) -> bool {
    matches!(c, '\\' | '"' | 'b' | '/' | 'f' | 'n' | 'r' | 't' | 'u' | 'U')
}

parse!(escape() -> char, {
    satisfy(is_escape_char)
        .message("While parsing escape sequence")
        .then(|c| {
            parser(move |input| {
                match c {
                    'b'  => Ok(('\u{8}', Consumed::Empty(()))),
                    'f'  => Ok(('\u{c}', Consumed::Empty(()))),
                    'n'  => Ok(('\n',    Consumed::Empty(()))),
                    'r'  => Ok(('\r',    Consumed::Empty(()))),
                    't'  => Ok(('\t',    Consumed::Empty(()))),
                    'u'  => hexescape(4).parse_stream(input),
                    'U'  => hexescape(8).parse_stream(input),
                    // ['\\', '"', '/']
                    _    => Ok((c,       Consumed::Empty(()))),
                }
            })
        })
});

parse!(hexescape(n: usize) -> char, {
    take(*n)
        .and_then(|s| u32::from_str_radix(s, 16))
        .and_then(|h| char::from_u32(h).ok_or(CustomError::InvalidHexEscape(h)))
});

// escape = %x5C                    ; \
const ESCAPE: char = '\\';

// basic-char = basic-unescaped / escaped
parse!(basic_char() -> char, {
    satisfy(|c| is_basic_unescaped(c) || c == ESCAPE)
        .then(|c| parser(move |input| {
            match c {
                ESCAPE => escape().parse_stream(input),
                _      => Ok((c, Consumed::Empty(()))),
            }
        }))
});

// quotation-mark = %x22            ; "
const QUOTATION_MARK: char = '"';

// basic-string = quotation-mark *basic-char quotation-mark
parse!(basic_string() -> InternalString, {
    between(char(QUOTATION_MARK), char(QUOTATION_MARK),
            many(basic_char()))
        .message("While parsing a Basic String")
});

// ;; Multiline Basic String

// ml-basic-unescaped = %x20-5B / %x5D-10FFFF
#[inline]
fn is_ml_basic_unescaped(c: char) -> bool {
    matches!(c, '\u{20}'..='\u{5B}' | '\u{5D}'..='\u{10FFFF}')
}

// ml-basic-string-delim = 3quotation-mark
const ML_BASIC_STRING_DELIM: &str = "\"\"\"";

// ml-basic-char = ml-basic-unescaped / escaped
parse!(ml_basic_char() -> char, {
    satisfy(|c| is_ml_basic_unescaped(c) || c == ESCAPE)
        .then(|c| parser(move |input| {
            match c {
                ESCAPE => escape().parse_stream(input),
                _      => Ok((c, Consumed::Empty(()))),
            }
        }))
});

// When the last non-whitespace character on a line is a \,
// it will be trimmed along with all whitespace
// (including newlines) up to the next non-whitespace
// character or closing delimiter.
parse!(try_eat_escaped_newline() -> (), {
    skip_many(attempt((
        char(ESCAPE),
        ws(),
        ws_newlines(),
    )))
});

// ml-basic-body = *( ( escape ws-newline ) / ml-basic-char / newline )
parse!(ml_basic_body() -> InternalString, {
    //  A newline immediately following the opening delimiter will be trimmed.
    optional(newline())
        .skip(try_eat_escaped_newline())
        .with(
            many(
                not_followed_by(range(ML_BASIC_STRING_DELIM).map(Info::Range))
                    .with(
                        choice((
                            // `TOML parsers should feel free to normalize newline
                            //  to whatever makes sense for their platform.`
                            newline(),
                            ml_basic_char(),
                        ))
                    )
                    .skip(try_eat_escaped_newline())
            )
        )
});

// ml-basic-string = ml-basic-string-delim ml-basic-body ml-basic-string-delim
parse!(ml_basic_string() -> InternalString, {
    between(range(ML_BASIC_STRING_DELIM),
            range(ML_BASIC_STRING_DELIM),
            ml_basic_body())
        .message("While parsing a Multiline Basic String")
});

// ;; Literal String

// apostrophe = %x27 ; ' apostrophe
const APOSTROPHE: char = '\'';

// literal-char = %x09 / %x20-26 / %x28-10FFFF
#[inline]
fn is_literal_char(c: char) -> bool {
    matches!(c, '\u{09}' | '\u{20}'..='\u{26}' | '\u{28}'..='\u{10FFFF}')
}

// literal-string = apostrophe *literal-char apostrophe
parse!(literal_string() -> &'a str, {
    between(char(APOSTROPHE), char(APOSTROPHE),
            take_while(is_literal_char))
        .message("While parsing a Literal String")
});

// ;; Multiline Literal String

// ml-literal-string-delim = 3apostrophe
const ML_LITERAL_STRING_DELIM: &str = "'''";

// ml-literal-char = %x09 / %x20-10FFFF
#[inline]
fn is_ml_literal_char(c: char) -> bool {
    matches!(c, '\u{09}' | '\u{20}'..='\u{10FFFF}')
}

// ml-literal-body = *( ml-literal-char / newline )
parse!(ml_literal_body() -> InternalString, {
    //  A newline immediately following the opening delimiter will be trimmed.
    optional(newline())
        .with(
            many(
                not_followed_by(range(ML_LITERAL_STRING_DELIM).map(Info::Range))
                    .with(
                        choice((
                            // `TOML parsers should feel free to normalize newline
                            //  to whatever makes sense for their platform.`
                            newline(),
                            satisfy(is_ml_literal_char),
                        ))
                    )
            )
        )
});

// ml-literal-string = ml-literal-string-delim ml-literal-body ml-literal-string-delim
parse!(ml_literal_string() -> InternalString, {
    between(range(ML_LITERAL_STRING_DELIM),
            range(ML_LITERAL_STRING_DELIM),
            ml_literal_body())
        .message("While parsing a Multiline Literal String")
});
<commit_msg>cargo fmt<commit_after>use crate::decor::InternalString;
use crate::parser::errors::CustomError;
use crate::parser::trivia::{newline, ws, ws_newlines};
use combine::char::char;
use combine::error::{Consumed, Info};
use combine::range::{range, take, take_while};
use combine::stream::RangeStream;
use combine::*;
use std::char;

// ;; String

// string = ml-basic-string / basic-string / ml-literal-string / literal-string
parse!(string() -> InternalString, {
    choice((
        ml_basic_string(),
        basic_string(),
        ml_literal_string(),
        literal_string().map(|s: &'a str| s.into()),
    ))
});

// basic-unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
#[inline]
fn is_basic_unescaped(c: char) -> bool {
    matches!(c, '\u{20}'..='\u{21}' | '\u{23}'..='\u{5B}' | '\u{5D}'..='\u{10FFFF}')
}

// escaped = escape ( %x22 /          ; "    quotation mark  U+0022
//                    %x5C /          ; \    reverse solidus U+005C
//                    %x2F /          ; /    solidus         U+002F
//                    %x62 /          ; b    backspace       U+0008
//                    %x66 /          ; f    form feed       U+000C
//                    %x6E /          ; n    line feed       U+000A
//                    %x72 /          ; r    carriage return U+000D
//                    %x74 /          ; t    tab             U+0009
//                    %x75 4HEXDIG /  ; uXXXX                U+XXXX
//                    %x55 8HEXDIG )  ; UXXXXXXXX            U+XXXXXXXX
#[inline]
fn is_escape_char(c: char) -> bool {
    matches!(
        c,
        '\\' | '"' | 'b' | '/' | 'f' | 'n' | 'r' | 't' | 'u' | 'U'
    )
}

parse!(escape() -> char, {
    satisfy(is_escape_char)
        .message("While parsing escape sequence")
        .then(|c| {
            parser(move |input| {
                match c {
                    'b'  => Ok(('\u{8}', Consumed::Empty(()))),
                    'f'  => Ok(('\u{c}', Consumed::Empty(()))),
                    'n'  => Ok(('\n',    Consumed::Empty(()))),
                    'r'  => Ok(('\r',    Consumed::Empty(()))),
                    't'  => Ok(('\t',    Consumed::Empty(()))),
                    'u'  => hexescape(4).parse_stream(input),
                    'U'  => hexescape(8).parse_stream(input),
                    // ['\\', '"', '/']
                    _    => Ok((c,       Consumed::Empty(()))),
                }
            })
        })
});

parse!(hexescape(n: usize) -> char, {
    take(*n)
        .and_then(|s| u32::from_str_radix(s, 16))
        .and_then(|h| char::from_u32(h).ok_or(CustomError::InvalidHexEscape(h)))
});

// escape = %x5C                    ; \
const ESCAPE: char = '\\';

// basic-char = basic-unescaped / escaped
parse!(basic_char() -> char, {
    satisfy(|c| is_basic_unescaped(c) || c == ESCAPE)
        .then(|c| parser(move |input| {
            match c {
                ESCAPE => escape().parse_stream(input),
                _      => Ok((c, Consumed::Empty(()))),
            }
        }))
});

// quotation-mark = %x22            ; "
const QUOTATION_MARK: char = '"';

// basic-string = quotation-mark *basic-char quotation-mark
parse!(basic_string() -> InternalString, {
    between(char(QUOTATION_MARK), char(QUOTATION_MARK),
            many(basic_char()))
        .message("While parsing a Basic String")
});

// ;; Multiline Basic String

// ml-basic-unescaped = %x20-5B / %x5D-10FFFF
#[inline]
fn is_ml_basic_unescaped(c: char) -> bool {
    matches!(c, '\u{20}'..='\u{5B}' | '\u{5D}'..='\u{10FFFF}')
}

// ml-basic-string-delim = 3quotation-mark
const ML_BASIC_STRING_DELIM: &str = "\"\"\"";

// ml-basic-char = ml-basic-unescaped / escaped
parse!(ml_basic_char() -> char, {
    satisfy(|c| is_ml_basic_unescaped(c) || c == ESCAPE)
        .then(|c| parser(move |input| {
            match c {
                ESCAPE => escape().parse_stream(input),
                _      => Ok((c, Consumed::Empty(()))),
            }
        }))
});

// When the last non-whitespace character on a line is a \,
// it will be trimmed along with all whitespace
// (including newlines) up to the next non-whitespace
// character or closing delimiter.
parse!(try_eat_escaped_newline() -> (), {
    skip_many(attempt((
        char(ESCAPE),
        ws(),
        ws_newlines(),
    )))
});

// ml-basic-body = *( ( escape ws-newline ) / ml-basic-char / newline )
parse!(ml_basic_body() -> InternalString, {
    //  A newline immediately following the opening delimiter will be trimmed.
    optional(newline())
        .skip(try_eat_escaped_newline())
        .with(
            many(
                not_followed_by(range(ML_BASIC_STRING_DELIM).map(Info::Range))
                    .with(
                        choice((
                            // `TOML parsers should feel free to normalize newline
                            //  to whatever makes sense for their platform.`
                            newline(),
                            ml_basic_char(),
                        ))
                    )
                    .skip(try_eat_escaped_newline())
            )
        )
});

// ml-basic-string = ml-basic-string-delim ml-basic-body ml-basic-string-delim
parse!(ml_basic_string() -> InternalString, {
    between(range(ML_BASIC_STRING_DELIM),
            range(ML_BASIC_STRING_DELIM),
            ml_basic_body())
        .message("While parsing a Multiline Basic String")
});

// ;; Literal String

// apostrophe = %x27 ; ' apostrophe
const APOSTROPHE: char = '\'';

// literal-char = %x09 / %x20-26 / %x28-10FFFF
#[inline]
fn is_literal_char(c: char) -> bool {
    matches!(c, '\u{09}' | '\u{20}'..='\u{26}' | '\u{28}'..='\u{10FFFF}')
}

// literal-string = apostrophe *literal-char apostrophe
parse!(literal_string() -> &'a str, {
    between(char(APOSTROPHE), char(APOSTROPHE),
            take_while(is_literal_char))
        .message("While parsing a Literal String")
});

// ;; Multiline Literal String

// ml-literal-string-delim = 3apostrophe
const ML_LITERAL_STRING_DELIM: &str = "'''";

// ml-literal-char = %x09 / %x20-10FFFF
#[inline]
fn is_ml_literal_char(c: char) -> bool {
    matches!(c, '\u{09}' | '\u{20}'..='\u{10FFFF}')
}

// ml-literal-body = *( ml-literal-char / newline )
parse!(ml_literal_body() -> InternalString, {
    //  A newline immediately following the opening delimiter will be trimmed.
    optional(newline())
        .with(
            many(
                not_followed_by(range(ML_LITERAL_STRING_DELIM).map(Info::Range))
                    .with(
                        choice((
                            // `TOML parsers should feel free to normalize newline
                            //  to whatever makes sense for their platform.`
                            newline(),
                            satisfy(is_ml_literal_char),
                        ))
                    )
            )
        )
});

// ml-literal-string = ml-literal-string-delim ml-literal-body ml-literal-string-delim
parse!(ml_literal_string() -> InternalString, {
    between(range(ML_LITERAL_STRING_DELIM),
            range(ML_LITERAL_STRING_DELIM),
            ml_literal_body())
        .message("While parsing a Multiline Literal String")
});
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::fs::{self, File, ReadDir, DirEntry};
use std::path::Path;
use std::vec;
use std::io::BufReader;
use std::cmp::Ordering;
use std::str::FromStr;

/// Get process stats (/proc/[pid]/stat)
pub mod stat;
/// Get process status (/proc/[pid]/status)
pub mod status;

use self::stat::PidStat;
use self::status::PidStatus;
use error::{ProcError, ProcFile, ProcOper};
use TaskId;

/// A struct containing information about a process.
///
/// This struct contains information from various files inside the
/// /proc/[pid] directory (for the respective pid).
#[derive(Debug)]
pub struct Pid {
    /// The tid of this process
    pub pid: TaskId,
    /// The /proc/[pid]/stat file
    pub stat: Box<PidStat>,
    /// The /proc/[pid]/status file
    pub status: Box<PidStatus>,
    /// The /proc/[pid]/cmdline file
    pub cmdline: Vec<String>,
    /// If this is a thread, this is set to true.
    /// Threads will never have tasks attached.
    is_thread: bool,
    /// Vec of threads under /proc/[pid]/tasks/[tid]
    threads: Option<Vec<Pid>>,
}

impl Pid {
    /// Create a new Pid struct for a process, given a pid.
    pub fn new(pid: TaskId) -> Result<Self, ProcError> {
        let pid_dir = Path::new("/proc");
        Self::new_dir(pid_dir, pid)
    }

    fn new_dir(proc_dir: &Path, pid: TaskId) -> Result<Self, ProcError> {
        let proc_dir = proc_dir.join(pid.to_string());
        let pid_stat = try!(PidStat::new(&proc_dir));
        let pid_status = try!(PidStatus::new(&proc_dir));
        let cmdline = try!(Self::read_cmdline(&proc_dir));

        Ok(Pid {
            pid: pid,
            stat: Box::new(pid_stat),
            status: Box::new(pid_status),
            cmdline: cmdline,
            is_thread: false,
            threads: None,
        })
    }

    /// Given a /proc/[pid] directory, read the respective /proc/[pid]/cmdline
    /// file and return them in a Vec.
    fn read_cmdline(proc_dir: &Path) -> Result<Vec<String>, ProcError> {
        File::open(proc_dir.join("cmdline"))
            .map_err(|e| ProcError::new_err(ProcOper::Opening, ProcFile::PidCmdline, e))
            .and_then(|file| {
                let mut contents = Vec::new();
                try!(
                    BufReader::with_capacity(4096, file)
                        .read_to_end(&mut contents)
                        .map_err(|e| ProcError::new_err(ProcOper::Reading, ProcFile::PidCmdline, e))
                );
                if contents.ends_with(&['\0' as u8]) {
                    let _ = contents.pop();
                }
                Ok(contents)
            }).and_then(|contents| {
                String::from_utf8(contents)
                    .or(Err(ProcError::new_more(ProcOper::Parsing, ProcFile::PidCmdline,
                                    Some("parsing utf8"))))
            }).map(|contents|
                contents
                    .split('\0')
                    .map(|a| a.to_string())
                    .collect()
            )
    }

    /// Determine whether this process matches this query
    fn query(&self, query: &PidQuery) -> bool {
        match *query {
            PidQuery::PidQuery(q) => PidQuery::taskid_query(self.stat.pid, q),
            PidQuery::PpidQuery(q) => PidQuery::taskid_query(self.stat.ppid, q),
            PidQuery::NameQuery(ref q) => PidQuery::string_query(&self.stat.comm, &q),
            PidQuery::CmdlineQuery(ref q) => PidQuery::string_query(&self.cmdline.join(" "), &q),
            PidQuery::NoneQuery => true
        }
    }

    pub fn tasks(&mut self) -> Option<Vec<Pid>> {
        self.tasks_query(PidQuery::NoneQuery)
    }

    // TODO: Work out if this really should return Option<_>
    // or Option<Result<Vec<Pid>>>. Otherwise the error is uncaught.
    pub fn tasks_query(&self, query: PidQuery) -> Option<Vec<Pid>> {
        if self.is_thread {
            return None;
        }

        PidIter::new_tid_query(self.pid, query.clone()).unwrap()
            .filter(|p| {
                let query = query.clone();
                match *p {
                    Ok(ref pid) => pid.query(&query),
                    Err(_) => true
                }
            }).collect::<Result<Vec<_>, _>>().ok()
    }
}

impl PartialEq for Pid {
    fn eq(&self, other: &Self) -> bool {
        self.stat.pid.eq(&other.stat.pid)
    }
}

impl Eq for Pid {}
impl PartialOrd for Pid {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl Ord for Pid {
    fn cmp(&self, other: &Self) -> Ordering {
        self.stat.pid.cmp(&other.stat.pid)
    }
}

/// An Iterator over processes in the system.
///
/// If a process disappears while scanning it, the partial Pid struct
/// will not be yielded. An atomic view of processes on the system seems
/// non-trivial.
pub struct PidIter {
    dir: String,
    dir_iter: ReadDir,
    query: PidQuery,
}

impl PidIter {
    /// Create a new iterator over all processes in /proc.
    pub fn new() -> Result<Self, ProcError> {
        Self::new_query(PidQuery::NoneQuery)
    }

    /// Create a new iterator over all processes in /proc, but only yield
    /// processes that match the given query.
    pub fn new_query(query: PidQuery) -> Result<Self, ProcError> {
        let dir_name = "/proc".to_owned();
        let proc_dir = Path::new(&dir_name);
        let dir_iter = try!(
            fs::read_dir(proc_dir)
                .map_err(|e|
                    ProcError::new(ProcOper::Opening, ProcFile::ProcDir, Some(e), Some("PidIter"))
                )
        );
        Ok(PidIter {
            dir: dir_name.clone(),
            dir_iter: dir_iter,
            query: query,
        })
    }

    fn new_tid_query(pid: TaskId, query: PidQuery) -> Result<Self, ProcError> {
        let dir_name = format!("/proc/{}/task", pid);
        let task_dir = Path::new(&dir_name);
        let dir_iter = try!(
            fs::read_dir(task_dir)
                .map_err(|e|
                    ProcError::new(ProcOper::Opening, ProcFile::PidTaskDir,
                        Some(e), Some("PidIter"))
                )
        );
        Ok(PidIter {
            dir: dir_name.clone(),
            dir_iter: dir_iter,
            query: query
        })
    }

    /// Given a DirEntry, try to create a Pid struct, and only return if
    /// it matches the query, and is complete.
    fn proc_dir_filter(entry_opt: Result<DirEntry, io::Error>, query: &PidQuery, dir_name: &str)
        -> Option<Result<Pid, ProcError>> {
        let file = entry_opt
            .map_err(|e|
                ProcError::new(ProcOper::Reading, ProcFile::ProcDir, Some(e), Some("PidIter"))
            )
            .and_then(|entry|
                entry.file_name().into_string()
                    .or(Err(ProcError::new_more(ProcOper::Parsing, ProcFile::ProcDir, Some("PidIter"))))
            );

        if let Err(e) = file{
            return Some(Err(e));
        }

        // Ensure filename is an integer (skip if not)
        match file.unwrap().parse() {
            Ok(pid) => {
                // If an error is not hard (error opening or reading file),
                // do not error as it may be a now-dead process.
                // If a parsing error occurs, then do return an error.
                let prc = match Pid::new_dir(Path::new(&dir_name), pid) {
                    Ok(prc) => prc,
                    Err(e) => {
                        if e.is_hard() {
                            return Some(Err(e));
                        } else {
                            return None;
                        }
                    }
                };
                match prc.query(&query) {
                    true => Some(Ok(prc)),
                    false => None
                }
            },
            Err(_) => None
        }
    }
}

impl Iterator for PidIter {
    type Item = Result<Pid, ProcError>;

    fn next(&mut self) -> Option<Self::Item> {
        for entry in self.dir_iter.by_ref() {
            match Self::proc_dir_filter(entry, &self.query, &self.dir) {
                some @ Some(_) => return some,
                None => continue
            }
        }
        None
    }

    /// Size may be anywhere from 0 to number of dirs.
    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, self.dir_iter.size_hint().1)
    }
}

/// An Iterator over threads of processes in the system.
///
/// If a task disappears while scanning it, the partial Pid struct
/// will not be yielded. An atomic view of processes on the system seems
/// non-trivial.
pub struct TidIter {
    pid_iter: PidIter,
    task_iter: Option<vec::IntoIter<Pid>>,
    query: PidQuery,
}

impl TidIter {
    /// Create a new iterator over all tasks in /proc.
    pub fn new() -> Result<Self, ProcError> {
            println!("{:?}", 3);
        Self::new_query(PidQuery::NoneQuery)
    }

    /// Create a new iterator over all tasks in /proc, but only yield
    /// those that match the given query.
    pub fn new_query(query: PidQuery) -> Result<Self, ProcError> {
        Ok(TidIter{
            pid_iter: try!(PidIter::new_query(query.clone())),
            task_iter: None,
            query: query,
        })
    }
}

impl Iterator for TidIter {
    type Item = Result<Pid, ProcError>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.task_iter.is_none() {
                let pid = match self.pid_iter.next() {
                    Some(Ok(pid)) => pid,
                    Some(Err(e)) => { return Some(Err(e)) },
                    None => { return None; }
                };
                let tasks_vec = pid.tasks_query(self.query.clone());
                if let Some(vec) = tasks_vec {
                    self.task_iter = Some(vec.into_iter());
                }
                continue;
            } else {
                let next = self.task_iter.as_mut().unwrap().next();
                match next {
                    Some(pid) => { return Some(Ok(pid)); },
                    None => { self.task_iter = None; },
                };
            }
        }
    }
}

#[derive(Clone, Debug)]
/// A list of query types for process querying.
pub enum PidQuery {
    /// Query by pid
    PidQuery(TaskId),
    /// Query by ppid
    PpidQuery(TaskId),
    /// Query by program name
    NameQuery(String),
    /// Query by cmdline contents (joined with space)
    CmdlineQuery(String),
    /// An empty query that always matches
    NoneQuery
}

impl PidQuery {
    /// Given a user-specified query string, decode it into
    /// an appropriate query.
    ///
    /// Bare number -> PidQuery
    /// Bare string -> NameQuery
    ///
    /// type=query is supported for the following types;
    /// pid -> PidQuery
    /// ppid -> PpidQuery
    /// name -> NameQuery
    /// cmdline -> CmdlineQuery
    fn create_query(query: &str) -> Result<PidQuery, String> {
        let splits: Vec<_> = query.splitn(2, '=').collect();

        match splits.len() {
            0 => Ok(PidQuery::NoneQuery),
            1 => Ok(match query.parse().ok() {
                Some(tid) => PidQuery::PidQuery(tid),
                None => PidQuery::NameQuery(query.to_owned())
            }),
            _ => {
                let q_text = splits[1].to_owned();
                let q_tid = q_text.parse();
                match &*splits[0].to_lowercase() {
                    "pid" => q_tid.map(|q| PidQuery::PidQuery(q))
                        .or(Err("Query value for type 'pid' not valid".to_owned())),
                    "ppid" => q_tid.map(|q| PidQuery::PpidQuery(q))
                        .or(Err("Query value for type 'ppid' not valid".to_owned())),
                    "name" => Ok(PidQuery::NameQuery(q_text)),
                    "cmdline" => Ok(PidQuery::CmdlineQuery(q_text)),
                    _ => Err("Invalid query type".to_owned())
                }
            }
        }
    }

    /// Match a pid by simple equality.
    pub fn taskid_query(tid: TaskId, query: TaskId) -> bool {
        tid == query
    }

    /// For strings, use a substring search.
    pub fn string_query(text: &str, query: &str) -> bool {
        text.contains(query)
    }
}

impl FromStr for PidQuery {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::create_query(s)
    }
}
<commit_msg>Add initial partial Pid parsing enum<commit_after>use std::io;
use std::io::prelude::*;
use std::fs::{self, File, ReadDir, DirEntry};
use std::path::Path;
use std::vec;
use std::io::BufReader;
use std::cmp::Ordering;
use std::str::FromStr;

/// Get process stats (/proc/[pid]/stat)
pub mod stat;
/// Get process status (/proc/[pid]/status)
pub mod status;

use self::stat::PidStat;
use self::status::PidStatus;
use error::{ProcError, ProcFile, ProcOper};
use TaskId;

/// A struct containing information about a process.
///
/// This struct contains information from various files inside the
/// /proc/[pid] directory (for the respective pid).
#[derive(Debug)]
pub struct Pid {
    // FIXME: Take Vec<PidFile> to indicate which things to parse
    /// The tid of this process
    pub pid: TaskId,
    /// The /proc/[pid]/stat file
    pub stat: Box<PidStat>,
    /// The /proc/[pid]/status file
    pub status: Box<PidStatus>,
    /// The /proc/[pid]/cmdline file
    pub cmdline: Vec<String>,
    /// If this is a thread, this is set to true.
    /// Threads will never have tasks attached.
    is_thread: bool,
    /// Vec of threads under /proc/[pid]/tasks/[tid]
    threads: Option<Vec<Pid>>,
}

impl Pid {
    /// Create a new Pid struct for a process, given a pid.
    pub fn new(pid: TaskId) -> Result<Self, ProcError> {
        let pid_dir = Path::new("/proc");
        Self::new_dir(pid_dir, pid)
    }

    fn new_dir(proc_dir: &Path, pid: TaskId) -> Result<Self, ProcError> {
        let proc_dir = proc_dir.join(pid.to_string());
        let pid_stat = try!(PidStat::new(&proc_dir));
        let pid_status = try!(PidStatus::new(&proc_dir));
        let cmdline = try!(Self::read_cmdline(&proc_dir));

        Ok(Pid {
            pid: pid,
            stat: Box::new(pid_stat),
            status: Box::new(pid_status),
            cmdline: cmdline,
            is_thread: false,
            threads: None,
        })
    }

    /// Given a /proc/[pid] directory, read the respective /proc/[pid]/cmdline
    /// file and return them in a Vec.
    fn read_cmdline(proc_dir: &Path) -> Result<Vec<String>, ProcError> {
        File::open(proc_dir.join("cmdline"))
            .map_err(|e| ProcError::new_err(ProcOper::Opening, ProcFile::PidCmdline, e))
            .and_then(|file| {
                let mut contents = Vec::new();
                try!(
                    BufReader::with_capacity(4096, file)
                        .read_to_end(&mut contents)
                        .map_err(|e| ProcError::new_err(ProcOper::Reading, ProcFile::PidCmdline, e))
                );
                if contents.ends_with(&['\0' as u8]) {
                    let _ = contents.pop();
                }
                Ok(contents)
            }).and_then(|contents| {
                String::from_utf8(contents)
                    .or(Err(ProcError::new_more(ProcOper::Parsing, ProcFile::PidCmdline,
                                    Some("parsing utf8"))))
            }).map(|contents|
                contents
                    .split('\0')
                    .map(|a| a.to_string())
                    .collect()
            )
    }

    /// Determine whether this process matches this query
    fn query(&self, query: &PidQuery) -> bool {
        match *query {
            PidQuery::PidQuery(q) => PidQuery::taskid_query(self.stat.pid, q),
            PidQuery::PpidQuery(q) => PidQuery::taskid_query(self.stat.ppid, q),
            PidQuery::NameQuery(ref q) => PidQuery::string_query(&self.stat.comm, &q),
            PidQuery::CmdlineQuery(ref q) => PidQuery::string_query(&self.cmdline.join(" "), &q),
            PidQuery::NoneQuery => true
        }
    }

    pub fn tasks(&mut self) -> Option<Vec<Pid>> {
        self.tasks_query(PidQuery::NoneQuery)
    }

    // TODO: Work out if this really should return Option<_>
    // or Option<Result<Vec<Pid>>>. Otherwise the error is uncaught.
    pub fn tasks_query(&self, query: PidQuery) -> Option<Vec<Pid>> {
        if self.is_thread {
            return None;
        }

        PidIter::new_tid_query(self.pid, query.clone()).unwrap()
            .filter(|p| {
                let query = query.clone();
                match *p {
                    Ok(ref pid) => pid.query(&query),
                    Err(_) => true
                }
            }).collect::<Result<Vec<_>, _>>().ok()
    }
}

impl PartialEq for Pid {
    fn eq(&self, other: &Self) -> bool {
        self.stat.pid.eq(&other.stat.pid)
    }
}

impl Eq for Pid {}
impl PartialOrd for Pid {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl Ord for Pid {
    fn cmp(&self, other: &Self) -> Ordering {
        self.stat.pid.cmp(&other.stat.pid)
    }
}

/// A list of files in the pid directory.
enum PIdFiles {
    PidStatus,
    PidStat,
    PidCmdline
}

/// An Iterator over processes in the system.
///
/// If a process disappears while scanning it, the partial Pid struct
/// will not be yielded. An atomic view of processes on the system seems
/// non-trivial.
pub struct PidIter {
    dir: String,
    dir_iter: ReadDir,
    query: PidQuery,
}

impl PidIter {
    /// Create a new iterator over all processes in /proc.
    pub fn new() -> Result<Self, ProcError> {
        Self::new_query(PidQuery::NoneQuery)
    }

    /// Create a new iterator over all processes in /proc, but only yield
    /// processes that match the given query.
    pub fn new_query(query: PidQuery) -> Result<Self, ProcError> {
        let dir_name = "/proc".to_owned();
        let proc_dir = Path::new(&dir_name);
        let dir_iter = try!(
            fs::read_dir(proc_dir)
                .map_err(|e|
                    ProcError::new(ProcOper::Opening, ProcFile::ProcDir, Some(e), Some("PidIter"))
                )
        );
        Ok(PidIter {
            dir: dir_name.clone(),
            dir_iter: dir_iter,
            query: query,
        })
    }

    fn new_tid_query(pid: TaskId, query: PidQuery) -> Result<Self, ProcError> {
        let dir_name = format!("/proc/{}/task", pid);
        let task_dir = Path::new(&dir_name);
        let dir_iter = try!(
            fs::read_dir(task_dir)
                .map_err(|e|
                    ProcError::new(ProcOper::Opening, ProcFile::PidTaskDir,
                        Some(e), Some("PidIter"))
                )
        );
        Ok(PidIter {
            dir: dir_name.clone(),
            dir_iter: dir_iter,
            query: query
        })
    }

    /// Given a DirEntry, try to create a Pid struct, and only return if
    /// it matches the query, and is complete.
    fn proc_dir_filter(entry_opt: Result<DirEntry, io::Error>, query: &PidQuery, dir_name: &str)
        -> Option<Result<Pid, ProcError>> {
        let file = entry_opt
            .map_err(|e|
                ProcError::new(ProcOper::Reading, ProcFile::ProcDir, Some(e), Some("PidIter"))
            )
            .and_then(|entry|
                entry.file_name().into_string()
                    .or(Err(ProcError::new_more(ProcOper::Parsing, ProcFile::ProcDir, Some("PidIter"))))
            );

        if let Err(e) = file{
            return Some(Err(e));
        }

        // Ensure filename is an integer (skip if not)
        match file.unwrap().parse() {
            Ok(pid) => {
                // If an error is not hard (error opening or reading file),
                // do not error as it may be a now-dead process.
                // If a parsing error occurs, then do return an error.
                let prc = match Pid::new_dir(Path::new(&dir_name), pid) {
                    Ok(prc) => prc,
                    Err(e) => {
                        if e.is_hard() {
                            return Some(Err(e));
                        } else {
                            return None;
                        }
                    }
                };
                match prc.query(&query) {
                    true => Some(Ok(prc)),
                    false => None
                }
            },
            Err(_) => None
        }
    }
}

impl Iterator for PidIter {
    type Item = Result<Pid, ProcError>;

    fn next(&mut self) -> Option<Self::Item> {
        for entry in self.dir_iter.by_ref() {
            match Self::proc_dir_filter(entry, &self.query, &self.dir) {
                some @ Some(_) => return some,
                None => continue
            }
        }
        None
    }

    /// Size may be anywhere from 0 to number of dirs.
    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, self.dir_iter.size_hint().1)
    }
}

/// An Iterator over threads of processes in the system.
///
/// If a task disappears while scanning it, the partial Pid struct
/// will not be yielded. An atomic view of processes on the system seems
/// non-trivial.
pub struct TidIter {
    pid_iter: PidIter,
    task_iter: Option<vec::IntoIter<Pid>>,
    query: PidQuery,
}

impl TidIter {
    /// Create a new iterator over all tasks in /proc.
    pub fn new() -> Result<Self, ProcError> {
            println!("{:?}", 3);
        Self::new_query(PidQuery::NoneQuery)
    }

    /// Create a new iterator over all tasks in /proc, but only yield
    /// those that match the given query.
    pub fn new_query(query: PidQuery) -> Result<Self, ProcError> {
        Ok(TidIter{
            pid_iter: try!(PidIter::new_query(query.clone())),
            task_iter: None,
            query: query,
        })
    }
}

impl Iterator for TidIter {
    type Item = Result<Pid, ProcError>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.task_iter.is_none() {
                let pid = match self.pid_iter.next() {
                    Some(Ok(pid)) => pid,
                    Some(Err(e)) => { return Some(Err(e)) },
                    None => { return None; }
                };
                let tasks_vec = pid.tasks_query(self.query.clone());
                if let Some(vec) = tasks_vec {
                    self.task_iter = Some(vec.into_iter());
                }
                continue;
            } else {
                let next = self.task_iter.as_mut().unwrap().next();
                match next {
                    Some(pid) => { return Some(Ok(pid)); },
                    None => { self.task_iter = None; },
                };
            }
        }
    }
}

#[derive(Clone, Debug)]
/// A list of query types for process querying.
pub enum PidQuery {
    /// Query by pid
    PidQuery(TaskId),
    /// Query by ppid
    PpidQuery(TaskId),
    /// Query by program name
    NameQuery(String),
    /// Query by cmdline contents (joined with space)
    CmdlineQuery(String),
    /// An empty query that always matches
    NoneQuery
}

impl PidQuery {
    /// Given a user-specified query string, decode it into
    /// an appropriate query.
    ///
    /// Bare number -> PidQuery
    /// Bare string -> NameQuery
    ///
    /// type=query is supported for the following types;
    /// pid -> PidQuery
    /// ppid -> PpidQuery
    /// name -> NameQuery
    /// cmdline -> CmdlineQuery
    fn create_query(query: &str) -> Result<PidQuery, String> {
        let splits: Vec<_> = query.splitn(2, '=').collect();

        match splits.len() {
            0 => Ok(PidQuery::NoneQuery),
            1 => Ok(match query.parse().ok() {
                Some(tid) => PidQuery::PidQuery(tid),
                None => PidQuery::NameQuery(query.to_owned())
            }),
            _ => {
                let q_text = splits[1].to_owned();
                let q_tid = q_text.parse();
                match &*splits[0].to_lowercase() {
                    "pid" => q_tid.map(|q| PidQuery::PidQuery(q))
                        .or(Err("Query value for type 'pid' not valid".to_owned())),
                    "ppid" => q_tid.map(|q| PidQuery::PpidQuery(q))
                        .or(Err("Query value for type 'ppid' not valid".to_owned())),
                    "name" => Ok(PidQuery::NameQuery(q_text)),
                    "cmdline" => Ok(PidQuery::CmdlineQuery(q_text)),
                    _ => Err("Invalid query type".to_owned())
                }
            }
        }
    }

    /// Match a pid by simple equality.
    pub fn taskid_query(tid: TaskId, query: TaskId) -> bool {
        tid == query
    }

    /// For strings, use a substring search.
    pub fn string_query(text: &str, query: &str) -> bool {
        text.contains(query)
    }
}

impl FromStr for PidQuery {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Self::create_query(s)
    }
}
<|endoftext|>