<commit_before>use core::result;
use core::fmt::Debug;

use ctx::{TryFromCtx, TryRefFromCtx};
use error;
use endian::Endian;

//type TryCtx<I, Ctx> = (I, Ctx);
//type SliceCtx<I, Ctx> = (I, I, Ctx);

/// A very generic, contextual pread interface in Rust. Allows completely parallelized reads, as `Self` is immutable
/// Don't be scared! The `Pread` definition _is_ terrifying, but it is definitely tractable. Essentially, `E` is the error, `Ctx` the parsing context, `I` is the indexing type, `TryCtx` is the "offset + ctx" Context given to the `TryFromCtx` trait bounds, and `SliceCtx` is the "offset + size + ctx" context given to the `TryRefFromCtx` trait bound.
///
/// They all have reasonable defaults, so if you're just using this trait, you can usually get away with `fn <T: scroll::Pread>(bytes: &T) -> yourResultWhichConvertsScrollErrors`
///
/// # Implementing Your Own Reader
/// If you want to implement your own reader for a type `Foo` from some kind of buffer (say `[u8]`), then you need to implement `TryFromCtx`
///
/// ```rust
/// use scroll::{self, ctx};
///  #[derive(Debug, PartialEq, Eq)]
///  pub struct Foo(u16);
///
///  impl<'a> ctx::TryFromCtx<'a> for Foo {
///      type Error = scroll::Error;
///      fn try_from_ctx(this: &'a [u8], ctx: (usize, scroll::Endian)) -> Result<Self, Self::Error> {
///          use scroll::Pread;
///          let offset = ctx.0;
///          let le = ctx.1;
///          if offset > 2 { return Err((scroll::Error::BadOffset("whatever".to_string())).into()) }
///          let n = this.pread(offset, le)?;
///          Ok(Foo(n))
///      }
///  }
///
/// use scroll::Pread;
/// // you can now read `Foo`'s out of a &[u8] buffer for free, with `Pread` and `Gread` without doing _anything_ else!
/// let bytes: [u8; 4] = [0xde, 0xad, 0, 0];
/// let foo = bytes.pread_into::<Foo>(0).unwrap();
/// assert_eq!(Foo(0xadde), foo);
/// let foo2 = bytes.pread::<Foo>(0, scroll::BE).unwrap();
/// assert_eq!(Foo(0xdeadu16), foo2);
/// ```
///
/// # Advanced: Using Your Own Error in `TryFromCtx`
/// ```rust
///  use scroll::{self, ctx};
///  use std::error;
///  use std::fmt::{self, Display};
///  // make some kind of normal error which also can transform a scroll error ideally (quick_error, error_chain allow this automatically nowadays)
///  #[derive(Debug)]
///  pub struct ExternalError {}
///
///  impl Display for ExternalError {
///      fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
///          write!(fmt, "ExternalError")
///      }
///  }
///
///  impl error::Error for ExternalError {
///      fn description(&self) -> &str {
///          "ExternalError"
///      }
///      fn cause(&self) -> Option<&error::Error> { None}
///  }
///
///  impl From<scroll::Error> for ExternalError {
///      fn from(err: scroll::Error) -> Self {
///          match err {
///              _ => ExternalError{},
///          }
///      }
///  }
///  #[derive(Debug, PartialEq, Eq)]
///  pub struct Foo(u16);
///
///  impl<'a> ctx::TryFromCtx<'a> for Foo {
///      type Error = ExternalError;
///      fn try_from_ctx(this: &'a [u8], ctx: (usize, scroll::Endian)) -> Result<Self, Self::Error> {
///          use scroll::Pread;
///          let offset = ctx.0;
///          let le = ctx.1;
///          if offset > 2 { return Err((ExternalError {}).into()) }
///          let n = this.pread(offset, le)?;
///          Ok(Foo(n))
///      }
///  }
///
/// use scroll::Pread;
/// // the only caveat is that you now need to specify the error type in fn generic params, e.g. `fn thingee<S: scroll::Pread<ExternalError>>`
/// let bytes: [u8; 4] = [0xde, 0xad, 0, 0];
/// let foo: Result<Foo, ExternalError> = bytes.pread_into(0);
/// ```

pub trait Pread<E = error::Error, Ctx = Endian, I = usize, TryCtx = (I, Ctx), SliceCtx = (I, I, Ctx) >
 where E: Debug,
       Ctx: Copy + Default + Debug,
       I: Copy + Debug,
       TryCtx: Copy + Default + Debug,
       SliceCtx: Copy + Default + Debug,
{
    #[inline]
    /// Implement this if you need a faster version for use by `Gread`
    fn pread_unsafe<'a, N: TryFromCtx<'a, TryCtx, Error = E>>(&'a self, offset: I, ctx: Ctx) -> N {
        self.pread(offset, ctx).unwrap()
    }
    #[inline]
    /// Reads a value from `self` at `offset` with a default `Ctx`. For the primitive numeric values, this will read at the machine's endianness.
    /// # Example
    /// ```rust
    /// use scroll::Pread;
    /// let bytes = [0x7fu8; 0x01];
    /// let byte = bytes.pread_into::<u8>(0).unwrap();
    fn pread_into<'a, N: TryFromCtx<'a, TryCtx, Error = E>>(&'a self, offset: I) -> result::Result<N, E> {
        self.pread(offset, Ctx::default())
    }
    #[inline]
    /// Reads a value from `self` at `offset` with the given `ctx`
    /// # Example
    /// ```rust
    /// use scroll::Pread;
    /// let bytes: [u8; 2] = [0xde, 0xad];
    /// let dead: u16 = bytes.pread(0, scroll::BE).unwrap();
    /// assert_eq!(dead, 0xdeadu16);
    fn pread<'a, N: TryFromCtx<'a, TryCtx, Error = E>>(&'a self, offset: I, ctx: Ctx) -> result::Result<N, E>;
    /// Slices an `N` from `self` at `offset` up to `count` times
    #[inline]
    /// # Example
    /// ```rust
    /// use scroll::Pread;
    /// let bytes: [u8; 2] = [0x48, 0x49];
    /// let hi: &str = bytes.pread_slice(0, 2).unwrap();
    /// assert_eq!(hi, "HI");
    /// let bytes2 = bytes.pread_slice::<[u8]>(0, 2).unwrap();
    /// assert_eq!(bytes, bytes2);
    fn pread_slice<'a, N: ?Sized + TryRefFromCtx<SliceCtx, Error = E>>(&'a self, offset: I, count: I) -> result::Result<&'a N, E>;
}

impl<E, Ctx> Pread<E, Ctx> for [u8]
    where
    E: Debug,
    Ctx: Debug + Copy + Default {
    #[inline]
    fn pread_unsafe<'a, N: TryFromCtx<'a, (usize, Ctx), Error = E>>(&'a self, offset: usize, le: Ctx) -> N {
        TryFromCtx::try_from_ctx(self, (offset, le)).unwrap()
    }
    #[inline]
    fn pread<'a, N: TryFromCtx<'a, (usize, Ctx), Error = E>>(&'a self, offset: usize, le: Ctx) -> result::Result<N, E> {
        TryFromCtx::try_from_ctx(self, (offset, le))
    }
    #[inline]
    fn pread_slice<N: ?Sized + TryRefFromCtx<(usize, usize, Ctx), Error = E>>(&self, offset: usize, count: usize) -> result::Result<&N, E> {
        TryRefFromCtx::try_ref_from_ctx(self, (offset, count, Ctx::default()))
    }
}

impl<E, Ctx, T> Pread<E, Ctx> for T
    where
    E: Debug,
    Ctx: Debug + Copy + Default,
    T: AsRef<[u8]> {
    #[inline]
    fn pread_unsafe<'a, N: TryFromCtx<'a, (usize, Ctx), Error = E>>(&'a self, offset: usize, le: Ctx) -> N {
        <[u8] as Pread<E, Ctx>>::pread_unsafe::<N>(self.as_ref(), offset, le)
        //FromCtx::try_from_ctx(self.as_ref(), offset, le)
    }
    #[inline]
    fn pread<'a, N: TryFromCtx<'a, (usize, Ctx), Error = E>>(&'a self, offset: usize, le: Ctx) -> result::Result<N, E> {
        TryFromCtx::try_from_ctx(self.as_ref(), (offset, le))
        //<[u8] as Pread<E, Ctx>>::pread::<N>(self.as_ref(), offset, le)
        //(*self.as_ref()).pread(offset, le)
    }
    #[inline]
    //fn pread_slice<N: ?Sized + TrySliceFrom<Error = E>>(&self, offset: usize, count: usize) -> result::Result<&N, E> {
    fn pread_slice<N: ?Sized + TryRefFromCtx<(usize, usize, Ctx), Error = E>>(&self, offset: usize, count: usize) -> result::Result<&N, E> {
        //(*self.as_ref()).pread_slice(offset, count)
        //TrySliceFrom::slice_from(self, offset, count)
        //<[u8] as Pread<E>>::pread_slice::<N>(self.as_ref(), offset, count)
        <[u8] as Pread<E, Ctx>>::pread_slice::<N>(self.as_ref(), offset, count)
    }
}

// impl<E, T> Pread<E> for Cursor<T> where T: AsRef<[u8]>, E: Debug {
//     #[inline]
//     fn pread_unsafe<N: FromCtx>(&self, offset: usize, le: super::Endian) -> N {
//         <[u8] as Pread<E>>::pread_unsafe::<N>(self.get_ref().as_ref(), offset, le)
//             //(*self.get_ref().as_ref()).pread_unsafe(offset, le)
//     }
//     #[inline]
//     fn pread<N: TryFromCtx<(usize, super::Endian), Error = E>>(&self, offset: usize, le: super::Endian) -> result::Result<N, E> {
//         (*self.get_ref().as_ref()).pread(offset, le)
//     }
//     #[inline]
//     fn pread_slice<N: ?Sized + TrySliceFrom<Error = E>>(&self, offset: usize, count: usize) -> result::Result<&N, E> {
//         (*self.get_ref().as_ref()).pread_slice(offset, count)
//     }
// }

// /// Implements a parallelized Pread + PwriteCompat bytes buffer
// pub mod parallel {

//     //use crossbeam;
//     use std::collections::HashSet;
//     use buffer;
//     use std::ops;
//     use std::io;
//     use std::result;
//     use std::slice;
//     use std::fs::OpenOptions;

//     use measure::Measure;
//     use greater::GreaterWrite;

//     type Range = ops::Range<usize>;

//     quick_error! {
//         #[derive(Debug)]
//         pub enum Error {
//             Io(err: io::Error) { from () }
//             EmptyFlush { from() }
//         }
//     }

//     type Result<T> = result::Result<T, Error>;

//     #[derive(Debug, Clone)]
//     pub enum Data {
//         U8(u8),
//         U16(u16),
//         U32(u32),
//         U64(u64),
//         Bytes(String),
//     }

//     impl Measure for Data {
//         fn measure(&self) -> usize {
//             match *self {
//                 Data::U8(_) => 1,
//                 Data::U16(_) => 2,
//                 Data::U32(_) => 4,
//                 Data::U64(_) => 8,
//                 Data::Bytes(ref string) => string.len(),
//             }
//         }
//     }

//     type Inner = buffer::Buffer;

//     /// A buffer for parallel reading and parallel writing
//     /// Describes the interface necessary to perform an effectless offset computation
//     /// on the underlying _writer_
//     /// NOTE: if every offset and write len computation is not an intersecting range of some other range in the in-flight writes
//     /// The write can be performed _completely_ in parallel with _no_ locking, by definition, as every write
//     /// is guaranteed to be free from the range of any other write.
//     //#[derive(Debug, Default)]
//     pub struct Buffer {
//         /// map of current in flight write computations
//         //ranges: HashMap<u64, Vec<Range>>,
//         ranges: HashSet<Vec<Range>>,
//         commits: Vec<(Data, Range)>,
//         //commits: crossbeam::sync::MsQueue<(Data, Range)>,
//         //commits: crossbeam::sync::chase_lev::Deque<(Data, Range)>,
//         //commits: crossbeam::sync::chase_lev::Worker<(Data, Range)>,
//         //flusher: crossbeam::sync::chase_lev::Stealer<(Data, Range)>,
//         /// underlying bytes
//         inner: Inner,
//         len: usize,
//         ncommits: usize,
//         /// debug buffer
//         _debug: Vec<String>,
//     }

//     impl Buffer {
//         pub fn new(buffer: buffer::Buffer) -> Buffer {
//             //let (commits, flusher) = crossbeam::sync::chase_lev::deque();
//             let commits = Vec::new();
//             Buffer {
//                 inner: buffer, ranges: HashSet::new(),
//                 _debug: Vec::new(),
//                 len: 0,
//                 ncommits: 0,
//                 //commits: commits, flusher: flusher,
//                 commits: commits,
//             }
//         }

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

//         //pub fn commit(&mut self, data: Data, range: Range) {
//         pub fn commit(&mut self, data: Data, offset: usize) {
//             let count = data.measure();
//             self.len += count;
//             self.ncommits += 1;
//             let range = offset..(offset + count);
//             // todo: check commit conflicts here
//             self.commits.push((data, range));
//         }

//         //<greater::GreaterWrite>
//         fn write(memmap: &[u8], len: usize, data: Data, range: Range) -> io::Result<()> {
//             let memmap = memmap as *const _ as *mut u8;
//             let memmap = unsafe { slice::from_raw_parts_mut(memmap, len) };
//             let offset = range.start;
//             match data {
//                 Data::U8(n) =>  memmap.write_u8           (offset, n),
//                 Data::U16(n) => memmap.write_u16          (offset, n, true),
//                 Data::U32(n) => memmap.write_u32          (offset, n, true),
//                 Data::U64(n) => memmap.write_u64          (offset, n, true),
//                 Data::Bytes(string) => memmap.write_slice (offset, string.as_bytes()),
//             }
//         }

//         pub fn flush(self, name: &str) -> Result<()> {
//             use rayon::prelude::*;
//             use memmap;
//             if self.len != 0 {
//                 //let file = File::create(name)?;
//                 let file = OpenOptions::new()
//                     .read(true)
//                     .write(true)
//                     .create(true)
//                     .open(name)?;
//                 println!("file: {:?}", file);
//                 file.set_len(self.len as u64)?;
//                 println!("len: {:?}", file.metadata().unwrap().len());
//                 let memmap = memmap::Mmap::open(&file, memmap::Protection::ReadWrite)?;
//                 println!("memmamp: {:?}", memmap);
//                 let memmap_slice = unsafe { memmap.as_slice() };
//                 let commits = self.commits;
//                 let len = self.len;
//                 commits.into_par_iter().for_each( | (data, range) | {
//                     //println!("data: {:?}", data);
//                     Buffer::write(memmap_slice, len, data, range).unwrap();
//                 });
//                 memmap.flush()?;
//                 Ok(())
//             } else {
//                 return Err(Error::EmptyFlush)
//             }
//         }
//     }
// }

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

//     #[test]
//     fn test_parallel_buffer() {
//         let crt1: Vec<u8> = include!("../crt1.rs");
//         let len2 = crt1.len();
//         let mut buffer = parallel::Buffer::new(Buffer::new(crt1));

//         buffer.commit(parallel::Data::U16(0xdead), 0);
//         buffer.commit(parallel::Data::U16(0xbeef), 2);
//         buffer.commit(parallel::Data::Bytes("lol i'm literally the best".to_owned()), 4);
//         let len1 = buffer.len();
//         buffer.flush("test.data").unwrap();
//         assert!(true);
//     }

//     #[test]
//     fn test_parallel_buffer2() {
//         use std::fs::File;
//         //let libc: Vec<u8> = include!("../libc.rs");
//         let mut file = File::open("libc.so.6").unwrap();
//         println!("file: {:?}", file);
//         let b = Buffer::try_from(file).unwrap();
//         let libc: Vec<u8> = b.into_inner();
//         let len2 = libc.len();
//         let mut buffer = parallel::Buffer::new(Buffer::new(&libc));
//         let mut offset = 0;
//         for byte in libc {
//             buffer.commit(parallel::Data::U8(byte), offset);
//             offset += 1;
//         }
//         let len1 = buffer.len();
//         buffer.flush("libc.test").unwrap();
//         assert!(len1 == len2);
//     }
// }
<commit_msg>pread: cleanup file<commit_after>use core::result;
use core::fmt::Debug;

use ctx::{TryFromCtx, TryRefFromCtx};
use error;
use endian::Endian;

/// A very generic, contextual pread interface in Rust. Allows completely parallelized reads, as `Self` is immutable
/// Don't be scared! The `Pread` definition _is_ terrifying, but it is definitely tractable. Essentially, `E` is the error, `Ctx` the parsing context, `I` is the indexing type, `TryCtx` is the "offset + ctx" Context given to the `TryFromCtx` trait bounds, and `SliceCtx` is the "offset + size + ctx" context given to the `TryRefFromCtx` trait bound.
///
/// They all have reasonable defaults, so if you're just using this trait, you can usually get away with `fn <T: scroll::Pread>(bytes: &T) -> yourResultWhichConvertsScrollErrors`
///
/// # Implementing Your Own Reader
/// If you want to implement your own reader for a type `Foo` from some kind of buffer (say `[u8]`), then you need to implement `TryFromCtx`
///
/// ```rust
/// use scroll::{self, ctx};
///  #[derive(Debug, PartialEq, Eq)]
///  pub struct Foo(u16);
///
///  impl<'a> ctx::TryFromCtx<'a> for Foo {
///      type Error = scroll::Error;
///      fn try_from_ctx(this: &'a [u8], ctx: (usize, scroll::Endian)) -> Result<Self, Self::Error> {
///          use scroll::Pread;
///          let offset = ctx.0;
///          let le = ctx.1;
///          if offset > 2 { return Err((scroll::Error::BadOffset("whatever".to_string())).into()) }
///          let n = this.pread(offset, le)?;
///          Ok(Foo(n))
///      }
///  }
///
/// use scroll::Pread;
/// // you can now read `Foo`'s out of a &[u8] buffer for free, with `Pread` and `Gread` without doing _anything_ else!
/// let bytes: [u8; 4] = [0xde, 0xad, 0, 0];
/// let foo = bytes.pread_into::<Foo>(0).unwrap();
/// assert_eq!(Foo(0xadde), foo);
/// let foo2 = bytes.pread::<Foo>(0, scroll::BE).unwrap();
/// assert_eq!(Foo(0xdeadu16), foo2);
/// ```
///
/// # Advanced: Using Your Own Error in `TryFromCtx`
/// ```rust
///  use scroll::{self, ctx};
///  use std::error;
///  use std::fmt::{self, Display};
///  // make some kind of normal error which also can transform a scroll error ideally (quick_error, error_chain allow this automatically nowadays)
///  #[derive(Debug)]
///  pub struct ExternalError {}
///
///  impl Display for ExternalError {
///      fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
///          write!(fmt, "ExternalError")
///      }
///  }
///
///  impl error::Error for ExternalError {
///      fn description(&self) -> &str {
///          "ExternalError"
///      }
///      fn cause(&self) -> Option<&error::Error> { None}
///  }
///
///  impl From<scroll::Error> for ExternalError {
///      fn from(err: scroll::Error) -> Self {
///          match err {
///              _ => ExternalError{},
///          }
///      }
///  }
///  #[derive(Debug, PartialEq, Eq)]
///  pub struct Foo(u16);
///
///  impl<'a> ctx::TryFromCtx<'a> for Foo {
///      type Error = ExternalError;
///      fn try_from_ctx(this: &'a [u8], ctx: (usize, scroll::Endian)) -> Result<Self, Self::Error> {
///          use scroll::Pread;
///          let offset = ctx.0;
///          let le = ctx.1;
///          if offset > 2 { return Err((ExternalError {}).into()) }
///          let n = this.pread(offset, le)?;
///          Ok(Foo(n))
///      }
///  }
///
/// use scroll::Pread;
/// // the only caveat is that you now need to specify the error type in fn generic params, e.g. `fn thingee<S: scroll::Pread<ExternalError>>`
/// let bytes: [u8; 4] = [0xde, 0xad, 0, 0];
/// let foo: Result<Foo, ExternalError> = bytes.pread_into(0);
/// ```

pub trait Pread<E = error::Error, Ctx = Endian, I = usize, TryCtx = (I, Ctx), SliceCtx = (I, I, Ctx) >
 where E: Debug,
       Ctx: Copy + Default + Debug,
       I: Copy + Debug,
       TryCtx: Copy + Default + Debug,
       SliceCtx: Copy + Default + Debug,
{
    #[inline]
    /// Implement this if you need a faster version for use by `Gread`
    fn pread_unsafe<'a, N: TryFromCtx<'a, TryCtx, Error = E>>(&'a self, offset: I, ctx: Ctx) -> N {
        self.pread(offset, ctx).unwrap()
    }
    #[inline]
    /// Reads a value from `self` at `offset` with a default `Ctx`. For the primitive numeric values, this will read at the machine's endianness.
    /// # Example
    /// ```rust
    /// use scroll::Pread;
    /// let bytes = [0x7fu8; 0x01];
    /// let byte = bytes.pread_into::<u8>(0).unwrap();
    fn pread_into<'a, N: TryFromCtx<'a, TryCtx, Error = E>>(&'a self, offset: I) -> result::Result<N, E> {
        self.pread(offset, Ctx::default())
    }
    #[inline]
    /// Reads a value from `self` at `offset` with the given `ctx`
    /// # Example
    /// ```rust
    /// use scroll::Pread;
    /// let bytes: [u8; 2] = [0xde, 0xad];
    /// let dead: u16 = bytes.pread(0, scroll::BE).unwrap();
    /// assert_eq!(dead, 0xdeadu16);
    fn pread<'a, N: TryFromCtx<'a, TryCtx, Error = E>>(&'a self, offset: I, ctx: Ctx) -> result::Result<N, E>;
    /// Slices an `N` from `self` at `offset` up to `count` times
    #[inline]
    /// # Example
    /// ```rust
    /// use scroll::Pread;
    /// let bytes: [u8; 2] = [0x48, 0x49];
    /// let hi: &str = bytes.pread_slice(0, 2).unwrap();
    /// assert_eq!(hi, "HI");
    /// let bytes2 = bytes.pread_slice::<[u8]>(0, 2).unwrap();
    /// assert_eq!(bytes, bytes2);
    fn pread_slice<'a, N: ?Sized + TryRefFromCtx<SliceCtx, Error = E>>(&'a self, offset: I, count: I) -> result::Result<&'a N, E>;
}

impl<E, Ctx> Pread<E, Ctx> for [u8]
    where
    E: Debug,
    Ctx: Debug + Copy + Default {
    #[inline]
    fn pread_unsafe<'a, N: TryFromCtx<'a, (usize, Ctx), Error = E>>(&'a self, offset: usize, le: Ctx) -> N {
        TryFromCtx::try_from_ctx(self, (offset, le)).unwrap()
    }
    #[inline]
    fn pread<'a, N: TryFromCtx<'a, (usize, Ctx), Error = E>>(&'a self, offset: usize, le: Ctx) -> result::Result<N, E> {
        TryFromCtx::try_from_ctx(self, (offset, le))
    }
    #[inline]
    fn pread_slice<N: ?Sized + TryRefFromCtx<(usize, usize, Ctx), Error = E>>(&self, offset: usize, count: usize) -> result::Result<&N, E> {
        TryRefFromCtx::try_ref_from_ctx(self, (offset, count, Ctx::default()))
    }
}

impl<E, Ctx, T> Pread<E, Ctx> for T
    where
    E: Debug,
    Ctx: Debug + Copy + Default,
    T: AsRef<[u8]> {
    #[inline]
    fn pread_unsafe<'a, N: TryFromCtx<'a, (usize, Ctx), Error = E>>(&'a self, offset: usize, le: Ctx) -> N {
        <[u8] as Pread<E, Ctx>>::pread_unsafe::<N>(self.as_ref(), offset, le)
    }
    #[inline]
    fn pread<'a, N: TryFromCtx<'a, (usize, Ctx), Error = E>>(&'a self, offset: usize, le: Ctx) -> result::Result<N, E> {
        TryFromCtx::try_from_ctx(self.as_ref(), (offset, le))
    }
    #[inline]
    fn pread_slice<N: ?Sized + TryRefFromCtx<(usize, usize, Ctx), Error = E>>(&self, offset: usize, count: usize) -> result::Result<&N, E> {
        <[u8] as Pread<E, Ctx>>::pread_slice::<N>(self.as_ref(), offset, count)
    }
}
<|endoftext|>


<commit_before>//! lint on multiple versions of a crate being used

use crate::utils::span_lint;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::DUMMY_SP;
use syntax::ast::*;

use itertools::Itertools;

declare_clippy_lint! {
    /// **What it does:** Checks to see if multiple versions of a crate are being
    /// used.
    ///
    /// **Why is this bad?** This bloats the size of targets, and can lead to
    /// confusing error messages when structs or traits are used interchangeably
    /// between different versions of a crate.
    ///
    /// **Known problems:** Because this can be caused purely by the dependencies
    /// themselves, it's not always possible to fix this issue.
    ///
    /// **Example:**
    /// ```toml
    /// # This will pull in both winapi v0.3.4 and v0.2.8, triggering a warning.
    /// [dependencies]
    /// ctrlc = "3.1.0"
    /// ansi_term = "0.11.0"
    /// ```
    pub MULTIPLE_CRATE_VERSIONS,
    cargo,
    "multiple versions of the same crate being used"
}

declare_lint_pass!(MultipleCrateVersions => [MULTIPLE_CRATE_VERSIONS]);

impl EarlyLintPass for MultipleCrateVersions {
    fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
        let metadata = if let Ok(metadata) = cargo_metadata::MetadataCommand::new().exec() {
            metadata
        } else {
            span_lint(cx, MULTIPLE_CRATE_VERSIONS, DUMMY_SP, "could not read cargo metadata");

            return;
        };

        let mut packages = metadata.packages;
        packages.sort_by(|a, b| a.name.cmp(&b.name));

        for (name, group) in &packages.into_iter().group_by(|p| p.name.clone()) {
            let group: Vec<cargo_metadata::Package> = group.collect();

            if group.len() > 1 {
                let versions = group.into_iter().map(|p| p.version).join(", ");

                span_lint(
                    cx,
                    MULTIPLE_CRATE_VERSIONS,
                    DUMMY_SP,
                    &format!("multiple versions for dependency `{}`: {}", name, versions),
                );
            }
        }
    }
}
<commit_msg>Pin versions to trigger lint correctly<commit_after>//! lint on multiple versions of a crate being used

use crate::utils::span_lint;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::DUMMY_SP;
use syntax::ast::*;

use itertools::Itertools;

declare_clippy_lint! {
    /// **What it does:** Checks to see if multiple versions of a crate are being
    /// used.
    ///
    /// **Why is this bad?** This bloats the size of targets, and can lead to
    /// confusing error messages when structs or traits are used interchangeably
    /// between different versions of a crate.
    ///
    /// **Known problems:** Because this can be caused purely by the dependencies
    /// themselves, it's not always possible to fix this issue.
    ///
    /// **Example:**
    /// ```toml
    /// # This will pull in both winapi v0.3.x and v0.2.x, triggering a warning.
    /// [dependencies]
    /// ctrlc = "=3.1.0"
    /// ansi_term = "=0.11.0"
    /// ```
    pub MULTIPLE_CRATE_VERSIONS,
    cargo,
    "multiple versions of the same crate being used"
}

declare_lint_pass!(MultipleCrateVersions => [MULTIPLE_CRATE_VERSIONS]);

impl EarlyLintPass for MultipleCrateVersions {
    fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
        let metadata = if let Ok(metadata) = cargo_metadata::MetadataCommand::new().exec() {
            metadata
        } else {
            span_lint(cx, MULTIPLE_CRATE_VERSIONS, DUMMY_SP, "could not read cargo metadata");

            return;
        };

        let mut packages = metadata.packages;
        packages.sort_by(|a, b| a.name.cmp(&b.name));

        for (name, group) in &packages.into_iter().group_by(|p| p.name.clone()) {
            let group: Vec<cargo_metadata::Package> = group.collect();

            if group.len() > 1 {
                let versions = group.into_iter().map(|p| p.version).join(", ");

                span_lint(
                    cx,
                    MULTIPLE_CRATE_VERSIONS,
                    DUMMY_SP,
                    &format!("multiple versions for dependency `{}`: {}", name, versions),
                );
            }
        }
    }
}
<|endoftext|>


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

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct PageParams {
    pub size: i64,
    pub number: i64,
}

/// JSON-API Query parameters
#[derive(Debug, PartialEq, Default)]
pub struct Query {
    pub _type: String,
    pub include: Option<Vec<String>>,
    pub fields: Option<HashMap<String, Vec<String>>>,
    pub page: Option<PageParams>,
    pub sort: Option<Vec<String>>,
    pub filter: Option<HashMap<String, Vec<String>>>
}

/// JSON-API Query parameters
impl Query {
    ///
    /// Takes a query parameter string and returns a Query
    ///
    /// ```
    /// use jsonapi::query::Query;
    /// let query = Query::from_params("include=author&fields[articles]=title,\
    ///                                 body&fields[people]=name&page[number]=3&page[size]=1");
    /// match query.include {
    ///     None => assert!(false),
    ///     Some(include) => {
    ///         assert_eq!(include.len(), 1);
    ///         assert_eq!(include[0], "author");
    ///     }
    /// }
    ///
    /// ```
    pub fn from_params(params: &str) -> Self {

        match parse(params) {
            Ok(o) => {
                let include = match o.pointer("/include") {
                    None => None,
                    Some(inc) => {
                        match inc.as_str() {
                            None => None,
                            Some(include_str) => {
                                let arr: Vec<String> =
                                    include_str.split(',').map(|s| s.to_string()).collect();
                                Some(arr)
                            }
                        }
                    }
                };

                let mut fields = HashMap::<String, Vec<String>>::new();

                if let Some(x) = o.pointer("/fields") {
                    if x.is_object() {
                        if let Some(obj) = x.as_object() {
                            for (key, value) in obj.iter() {
                                let arr: Vec<String> = match value.as_str() {
                                    Some(string) => {
                                        string.split(',').map(|s| s.to_string()).collect()
                                    }
                                    None => Vec::<String>::new(),
                                };
                                fields.insert(key.to_string(), arr);

                            }
                        }
                    } else {
                        error!("Query::from_params : No fields found in {:?}", x);
                    }
                }

                let sort = match o.pointer("/sort") {
                    None => None,
                    Some(sort) => {
                        match sort.as_str() {
                            None => None,
                            Some(sort_str) => {
                                let arr: Vec<String> =
                                    sort_str.split(',').map(|s| s.to_string()).collect();
                                Some(arr)
                            }
                        }
                    }
                };

                let mut filter = match o.pointer("/filter") {
                    None => None,
                    Some(x) => {
                        if x.is_object() {
                            let mut tmp_filter = HashMap::<String, Vec<String>>::new();
                            if let Some(obj) = x.as_object() {
                                for (key, value) in obj.iter() {
                                    let arr: Vec<String> = match value.as_str() {
                                        Some(string) => {
                                            string.split(',').map(|s| s.to_string()).collect()
                                        }
                                        None => Vec::<String>::new(),
                                    };
                                    tmp_filter.insert(key.to_string(), arr);
                                }
                            }
                            Some(tmp_filter)
                        } else {
                            error!("Query::from_params : No filter found in {:?}", x);
                            None
                        }
                    }
                };

                let page = PageParams {
                    number: match o.pointer("/page/number") {
                        None => {
                            warn!(
                                "Query::from_params : No page/number found in {:?}, setting \
                                   default 0",
                                o
                            );
                            0
                        }
                        Some(num) => {
                            if num.is_string() {
                                match num.as_str().map(str::parse::<i64>) {
                                    Some(y) => y.unwrap_or(0),
                                    None => {
                                        warn!(
                                            "Query::from_params : page/number found in {:?}, \
                                               not able not able to parse it - setting default 0",
                                            o
                                        );
                                        0
                                    }
                                }
                            } else {
                                warn!(
                                    "Query::from_params : page/number found in {:?}, but it is \
                                       not an expected type - setting default 0",
                                    o
                                );
                                0
                            }
                        }
                    },
                    size: match o.pointer("/page/size") {
                        None => {
                            warn!(
                                "Query::from_params : No page/size found in {:?}, setting \
                                   default 0",
                                o
                            );
                            0
                        }
                        Some(num) => {
                            if num.is_string() {
                                match num.as_str().map(str::parse::<i64>) {
                                    Some(y) => y.unwrap_or(0),
                                    None => {
                                        warn!(
                                            "Query::from_params : page/size found in {:?}, \
                                               not able not able to parse it - setting default 0",
                                            o
                                        );
                                        0
                                    }
                                }
                            } else {
                                warn!(
                                    "Query::from_params : page/size found in {:?}, but it is \
                                       not an expected type - setting default 0",
                                    o
                                );
                                0
                            }
                        }
                    },
                };

                Query {
                    _type: "none".into(),
                    include,
                    fields: Some(fields),
                    page: Some(page),
                    sort: sort,
                    filter: filter,
                }
            }
            Err(err) => {
                error!("Query::from_params : Can't parse : {:?}", err);
                Query {
                    _type: "none".into(),
                    ..Default::default()
                }
            }
        }
    }

    ///
    /// Builds a query parameter string from a Query
    ///
    /// ```
    /// use jsonapi::query::{Query, PageParams};
    /// let query = Query {
    ///   _type: "post".into(),
    ///   include: Some(vec!["author".into()]),
    ///   fields: None,
    ///   page: Some(PageParams {
    ///     size: 5,
    ///     number: 10,
    ///   }),
    ///   sort: None,
    ///   filter: None,
    /// };
    ///
    /// let query_string = query.to_params();
    /// assert_eq!(query_string, "include=author&page[size]=5&page[number]=10");
    ///
    /// ```
    pub fn to_params(&self) -> String {
        let mut params = Vec::<String>::new();

        if let Some(ref include) = self.include {
            params.push(format!("include={}", include.join(",")));
        }

        // Examples from json-api.org,
        // fields[articles]=title,body,author&fields[people]=name
        // fields[articles]=title,body&fields[people]=name

        if let Some(ref fields) = self.fields {
            for (name, val) in fields.iter() {
                params.push(format!("fields[{}]={}", name, val.join(",")));
            }
        }

        if let Some(ref sort) = self.sort {
            params.push(format!("sort={}", sort.join(",")))
        }

        if let Some(ref filter) = self.filter {
            for (name, val) in filter.iter() {
                params.push(format!("filter[{}]={}", name, val.join(",")));
            }
        }

        if let Some(ref page) = self.page {
            params.push(page.to_params());
        }

        params.join("&")
    }
}

impl PageParams {
    pub fn to_params(&self) -> String {
        format!("page[size]={}&page[number]={}", self.size, self.number)
    }
}
<commit_msg>:sparkles: Derive Clone for Query<commit_after>use queryst::parse;
use std::collections::HashMap;

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct PageParams {
    pub size: i64,
    pub number: i64,
}

/// JSON-API Query parameters
#[derive(Clone, Debug, PartialEq, Default)]
pub struct Query {
    pub _type: String,
    pub include: Option<Vec<String>>,
    pub fields: Option<HashMap<String, Vec<String>>>,
    pub page: Option<PageParams>,
    pub sort: Option<Vec<String>>,
    pub filter: Option<HashMap<String, Vec<String>>>
}

/// JSON-API Query parameters
impl Query {
    ///
    /// Takes a query parameter string and returns a Query
    ///
    /// ```
    /// use jsonapi::query::Query;
    /// let query = Query::from_params("include=author&fields[articles]=title,\
    ///                                 body&fields[people]=name&page[number]=3&page[size]=1");
    /// match query.include {
    ///     None => assert!(false),
    ///     Some(include) => {
    ///         assert_eq!(include.len(), 1);
    ///         assert_eq!(include[0], "author");
    ///     }
    /// }
    ///
    /// ```
    pub fn from_params(params: &str) -> Self {

        match parse(params) {
            Ok(o) => {
                let include = match o.pointer("/include") {
                    None => None,
                    Some(inc) => {
                        match inc.as_str() {
                            None => None,
                            Some(include_str) => {
                                let arr: Vec<String> =
                                    include_str.split(',').map(|s| s.to_string()).collect();
                                Some(arr)
                            }
                        }
                    }
                };

                let mut fields = HashMap::<String, Vec<String>>::new();

                if let Some(x) = o.pointer("/fields") {
                    if x.is_object() {
                        if let Some(obj) = x.as_object() {
                            for (key, value) in obj.iter() {
                                let arr: Vec<String> = match value.as_str() {
                                    Some(string) => {
                                        string.split(',').map(|s| s.to_string()).collect()
                                    }
                                    None => Vec::<String>::new(),
                                };
                                fields.insert(key.to_string(), arr);

                            }
                        }
                    } else {
                        error!("Query::from_params : No fields found in {:?}", x);
                    }
                }

                let sort = match o.pointer("/sort") {
                    None => None,
                    Some(sort) => {
                        match sort.as_str() {
                            None => None,
                            Some(sort_str) => {
                                let arr: Vec<String> =
                                    sort_str.split(',').map(|s| s.to_string()).collect();
                                Some(arr)
                            }
                        }
                    }
                };

                let mut filter = match o.pointer("/filter") {
                    None => None,
                    Some(x) => {
                        if x.is_object() {
                            let mut tmp_filter = HashMap::<String, Vec<String>>::new();
                            if let Some(obj) = x.as_object() {
                                for (key, value) in obj.iter() {
                                    let arr: Vec<String> = match value.as_str() {
                                        Some(string) => {
                                            string.split(',').map(|s| s.to_string()).collect()
                                        }
                                        None => Vec::<String>::new(),
                                    };
                                    tmp_filter.insert(key.to_string(), arr);
                                }
                            }
                            Some(tmp_filter)
                        } else {
                            error!("Query::from_params : No filter found in {:?}", x);
                            None
                        }
                    }
                };

                let page = PageParams {
                    number: match o.pointer("/page/number") {
                        None => {
                            warn!(
                                "Query::from_params : No page/number found in {:?}, setting \
                                   default 0",
                                o
                            );
                            0
                        }
                        Some(num) => {
                            if num.is_string() {
                                match num.as_str().map(str::parse::<i64>) {
                                    Some(y) => y.unwrap_or(0),
                                    None => {
                                        warn!(
                                            "Query::from_params : page/number found in {:?}, \
                                               not able not able to parse it - setting default 0",
                                            o
                                        );
                                        0
                                    }
                                }
                            } else {
                                warn!(
                                    "Query::from_params : page/number found in {:?}, but it is \
                                       not an expected type - setting default 0",
                                    o
                                );
                                0
                            }
                        }
                    },
                    size: match o.pointer("/page/size") {
                        None => {
                            warn!(
                                "Query::from_params : No page/size found in {:?}, setting \
                                   default 0",
                                o
                            );
                            0
                        }
                        Some(num) => {
                            if num.is_string() {
                                match num.as_str().map(str::parse::<i64>) {
                                    Some(y) => y.unwrap_or(0),
                                    None => {
                                        warn!(
                                            "Query::from_params : page/size found in {:?}, \
                                               not able not able to parse it - setting default 0",
                                            o
                                        );
                                        0
                                    }
                                }
                            } else {
                                warn!(
                                    "Query::from_params : page/size found in {:?}, but it is \
                                       not an expected type - setting default 0",
                                    o
                                );
                                0
                            }
                        }
                    },
                };

                Query {
                    _type: "none".into(),
                    include,
                    fields: Some(fields),
                    page: Some(page),
                    sort: sort,
                    filter: filter,
                }
            }
            Err(err) => {
                error!("Query::from_params : Can't parse : {:?}", err);
                Query {
                    _type: "none".into(),
                    ..Default::default()
                }
            }
        }
    }

    ///
    /// Builds a query parameter string from a Query
    ///
    /// ```
    /// use jsonapi::query::{Query, PageParams};
    /// let query = Query {
    ///   _type: "post".into(),
    ///   include: Some(vec!["author".into()]),
    ///   fields: None,
    ///   page: Some(PageParams {
    ///     size: 5,
    ///     number: 10,
    ///   }),
    ///   sort: None,
    ///   filter: None,
    /// };
    ///
    /// let query_string = query.to_params();
    /// assert_eq!(query_string, "include=author&page[size]=5&page[number]=10");
    ///
    /// ```
    pub fn to_params(&self) -> String {
        let mut params = Vec::<String>::new();

        if let Some(ref include) = self.include {
            params.push(format!("include={}", include.join(",")));
        }

        // Examples from json-api.org,
        // fields[articles]=title,body,author&fields[people]=name
        // fields[articles]=title,body&fields[people]=name

        if let Some(ref fields) = self.fields {
            for (name, val) in fields.iter() {
                params.push(format!("fields[{}]={}", name, val.join(",")));
            }
        }

        if let Some(ref sort) = self.sort {
            params.push(format!("sort={}", sort.join(",")))
        }

        if let Some(ref filter) = self.filter {
            for (name, val) in filter.iter() {
                params.push(format!("filter[{}]={}", name, val.join(",")));
            }
        }

        if let Some(ref page) = self.page {
            params.push(page.to_params());
        }

        params.join("&")
    }
}

impl PageParams {
    pub fn to_params(&self) -> String {
        format!("page[size]={}&page[number]={}", self.size, self.number)
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;

#[allow(raw_pointer_derive)]
#[derive(Clone, Copy)]
struct Rawlink<T> {
    p: *mut T
}

impl<T> Rawlink<T> {
    fn none() -> Rawlink<T> {
        Rawlink { p: ptr::null_mut() }
    }

    fn some(n: &mut T) -> Rawlink<T> {
        Rawlink { p: n }
    }

    fn take(&mut self) -> Rawlink<T> {
        mem::replace(self, Rawlink::none())
    }
}

struct Node<T> {
    val: T,
    next: Option<Box<Node<T>>>
}

impl<T> Node<T> {
    /// work around for moved value
    fn into_val_and_next(self) -> (T, Option<Box<Node<T>>>) {
        (self.val, self.next)
    }

    fn len(&self) -> usize {
        self.next.as_ref().map_or(1, |n| 1 + n.len())
    }
}

impl<T: Clone> Clone for Node<T> {
    fn clone(&self) -> Self {
        Node {
            val: self.val.clone(),
            next: self.next.clone()
        }
    }
}

pub struct Queue<T> {
    first: Option<Box<Node<T>>>,
    last: Rawlink<Node<T>>
}

impl<T: Clone> Clone for Queue<T> {
    fn clone(&self) -> Self {
        let mut first = self.first.clone();
        let last = {
            let mut p = first.as_mut();
            while p.as_ref().map_or(false, |n| n.next.is_some()) {
                p = p.unwrap().next.as_mut();
            }
            p.map_or_else(Rawlink::none, |n| Rawlink::some(&mut **n))
        };
        Queue {
            first: first,
            last: last
        }
    }
}

impl<T> Queue<T> {
    pub fn new() -> Queue<T> {
        Queue { first: None, last: Rawlink::none() }
    }

    pub fn is_empty(&self) -> bool {
        self.first.is_none()
    }

    pub fn enqueue(&mut self, val: T) {
        let ref old_last = self.last.take();
        let mut last = Box::new(Node {
            val: val,
            next: None
        });
        self.last = Rawlink::some(&mut last);
        if self.is_empty() {
            self.first = Some(last)
        } else {
            unsafe {
                (*old_last.p).next = Some(last)
            }
        }
    }

    pub fn dequeue(&mut self) -> Option<T> {
        if self.first.is_none() {
            return None;
        }
        let old_first = self.first.take();
        let (val, first) = old_first.unwrap().into_val_and_next();
        self.first = first;
        if self.first.is_none() {
            self.last = Rawlink::none()
        }
        Some(val)
    }

    pub fn peek(&self) -> Option<&T> {
        self.first.as_ref().map(|n| &(*n).val)
    }

    pub fn peek_mut(&mut self) -> Option<&mut T> {
        self.first.as_mut().map(|n| &mut (*n).val)
    }

    pub fn len(&self) -> usize {
        self.first.as_ref().map_or(0, |n| n.len())
    }
}

pub struct IntoIter<T> {
    queue: Queue<T>
}

impl<T> Iterator for IntoIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        self.queue.dequeue()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let length = self.queue.len();
        (length, Some(length))
    }
}

impl<T> IntoIterator for Queue<T> {
    type Item = T;
    type IntoIter = IntoIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        IntoIter { queue: self }
    }
}

pub struct Iter<'a, T> where T: 'a {
    node: Option<&'a Box<Node<T>>>
}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<&'a T> {
        let ret = self.node.map(|n| &n.val);
        self.node = self.node.map_or(None, |n| n.next.as_ref());
        ret
    }

    // Bad
    fn size_hint(&self) -> (usize, Option<usize>) {
        let mut sz = 0;
        let mut p = self.node;
        while p.is_some() {
            p = p.map_or(None, |n| n.next.as_ref());
            sz += 1;
        }
        (sz, Some(sz))
    }
}

impl<'a, T> ExactSizeIterator for Iter<'a, T> {
    fn len(&self) -> usize {
        self.size_hint().0
    }
}

impl<T> Queue<T> {
    pub fn iter<'a>(&'a self) -> Iter<'a, T> {
        Iter {
            node: self.first.as_ref()
        }
    }
}

#[test]
fn test_queue() {
    let mut queue = Queue::<&str>::new();
    assert!(queue.is_empty());
    assert_eq!(queue.len(), 0);

    assert_eq!(queue.peek(), None);

    queue.enqueue("welcome");
    queue.enqueue("to");
    queue.enqueue("china");
    assert!(!queue.is_empty());
    assert_eq!(queue.len(), 3);

    assert_eq!(queue.peek(), Some(&"welcome"));
    queue.peek_mut().map(|val| *val = "go");
    assert_eq!(queue.peek(), Some(&"go"));
}

#[test]
fn test_queue_clone() {
    let mut queue1 = Queue::<&str>::new();
    queue1.enqueue("welcome");
    queue1.enqueue("to");
    queue1.enqueue("china");

    let mut queue2 = queue1.clone();
    queue2.dequeue();
    assert_eq!(queue1.peek(), Some(&"welcome"));
    assert_eq!(queue2.peek(), Some(&"to"));

    queue2.dequeue();
    queue2.dequeue();
    queue2.enqueue("beijing");

    assert_eq!(queue1.peek(), Some(&"welcome"));
    assert_eq!(queue2.peek(), Some(&"beijing"));

}

#[test]
fn test_queue_into_iter() {
    let mut queue = Queue::<&str>::new();
    queue.enqueue("welcome");
    queue.enqueue("to");
    queue.enqueue("china");

    let result = vec!["welcome", "to", "china"];
    for i in queue {
        assert!(result.contains(&i));
    }
}

#[test]
fn test_queue_iter() {
    let mut queue = Queue::<&str>::new();
    queue.enqueue("welcome");
    queue.enqueue("to");
    queue.enqueue("china");

    let mut rit = vec!["welcome", "to", "china"].into_iter();
    for i in queue.iter() {
        assert_eq!(i, &rit.next().unwrap())
    }

}
<commit_msg>remove unused code<commit_after>use std::mem;
use std::ptr;

struct Rawlink<T> {
    p: *mut T
}

impl<T> Rawlink<T> {
    fn none() -> Rawlink<T> {
        Rawlink { p: ptr::null_mut() }
    }

    fn some(n: &mut T) -> Rawlink<T> {
        Rawlink { p: n }
    }

    fn take(&mut self) -> Rawlink<T> {
        mem::replace(self, Rawlink::none())
    }
}

struct Node<T> {
    val: T,
    next: Option<Box<Node<T>>>
}

impl<T> Node<T> {
    /// work around for moved value
    fn into_val_and_next(self) -> (T, Option<Box<Node<T>>>) {
        (self.val, self.next)
    }

    fn len(&self) -> usize {
        self.next.as_ref().map_or(1, |n| 1 + n.len())
    }
}

impl<T: Clone> Clone for Node<T> {
    fn clone(&self) -> Self {
        Node {
            val: self.val.clone(),
            next: self.next.clone()
        }
    }
}

pub struct Queue<T> {
    first: Option<Box<Node<T>>>,
    last: Rawlink<Node<T>>
}

impl<T: Clone> Clone for Queue<T> {
    fn clone(&self) -> Self {
        let mut first = self.first.clone();
        let last = {
            let mut p = first.as_mut();
            while p.as_ref().map_or(false, |n| n.next.is_some()) {
                p = p.unwrap().next.as_mut();
            }
            p.map_or_else(Rawlink::none, |n| Rawlink::some(&mut **n))
        };
        Queue {
            first: first,
            last: last
        }
    }
}

impl<T> Queue<T> {
    pub fn new() -> Queue<T> {
        Queue { first: None, last: Rawlink::none() }
    }

    pub fn is_empty(&self) -> bool {
        self.first.is_none()
    }

    pub fn enqueue(&mut self, val: T) {
        let ref old_last = self.last.take();
        let mut last = Box::new(Node {
            val: val,
            next: None
        });
        self.last = Rawlink::some(&mut last);
        if self.is_empty() {
            self.first = Some(last)
        } else {
            unsafe {
                (*old_last.p).next = Some(last)
            }
        }
    }

    pub fn dequeue(&mut self) -> Option<T> {
        if self.first.is_none() {
            return None;
        }
        let old_first = self.first.take();
        let (val, first) = old_first.unwrap().into_val_and_next();
        self.first = first;
        if self.first.is_none() {
            self.last = Rawlink::none()
        }
        Some(val)
    }

    pub fn peek(&self) -> Option<&T> {
        self.first.as_ref().map(|n| &(*n).val)
    }

    pub fn peek_mut(&mut self) -> Option<&mut T> {
        self.first.as_mut().map(|n| &mut (*n).val)
    }

    pub fn len(&self) -> usize {
        self.first.as_ref().map_or(0, |n| n.len())
    }
}

pub struct IntoIter<T> {
    queue: Queue<T>
}

impl<T> Iterator for IntoIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        self.queue.dequeue()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let length = self.queue.len();
        (length, Some(length))
    }
}

impl<T> IntoIterator for Queue<T> {
    type Item = T;
    type IntoIter = IntoIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        IntoIter { queue: self }
    }
}

pub struct Iter<'a, T> where T: 'a {
    node: Option<&'a Box<Node<T>>>
}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<&'a T> {
        let ret = self.node.map(|n| &n.val);
        self.node = self.node.map_or(None, |n| n.next.as_ref());
        ret
    }

    // Bad
    fn size_hint(&self) -> (usize, Option<usize>) {
        let mut sz = 0;
        let mut p = self.node;
        while p.is_some() {
            p = p.map_or(None, |n| n.next.as_ref());
            sz += 1;
        }
        (sz, Some(sz))
    }
}

impl<'a, T> ExactSizeIterator for Iter<'a, T> {
    fn len(&self) -> usize {
        self.size_hint().0
    }
}

impl<T> Queue<T> {
    pub fn iter<'a>(&'a self) -> Iter<'a, T> {
        Iter {
            node: self.first.as_ref()
        }
    }
}

#[test]
fn test_queue() {
    let mut queue = Queue::<&str>::new();
    assert!(queue.is_empty());
    assert_eq!(queue.len(), 0);

    assert_eq!(queue.peek(), None);

    queue.enqueue("welcome");
    queue.enqueue("to");
    queue.enqueue("china");
    assert!(!queue.is_empty());
    assert_eq!(queue.len(), 3);

    assert_eq!(queue.peek(), Some(&"welcome"));
    queue.peek_mut().map(|val| *val = "go");
    assert_eq!(queue.peek(), Some(&"go"));
}

#[test]
fn test_queue_clone() {
    let mut queue1 = Queue::<&str>::new();
    queue1.enqueue("welcome");
    queue1.enqueue("to");
    queue1.enqueue("china");

    let mut queue2 = queue1.clone();
    queue2.dequeue();
    assert_eq!(queue1.peek(), Some(&"welcome"));
    assert_eq!(queue2.peek(), Some(&"to"));

    queue2.dequeue();
    queue2.dequeue();
    queue2.enqueue("beijing");

    assert_eq!(queue1.peek(), Some(&"welcome"));
    assert_eq!(queue2.peek(), Some(&"beijing"));

}

#[test]
fn test_queue_into_iter() {
    let mut queue = Queue::<&str>::new();
    queue.enqueue("welcome");
    queue.enqueue("to");
    queue.enqueue("china");

    let result = vec!["welcome", "to", "china"];
    for i in queue {
        assert!(result.contains(&i));
    }
}

#[test]
fn test_queue_iter() {
    let mut queue = Queue::<&str>::new();
    queue.enqueue("welcome");
    queue.enqueue("to");
    queue.enqueue("china");

    let mut rit = vec!["welcome", "to", "china"].into_iter();
    for i in queue.iter() {
        assert_eq!(i, &rit.next().unwrap())
    }

}
<|endoftext|>


<commit_before>use hyper::server::Request;
use std::sync::Mutex;
extern crate redis;
extern crate byteorder;
extern crate hyper;
use common::*;
use self::byteorder::{BigEndian, WriteBytesExt};
use std::net::IpAddr;
extern crate time;
use std::error::Error;
use std::str::FromStr;

enum IPVersion {
    V4,
    V6
}

enum Event {
    Unspecified,
    Started,
    Stopped,
    Completed,
}

pub fn announce(req: &Request, redis_connection: &Mutex<redis::Connection>,
    announce_interval: u32,
    drop_threshold: u32,
    completion_website: &Option<String>) -> Result<Vec<u8>, String>
{
    // Get which ip version we are serving
    let ip_version = match req.remote_addr.ip() {
        IpAddr::V4(_) => IPVersion::V4,
        IpAddr::V6(_) => IPVersion::V6,
    };

    let query_hashmap = query_hashmap(&req.uri);

    // Check we have everything we need
    let info_hash = try!(query_hashmap.get("info_hash")
        .ok_or_else(|| "No info_hash specified".to_owned())
        .and_then(|i| parse_info_hash(i)));
    debug!("    infohash={}", info_hash);
    /*let peer_id = try!(query_hashmap.get("peer_id")
        .ok_or_else(|| "No peer_id specified".to_owned())
        .and_then(|i| parse_peer_id(i)));*/
    let port = try!(query_hashmap.get("port")
        .ok_or_else(|| "No port specified".to_owned())
        .and_then(|i| i.parse::<u16>().map_err(|_| "Invalid port specified".to_owned())));
    let left = try!(query_hashmap.get("left")
        .ok_or_else(|| "No left specified".to_owned())
        .and_then(|i| i.parse::<u64>().map_err(|_| "Invalid left specified".to_owned())));
    let compact = try!(query_hashmap.get("compact")
        .ok_or_else(|| "No compact specified".to_owned())
        .and_then(|i| i.parse::<u64>().map_err(|_| "Invalid compact specified".to_owned())));
    if compact != 1 {
        return Err("This tracker only supports compact responses".to_owned());
    }
    let numwant = try!(query_hashmap.get("numwant")
        .unwrap_or(&"50")
        .parse::<u64>().map_err(|_| "Invalid numwant specified".to_owned()));
    let event;
    match query_hashmap.get("event") {
        Some(i) => {
            if *i == "started" {
                event = Event::Started;
            }
            else if *i == "stopped" {
                event = Event::Stopped;
            }
            else if *i == "completed" {
                event = Event::Completed;
            }
            else {
                return Err("Event parameter not understood".to_owned());
            }
        }
        None => { event = Event::Unspecified; },
    }

    // Do completion hook if it exists
    if let Event::Completed = event {
        if let Some(ref completion_website_baseurl) = *completion_website {
            let hyper_client = hyper::Client::new();
            match hyper_client.get(
                    &format!("{}tracker/{}/snatched", completion_website_baseurl, info_hash))
                .header(hyper::header::Connection::close()).send() {
                Ok(_) => {},
                Err(e) => {
                    error!("Error performing completion hook ({})", e.to_string());
                }
            }
        }
    }

    // Get ip
    let ip: Option<IpAddr>;
    match ip_version {
        IPVersion::V4 => {
            ip = query_hashmap.get("ip").
                and_then(|i| IpAddr::from_str(i).ok()).
                // only acccept it if it's an ipv4 address
                and_then(|i| if let IpAddr::V4(_) = i { Some(i) } else { None });
        }
        IPVersion::V6 => {
            ip = query_hashmap.get("ipv6").
                or(query_hashmap.get("ip")).
                and_then(|i| IpAddr::from_str(i).ok()).
                // only acccept it if it's an ipv6 address
                and_then(|i| if let IpAddr::V6(_) = i { Some(i) } else { None });
        }
    }
    // Fallback on connection ip if it was invalid or not specified
    let ip = ip.unwrap_or(req.remote_addr.ip());
    debug!("    ip={}, port={}", ip.to_string(), port);

    // Generate compact peer entry
    let peer = generate_peer(ip, port);
    let size_of_peer = &peer.len();
    assert_eq!(*size_of_peer, if let IPVersion::V6 = ip_version {18} else {6});

    // Get ready for redis queries
    let key_base = format!("torrent:{}", info_hash);
    let key_seeds = format!("{}:seeds{}", key_base, if let IPVersion::V6 = ip_version {"6"} else {""});
    let key_peers = format!("{}:peers{}", key_base, if let IPVersion::V6 = ip_version {"6"} else {""});
    let time_now = time::get_time().sec*1000;
    let time_drop = time_now - (drop_threshold as i64)*1000;
    let mut pipe = redis::pipe();

    // Prune out old entries
    pipe.cmd("ZREMRANGEBYSCORE").arg(&*key_seeds).arg(0).arg(time_drop).ignore();
    pipe.cmd("ZREMRANGEBYSCORE").arg(&*key_peers).arg(0).arg(time_drop).ignore();

    // Get total count of peers/seeds
    pipe.cmd("ZCARD").arg(&*key_seeds);
    pipe.cmd("ZCARD").arg(&*key_peers);

    // Get peers and seeds
    pipe.cmd("ZRANGE").arg(&*key_seeds).arg(0).arg(numwant);
    pipe.cmd("ZRANGE").arg(&*key_peers).arg(0).arg(numwant);

    // Add
    if left == 0 {
        pipe.cmd("ZADD").arg(&*key_seeds).arg(time_now).arg(peer).ignore();
    }
    else {
        pipe.cmd("ZADD").arg(&*key_peers).arg(time_now).arg(peer).ignore();
    }

    // Unlock mutex and go!
    let results: (u32, u32, Vec<Vec<u8>>, Vec<Vec<u8>>);
    {
        let r = redis_connection.lock().unwrap();
        results = try!(pipe.query(&(*r))
            .map_err(|e| format!("Redis error: {}", e.description())));
    }

    let (total_seeds, total_peers, seeds, peers) = results;
    debug!("    seeds={}, peers={}", total_seeds, total_peers);

    // Begin building output
    let mut response: Vec<u8> = Vec::new();
    response.extend(format!("d8:completei{}e10:incompletei{}e8:intervali{}e",
        total_seeds, total_peers, announce_interval).bytes());
    match ip_version {
        IPVersion::V4 => response.extend(b"5:peers"),
        IPVersion::V6 => response.extend(b"6:peers6"),
    }

    // dont give seeds to seeds
    if left == 0 {
        response.extend(format!("{}:", size_of_peer*peers.len()).bytes());
        for i in peers {
            response.extend(i);
        }
    }
    else {
        response.extend(format!("{}:", size_of_peer*seeds.len() + size_of_peer*peers.len()).bytes());
        for i in seeds {
            response.extend(i);
        }
        for i in peers {
            response.extend(i);
        }
    }
    response.extend(b"e");

    return Ok(response);
}

fn generate_peer(ip: IpAddr, port: u16) -> Vec<u8> {
    let mut retval: Vec<u8>;
    match ip {
        IpAddr::V4(ip_v4) => {
            retval = Vec::with_capacity(6);
            retval.extend(ip_v4.octets().iter());
        },
        IpAddr::V6(ip_v6) => {
            retval = Vec::with_capacity(18);
            //retval.extend(ip_v6.octets().iter()); not yet in stable
            for i in ip_v6.segments().iter() {
                retval.write_u16::<BigEndian>(*i).unwrap();
            }
        }
    }
    retval.write_u16::<BigEndian>(port).unwrap();
    return retval;
}

#[test]
fn generate_peer_test() {
    assert_eq!(generate_peer(IpAddr::from_str("127.0.0.1").unwrap(), 0x3039), &[127, 0, 0, 1, 0x30, 0x39]);
    assert_eq!(generate_peer(IpAddr::from_str("abcd:ef01:2345:6789:abcd:ef01:2345:6789").unwrap(), 0x1234), &[0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0x12, 0x34]);
}
<commit_msg>announce: Only announce if event!=stopped<commit_after>use hyper::server::Request;
use std::sync::Mutex;
extern crate redis;
extern crate byteorder;
extern crate hyper;
use common::*;
use self::byteorder::{BigEndian, WriteBytesExt};
use std::net::IpAddr;
extern crate time;
use std::error::Error;
use std::str::FromStr;

enum IPVersion {
    V4,
    V6
}

enum Event {
    Unspecified,
    Started,
    Stopped,
    Completed,
}

pub fn announce(req: &Request, redis_connection: &Mutex<redis::Connection>,
    announce_interval: u32,
    drop_threshold: u32,
    completion_website: &Option<String>) -> Result<Vec<u8>, String>
{
    // Get which ip version we are serving
    let ip_version = match req.remote_addr.ip() {
        IpAddr::V4(_) => IPVersion::V4,
        IpAddr::V6(_) => IPVersion::V6,
    };

    let query_hashmap = query_hashmap(&req.uri);

    // Check we have everything we need
    let info_hash = try!(query_hashmap.get("info_hash")
        .ok_or_else(|| "No info_hash specified".to_owned())
        .and_then(|i| parse_info_hash(i)));
    debug!("    infohash={}", info_hash);
    /*let peer_id = try!(query_hashmap.get("peer_id")
        .ok_or_else(|| "No peer_id specified".to_owned())
        .and_then(|i| parse_peer_id(i)));*/
    let port = try!(query_hashmap.get("port")
        .ok_or_else(|| "No port specified".to_owned())
        .and_then(|i| i.parse::<u16>().map_err(|_| "Invalid port specified".to_owned())));
    let left = try!(query_hashmap.get("left")
        .ok_or_else(|| "No left specified".to_owned())
        .and_then(|i| i.parse::<u64>().map_err(|_| "Invalid left specified".to_owned())));
    let compact = try!(query_hashmap.get("compact")
        .ok_or_else(|| "No compact specified".to_owned())
        .and_then(|i| i.parse::<u64>().map_err(|_| "Invalid compact specified".to_owned())));
    if compact != 1 {
        return Err("This tracker only supports compact responses".to_owned());
    }
    let numwant = try!(query_hashmap.get("numwant")
        .unwrap_or(&"50")
        .parse::<u64>().map_err(|_| "Invalid numwant specified".to_owned()));
    let event;
    match query_hashmap.get("event") {
        Some(i) => {
            if *i == "started" {
                event = Event::Started;
            }
            else if *i == "stopped" {
                event = Event::Stopped;
            }
            else if *i == "completed" {
                event = Event::Completed;
            }
            else {
                return Err("Event parameter not understood".to_owned());
            }
        }
        None => { event = Event::Unspecified; },
    }

    // Do completion hook if it exists
    if let Event::Completed = event {
        if let Some(ref completion_website_baseurl) = *completion_website {
            let hyper_client = hyper::Client::new();
            match hyper_client.get(
                    &format!("{}tracker/{}/snatched", completion_website_baseurl, info_hash))
                .header(hyper::header::Connection::close()).send() {
                Ok(_) => {},
                Err(e) => {
                    error!("Error performing completion hook ({})", e.to_string());
                }
            }
        }
    }

    // Get ip
    let ip: Option<IpAddr>;
    match ip_version {
        IPVersion::V4 => {
            ip = query_hashmap.get("ip").
                and_then(|i| IpAddr::from_str(i).ok()).
                // only acccept it if it's an ipv4 address
                and_then(|i| if let IpAddr::V4(_) = i { Some(i) } else { None });
        }
        IPVersion::V6 => {
            ip = query_hashmap.get("ipv6").
                or(query_hashmap.get("ip")).
                and_then(|i| IpAddr::from_str(i).ok()).
                // only acccept it if it's an ipv6 address
                and_then(|i| if let IpAddr::V6(_) = i { Some(i) } else { None });
        }
    }
    // Fallback on connection ip if it was invalid or not specified
    let ip = ip.unwrap_or(req.remote_addr.ip());
    debug!("    ip={}, port={}", ip.to_string(), port);

    // Generate compact peer entry
    let peer = generate_peer(ip, port);
    let size_of_peer = &peer.len();
    assert_eq!(*size_of_peer, if let IPVersion::V6 = ip_version {18} else {6});

    // Get ready for redis queries
    let key_base = format!("torrent:{}", info_hash);
    let key_seeds = format!("{}:seeds{}", key_base, if let IPVersion::V6 = ip_version {"6"} else {""});
    let key_peers = format!("{}:peers{}", key_base, if let IPVersion::V6 = ip_version {"6"} else {""});
    let time_now = time::get_time().sec*1000;
    let time_drop = time_now - (drop_threshold as i64)*1000;
    let mut pipe = redis::pipe();

    // Prune out old entries
    pipe.cmd("ZREMRANGEBYSCORE").arg(&*key_seeds).arg(0).arg(time_drop).ignore();
    pipe.cmd("ZREMRANGEBYSCORE").arg(&*key_peers).arg(0).arg(time_drop).ignore();

    // Get total count of peers/seeds
    pipe.cmd("ZCARD").arg(&*key_seeds);
    pipe.cmd("ZCARD").arg(&*key_peers);

    // Get peers and seeds
    pipe.cmd("ZRANGE").arg(&*key_seeds).arg(0).arg(numwant);
    pipe.cmd("ZRANGE").arg(&*key_peers).arg(0).arg(numwant);

    // Add (only if not stopped)
    match event {
        Event::Stopped => {},
        _ => {
            if left == 0 {
                pipe.cmd("ZADD").arg(&*key_seeds).arg(time_now).arg(peer).ignore();
            }
            else {
                pipe.cmd("ZADD").arg(&*key_peers).arg(time_now).arg(peer).ignore();
            }
        },
    }

    // Unlock mutex and go!
    let results: (u32, u32, Vec<Vec<u8>>, Vec<Vec<u8>>);
    {
        let r = redis_connection.lock().unwrap();
        results = try!(pipe.query(&(*r))
            .map_err(|e| format!("Redis error: {}", e.description())));
    }

    let (total_seeds, total_peers, seeds, peers) = results;
    debug!("    seeds={}, peers={}", total_seeds, total_peers);

    // Begin building output
    let mut response: Vec<u8> = Vec::new();
    response.extend(format!("d8:completei{}e10:incompletei{}e8:intervali{}e",
        total_seeds, total_peers, announce_interval).bytes());
    match ip_version {
        IPVersion::V4 => response.extend(b"5:peers"),
        IPVersion::V6 => response.extend(b"6:peers6"),
    }

    // dont give seeds to seeds
    if left == 0 {
        response.extend(format!("{}:", size_of_peer*peers.len()).bytes());
        for i in peers {
            response.extend(i);
        }
    }
    else {
        response.extend(format!("{}:", size_of_peer*seeds.len() + size_of_peer*peers.len()).bytes());
        for i in seeds {
            response.extend(i);
        }
        for i in peers {
            response.extend(i);
        }
    }
    response.extend(b"e");

    return Ok(response);
}

fn generate_peer(ip: IpAddr, port: u16) -> Vec<u8> {
    let mut retval: Vec<u8>;
    match ip {
        IpAddr::V4(ip_v4) => {
            retval = Vec::with_capacity(6);
            retval.extend(ip_v4.octets().iter());
        },
        IpAddr::V6(ip_v6) => {
            retval = Vec::with_capacity(18);
            //retval.extend(ip_v6.octets().iter()); not yet in stable
            for i in ip_v6.segments().iter() {
                retval.write_u16::<BigEndian>(*i).unwrap();
            }
        }
    }
    retval.write_u16::<BigEndian>(port).unwrap();
    return retval;
}

#[test]
fn generate_peer_test() {
    assert_eq!(generate_peer(IpAddr::from_str("127.0.0.1").unwrap(), 0x3039), &[127, 0, 0, 1, 0x30, 0x39]);
    assert_eq!(generate_peer(IpAddr::from_str("abcd:ef01:2345:6789:abcd:ef01:2345:6789").unwrap(), 0x1234), &[0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0x12, 0x34]);
}
<|endoftext|>


<commit_before>use crate::cli::Command;
use mprovision as mp;
use std::env;
use std::io::{self, Write};
use std::path::Path;
use std::path::PathBuf;
use std::time::{Duration, SystemTime};

mod cli;

type Result = std::result::Result<(), cli::Error>;

fn main() {
    if let Err(e) = cli::parse(env::args()).and_then(run) {
        e.exit();
    }
}

fn run(command: cli::Command) -> Result {
    match command {
        Command::List(cli::ListParams {
            text,
            expire_in_days,
            directory,
        }) => list(&text, expire_in_days, directory),
        Command::ShowUuid(cli::ShowUuidParams { uuid, directory }) => show_uuid(&uuid, directory),
        Command::ShowFile(cli::ShowFileParams { file }) => show_file(&file),
        Command::Remove(cli::RemoveParams { ids, directory }) => remove(&ids, directory),
        Command::Clean(cli::CleanParams { directory }) => clean(directory),
    }
}

fn list(text: &Option<String>, expires_in_days: Option<u64>, directory: Option<PathBuf>) -> Result {
    let dir = mp::with_directory(directory)?;
    let entries = mp::entries(&dir).map(std::iter::Iterator::collect)?;
    let date =
        expires_in_days.map(|days| SystemTime::now() + Duration::from_secs(days * 24 * 60 * 60));
    let filter_string = text.as_ref();
    let mut profiles = mp::filter(entries, |profile| match (date, filter_string) {
        (Some(date), Some(string)) => {
            profile.info.expiration_date <= date && profile.info.contains(string)
        }
        (Some(date), _) => profile.info.expiration_date <= date,
        (_, Some(string)) => profile.info.contains(string),
        (_, _) => true,
    });
    profiles.sort_by(|a, b| a.info.creation_date.cmp(&b.info.creation_date));
    if profiles.is_empty() {
        Ok(())
    } else {
        let stdout = io::stdout();
        let mut stdout = stdout.lock();
        for profile in &profiles {
            writeln!(&mut stdout, "{}\n", profile.info.description())?;
        }
        Ok(())
    }
}

fn show_uuid(uuid: &str, directory: Option<PathBuf>) -> Result {
    let dir = mp::with_directory(directory)?;
    let profile = mp::find_by_uuid(&dir, &uuid)?;
    show_file(&profile.path)
}

fn show_file(path: &Path) -> Result {
    let xml = mp::show(&path)?;
    writeln!(io::stdout(), "{}", xml)?;
    Ok(())
}

fn remove(ids: &[String], directory: Option<PathBuf>) -> Result {
    let dir = mp::with_directory(directory)?;
    let profiles = mp::find_by_ids(&dir, &ids)?;
    remove_profiles(profiles)
}

fn clean(directory: Option<PathBuf>) -> Result {
    let date = SystemTime::now();
    let dir = mp::with_directory(directory)?;
    let entries = mp::entries(&dir).map(std::iter::Iterator::collect)?;
    let profiles = mp::filter(entries, |profile| profile.info.expiration_date <= date);
    remove_profiles(profiles)
}

fn remove_profiles(profiles: Vec<mp::Profile>) -> Result {
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    for profile in profiles {
        match mp::remove(&profile.path) {
            Ok(()) => writeln!(&mut stdout, "{}/n", profile.info.description())?,
            Err(err) => writeln!(io::stderr(), "{}", err)?,
        }
    }
    Ok(())
}
<commit_msg>Make sure to exit with error exit code when failed to remove<commit_after>use crate::cli::Command;
use mprovision as mp;
use std::env;
use std::io::{self, Write};
use std::path::Path;
use std::path::PathBuf;
use std::time::{Duration, SystemTime};

mod cli;

type Result = std::result::Result<(), cli::Error>;

fn main() {
    if let Err(e) = cli::parse(env::args()).and_then(run) {
        e.exit();
    }
}

fn run(command: cli::Command) -> Result {
    match command {
        Command::List(cli::ListParams {
            text,
            expire_in_days,
            directory,
        }) => list(&text, expire_in_days, directory),
        Command::ShowUuid(cli::ShowUuidParams { uuid, directory }) => show_uuid(&uuid, directory),
        Command::ShowFile(cli::ShowFileParams { file }) => show_file(&file),
        Command::Remove(cli::RemoveParams { ids, directory }) => remove(&ids, directory),
        Command::Clean(cli::CleanParams { directory }) => clean(directory),
    }
}

fn list(text: &Option<String>, expires_in_days: Option<u64>, directory: Option<PathBuf>) -> Result {
    let dir = mp::with_directory(directory)?;
    let entries = mp::entries(&dir).map(std::iter::Iterator::collect)?;
    let date =
        expires_in_days.map(|days| SystemTime::now() + Duration::from_secs(days * 24 * 60 * 60));
    let filter_string = text.as_ref();
    let mut profiles = mp::filter(entries, |profile| match (date, filter_string) {
        (Some(date), Some(string)) => {
            profile.info.expiration_date <= date && profile.info.contains(string)
        }
        (Some(date), _) => profile.info.expiration_date <= date,
        (_, Some(string)) => profile.info.contains(string),
        (_, _) => true,
    });
    profiles.sort_by(|a, b| a.info.creation_date.cmp(&b.info.creation_date));
    if profiles.is_empty() {
        Ok(())
    } else {
        let stdout = io::stdout();
        let mut stdout = stdout.lock();
        for profile in &profiles {
            writeln!(&mut stdout, "{}\n", profile.info.description())?;
        }
        Ok(())
    }
}

fn show_uuid(uuid: &str, directory: Option<PathBuf>) -> Result {
    let dir = mp::with_directory(directory)?;
    let profile = mp::find_by_uuid(&dir, &uuid)?;
    show_file(&profile.path)
}

fn show_file(path: &Path) -> Result {
    let xml = mp::show(&path)?;
    writeln!(io::stdout(), "{}", xml)?;
    Ok(())
}

fn remove(ids: &[String], directory: Option<PathBuf>) -> Result {
    let dir = mp::with_directory(directory)?;
    let profiles = mp::find_by_ids(&dir, &ids)?;
    remove_profiles(profiles)
}

fn clean(directory: Option<PathBuf>) -> Result {
    let date = SystemTime::now();
    let dir = mp::with_directory(directory)?;
    let entries = mp::entries(&dir).map(std::iter::Iterator::collect)?;
    let profiles = mp::filter(entries, |profile| profile.info.expiration_date <= date);
    remove_profiles(profiles)
}

fn remove_profiles(profiles: Vec<mp::Profile>) -> Result {
    let mut errors_exist = false;
    let stdout = io::stdout();
    let mut stdout = stdout.lock();
    for profile in profiles {
        match mp::remove(&profile.path) {
            Ok(()) => writeln!(&mut stdout, "{}/n", profile.info.description())?,
            Err(err) => {
                errors_exist = true;
                writeln!(io::stderr(), "{}", err)?
            }
        }
    }
    if errors_exist {
        // Don't need to show anything – all errors are already printed.
        Err(cli::Error::Custom(String::new()))
    } else {
        Ok(())
    }
}
<|endoftext|>


<commit_before>use super::ErrorCode;
use bindings::root::*;
use std::ptr;
use std::os::raw::c_void;
use std::ffi::CStr;

pub use bindings::root::spv::ExecutionModel;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct WorkgroupSize {
    pub x: u32,
    pub y: u32,
    pub z: u32,
}

#[derive(Debug, Clone)]
pub struct EntryPoint {
    pub name: String,
    pub execution_model: ExecutionModel,
    pub workgroup_size: WorkgroupSize,
}

#[derive(Debug, Clone)]
pub struct Module<'a> {
    ir: &'a [u32],
}

impl<'a> Module<'a> {
    pub fn new(ir: &[u32]) -> Module {
        Module { ir }
    }
}

pub struct ParsedModule {
    pub entry_points: Vec<EntryPoint>,
    pub(crate) ir: Vec<u32>,
}

impl ParsedModule {
    fn new(ir: Vec<u32>, entry_points: Vec<EntryPoint>) -> ParsedModule {
        ParsedModule { entry_points, ir }
    }
}

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

impl ParserOptions {
    pub fn new() -> ParserOptions {
        ParserOptions
    }
}

#[derive(Debug, Clone)]
pub struct Parser {
    _unconstructable: (),
}

impl Parser {
    // TODO: Remove `compile_target`, see https://github.com/KhronosGroup/SPIRV-Cross/issues/287
    pub fn new() -> Parser {
        Parser {
            _unconstructable: (),
        }
    }

    pub fn parse(
        &self,
        module: &Module,
        _options: &ParserOptions,
    ) -> Result<ParsedModule, ErrorCode> {
        unsafe {
            let mut entry_points_raw = ptr::null_mut();
            let mut entry_points_raw_length = 0 as usize;

            let mut ir = vec![0; module.ir.len()];
            ir.copy_from_slice(module.ir);

            check!(sc_internal_compiler_base_parse(
                ir.as_ptr() as *const u32,
                ir.len() as usize,
                &mut entry_points_raw,
                &mut entry_points_raw_length,
            ));

            let entry_points = (0..entry_points_raw_length)
                .map(|offset| {
                    let entry_point_raw_ptr = entry_points_raw.offset(offset as isize);
                    let entry_point_raw = *entry_point_raw_ptr;
                    let name = match CStr::from_ptr(entry_point_raw.name)
                        .to_owned()
                        .into_string()
                    {
                        Ok(n) => n,
                        _ => return Err(ErrorCode::Unhandled),
                    };

                    let entry_point = EntryPoint {
                        name,
                        execution_model: entry_point_raw.execution_model,
                        workgroup_size: WorkgroupSize {
                            x: entry_point_raw.workgroup_size_x,
                            y: entry_point_raw.workgroup_size_y,
                            z: entry_point_raw.workgroup_size_z,
                        },
                    };

                    check!(sc_internal_free_pointer(
                        entry_point_raw.name as *mut c_void,
                    ));
                    check!(sc_internal_free_pointer(entry_point_raw_ptr as *mut c_void));

                    Ok(entry_point)
                })
                .collect::<Result<Vec<_>, _>>();

            Ok(ParsedModule::new(
                ir,
                match entry_points {
                    Ok(e) => e,
                    Err(e) => return Err(e),
                },
            ))
        }
    }
}
<commit_msg>Remove note<commit_after>use super::ErrorCode;
use bindings::root::*;
use std::ptr;
use std::os::raw::c_void;
use std::ffi::CStr;

pub use bindings::root::spv::ExecutionModel;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct WorkgroupSize {
    pub x: u32,
    pub y: u32,
    pub z: u32,
}

#[derive(Debug, Clone)]
pub struct EntryPoint {
    pub name: String,
    pub execution_model: ExecutionModel,
    pub workgroup_size: WorkgroupSize,
}

#[derive(Debug, Clone)]
pub struct Module<'a> {
    ir: &'a [u32],
}

impl<'a> Module<'a> {
    pub fn new(ir: &[u32]) -> Module {
        Module { ir }
    }
}

pub struct ParsedModule {
    pub entry_points: Vec<EntryPoint>,
    pub(crate) ir: Vec<u32>,
}

impl ParsedModule {
    fn new(ir: Vec<u32>, entry_points: Vec<EntryPoint>) -> ParsedModule {
        ParsedModule { entry_points, ir }
    }
}

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

impl ParserOptions {
    pub fn new() -> ParserOptions {
        ParserOptions
    }
}

#[derive(Debug, Clone)]
pub struct Parser {
    _unconstructable: (),
}

impl Parser {
    pub fn new() -> Parser {
        Parser {
            _unconstructable: (),
        }
    }

    pub fn parse(
        &self,
        module: &Module,
        _options: &ParserOptions,
    ) -> Result<ParsedModule, ErrorCode> {
        unsafe {
            let mut entry_points_raw = ptr::null_mut();
            let mut entry_points_raw_length = 0 as usize;

            let mut ir = vec![0; module.ir.len()];
            ir.copy_from_slice(module.ir);

            check!(sc_internal_compiler_base_parse(
                ir.as_ptr() as *const u32,
                ir.len() as usize,
                &mut entry_points_raw,
                &mut entry_points_raw_length,
            ));

            let entry_points = (0..entry_points_raw_length)
                .map(|offset| {
                    let entry_point_raw_ptr = entry_points_raw.offset(offset as isize);
                    let entry_point_raw = *entry_point_raw_ptr;
                    let name = match CStr::from_ptr(entry_point_raw.name)
                        .to_owned()
                        .into_string()
                    {
                        Ok(n) => n,
                        _ => return Err(ErrorCode::Unhandled),
                    };

                    let entry_point = EntryPoint {
                        name,
                        execution_model: entry_point_raw.execution_model,
                        workgroup_size: WorkgroupSize {
                            x: entry_point_raw.workgroup_size_x,
                            y: entry_point_raw.workgroup_size_y,
                            z: entry_point_raw.workgroup_size_z,
                        },
                    };

                    check!(sc_internal_free_pointer(
                        entry_point_raw.name as *mut c_void,
                    ));
                    check!(sc_internal_free_pointer(entry_point_raw_ptr as *mut c_void));

                    Ok(entry_point)
                })
                .collect::<Result<Vec<_>, _>>();

            Ok(ParsedModule::new(
                ir,
                match entry_points {
                    Ok(e) => e,
                    Err(e) => return Err(e),
                },
            ))
        }
    }
}
<|endoftext|>


<commit_before>#![no_std]

//! An internal helper crate to workaround limitations in the
//! `use_extern_macros` feature with re-exported Macros 1.0 macros.
//!
//! All macros defined here should be imported via [`futures::prelude`] instead.

/// Await a sub-future inside an `#[async]` function.
///
/// You should pass an object implementing [`Future`] or [`StableFuture`] to
/// this macro, it will implicitly `yield` while that future returns
/// [`Async::Pending`] and evaluate to a [`Result`] containing the result of
/// that future once complete.
///
/// # Examples
///
#[cfg_attr(feature = "nightly", doc = "```")]
#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
/// #![feature(proc_macro, generators, pin)]
/// extern crate futures;
///
/// use futures::prelude::*;
/// use futures::future;
/// use futures::stable::block_on_stable;
///
/// #[async]
/// fn probably_one() -> Result<u32, u32> {
///     let one = await!(future::ok::<u32, u32>(1))?;
///     Ok(one)
/// }
///
/// assert_eq!(Ok(1), block_on_stable(probably_one()));
/// ```

#[macro_export]
macro_rules! await {
    ($e:expr) => ({
        // This macro is just here for documetation purposes, see
        // futures-macro-async/src/lib.rs for the implementation.
        __await!($e)
    })
}

/// Await an item from a stream inside an `#[async]` function.
///
/// You should pass an object implementing [`Stream`] to this macro, it will
/// implicitly `yield` while that stream returns [`Async::Pending`] and evaluate
/// to a [`Result`] containing the next item or error from that stream.
///
/// If you want to iterate over all items in a `Stream` you should instead see
/// the documentation on `#[async] for` in the main `#[async]` documentation.
///
/// # Examples
///
#[cfg_attr(feature = "nightly", doc = "```")]
#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
/// #![feature(proc_macro, generators, pin)]
/// extern crate futures;
///
/// use futures::prelude::*;
/// use futures::stream;
/// use futures::stable::block_on_stable;
///
/// #[async]
/// fn eventually_ten() -> Result<u32, u32> {
///     let mut stream = stream::repeat::<u32, u32>(5);
///     if let Some(first) = await_item!(stream)? {
///         if let Some(second) = await_item!(stream)? {
///             return Ok(first + second);
///         }
///     }
///     Err(0)
/// }
///
/// assert_eq!(Ok(10), block_on_stable(eventually_ten()));
/// ```

#[macro_export]
macro_rules! await_item {
    ($e:expr) => ({
        loop {
            let poll = ::futures::__rt::in_ctx(|ctx| ::futures::Stream::poll_next(&mut $e, ctx));
            // Allow for #[feature(never_type)] and Stream<Error = !>
            #[allow(unreachable_code, unreachable_patterns)]
            match poll {
                ::futures::__rt::std::result::Result::Ok(::futures::__rt::Async::Ready(e)) => {
                    break ::futures::__rt::std::result::Result::Ok(e)
                }
                ::futures::__rt::std::result::Result::Ok(::futures::__rt::Async::Pending) => {}
                ::futures::__rt::std::result::Result::Err(e) => {
                    break ::futures::__rt::std::result::Result::Err(e)
                }
            }

            yield ::futures::__rt::Async::Pending
        }
    })
}

/// Yield an item from an `#[async_stream]` function.
///
/// # Examples
///
#[cfg_attr(feature = "nightly", doc = "```")]
#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
/// #![feature(proc_macro, generators, pin)]
/// extern crate futures;
///
/// use futures::prelude::*;
/// use futures::stream;
/// use futures::executor::block_on;
///
/// #[async_stream_move(item = u32)]
/// fn one_five() -> Result<(), u32> {
///     stream_yield!(5);
///     Ok(())
/// }
///
/// assert_eq!(Ok(vec![5]), block_on(one_five().collect()));
/// ```

// TODO: This macro needs to use an extra temporary variable because of
// rust-lang/rust#44197, once that's fixed this should just use $e directly
// inside the yield expression
#[macro_export]
macro_rules! stream_yield {
    ($e:expr) => ({
        let e = $e;
        yield ::futures::__rt::Async::Ready(e)
    })
}
<commit_msg>Fix stream_yield example<commit_after>#![no_std]

//! An internal helper crate to workaround limitations in the
//! `use_extern_macros` feature with re-exported Macros 1.0 macros.
//!
//! All macros defined here should be imported via [`futures::prelude`] instead.

/// Await a sub-future inside an `#[async]` function.
///
/// You should pass an object implementing [`Future`] or [`StableFuture`] to
/// this macro, it will implicitly `yield` while that future returns
/// [`Async::Pending`] and evaluate to a [`Result`] containing the result of
/// that future once complete.
///
/// # Examples
///
#[cfg_attr(feature = "nightly", doc = "```")]
#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
/// #![feature(proc_macro, generators, pin)]
/// extern crate futures;
///
/// use futures::prelude::*;
/// use futures::future;
/// use futures::stable::block_on_stable;
///
/// #[async]
/// fn probably_one() -> Result<u32, u32> {
///     let one = await!(future::ok::<u32, u32>(1))?;
///     Ok(one)
/// }
///
/// assert_eq!(Ok(1), block_on_stable(probably_one()));
/// ```

#[macro_export]
macro_rules! await {
    ($e:expr) => ({
        // This macro is just here for documetation purposes, see
        // futures-macro-async/src/lib.rs for the implementation.
        __await!($e)
    })
}

/// Await an item from a stream inside an `#[async]` function.
///
/// You should pass an object implementing [`Stream`] to this macro, it will
/// implicitly `yield` while that stream returns [`Async::Pending`] and evaluate
/// to a [`Result`] containing the next item or error from that stream.
///
/// If you want to iterate over all items in a `Stream` you should instead see
/// the documentation on `#[async] for` in the main `#[async]` documentation.
///
/// # Examples
///
#[cfg_attr(feature = "nightly", doc = "```")]
#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
/// #![feature(proc_macro, generators, pin)]
/// extern crate futures;
///
/// use futures::prelude::*;
/// use futures::stream;
/// use futures::stable::block_on_stable;
///
/// #[async]
/// fn eventually_ten() -> Result<u32, u32> {
///     let mut stream = stream::repeat::<u32, u32>(5);
///     if let Some(first) = await_item!(stream)? {
///         if let Some(second) = await_item!(stream)? {
///             return Ok(first + second);
///         }
///     }
///     Err(0)
/// }
///
/// assert_eq!(Ok(10), block_on_stable(eventually_ten()));
/// ```

#[macro_export]
macro_rules! await_item {
    ($e:expr) => ({
        loop {
            let poll = ::futures::__rt::in_ctx(|ctx| ::futures::Stream::poll_next(&mut $e, ctx));
            // Allow for #[feature(never_type)] and Stream<Error = !>
            #[allow(unreachable_code, unreachable_patterns)]
            match poll {
                ::futures::__rt::std::result::Result::Ok(::futures::__rt::Async::Ready(e)) => {
                    break ::futures::__rt::std::result::Result::Ok(e)
                }
                ::futures::__rt::std::result::Result::Ok(::futures::__rt::Async::Pending) => {}
                ::futures::__rt::std::result::Result::Err(e) => {
                    break ::futures::__rt::std::result::Result::Err(e)
                }
            }

            yield ::futures::__rt::Async::Pending
        }
    })
}

/// Yield an item from an `#[async_stream]` function.
///
/// # Examples
///
#[cfg_attr(feature = "nightly", doc = "```")]
#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
/// #![feature(proc_macro, generators, pin)]
/// extern crate futures;
///
/// use futures::prelude::*;
/// use futures::stream;
/// use futures::executor::block_on;
///
/// #[async_stream(unpin, item = u32)]
/// fn one_five() -> Result<(), u32> {
///     stream_yield!(5);
///     Ok(())
/// }
///
/// assert_eq!(Ok(vec![5]), block_on(one_five().collect()));
/// ```

// TODO: This macro needs to use an extra temporary variable because of
// rust-lang/rust#44197, once that's fixed this should just use $e directly
// inside the yield expression
#[macro_export]
macro_rules! stream_yield {
    ($e:expr) => ({
        let e = $e;
        yield ::futures::__rt::Async::Ready(e)
    })
}
<|endoftext|>