<commit_before>extern crate ffmpeg;

use std::path::Path;

use ffmpeg::Rational;
use ffmpeg::format::stream::Disposition;

pub struct Context {
    ffmpeg_context: ffmpeg::format::context::Input,
    pub name: String,
    pub description: String,
    pub video_stream: Option<VideoStream>,
    pub audio_stream: Option<AudioStream>,
}

impl Context {
    pub fn new(path: &Path) -> Result<Context, String> {
        match ffmpeg::format::input(&path) {
            Ok(ffmpeg_context) => {
                // for the moment, let's work on the best streams, if available
                let mut new_ctx = Context{
                    ffmpeg_context: ffmpeg_context,
                    name: String::new(),
                    description: String::new(),
                    video_stream: None,
                    audio_stream: None,
                };

                let stream_count;
                {
                    let format = new_ctx.ffmpeg_context.format();
                    new_ctx.name = String::from(format.name());
                    new_ctx.description = String::from(format.description());

                    let stream_iter = new_ctx.ffmpeg_context.streams();
                    stream_count = stream_iter.size_hint().0;

                    new_ctx.video_stream = VideoStream::new(&stream_iter);
                    new_ctx.audio_stream = AudioStream::new(&stream_iter);
                }

                // TODO: process metadata

                // TODO: see what we should do with subtitles

                println!("Input: {} - {}, {} streams",
                         &new_ctx.name, &new_ctx.description, stream_count
                );

                if stream_count > 0 {
                    // TODO: also check for misdetections (detection score)
                    Ok(new_ctx)
                }
                else {
                    Err("Couldn't find any video or audio stream".to_owned())
                }
            },
            Err(error) => {
                Err(format!("{:?}", error))
            },
        }
    }

}

pub struct VideoStream {
    pub index: usize,
    pub time_base: Rational,
    pub start_time: i64,
    pub duration: i64,
    pub frames: i64,
    pub disposition: Disposition,
    pub rate: Rational,
    pub avg_frame_rate: Rational,
}

impl VideoStream {
    pub fn new(stream_iter: &ffmpeg::format::context::common::StreamIter) -> Option<VideoStream> {
        let video_stream = stream_iter.best(ffmpeg::media::Type::Video);

        match video_stream {
            Some(video_stream) => {
                if video_stream.frames() > 0 {
                    Some(VideoStream {
                        index: video_stream.index(),
                        time_base: video_stream.time_base(),
                        start_time: video_stream.start_time(),
                        duration: video_stream.duration(),
                        frames: video_stream.frames(),
                        disposition: video_stream.disposition(),
                        rate: video_stream.rate(),
                        avg_frame_rate: video_stream.avg_frame_rate(),
                    })
                }
                else {
                    None
                }
            },
            None => None,
        }
    }
}

// TODO: use composition to factorize the members common to Video and Audio
pub struct AudioStream {
    pub index: usize,
    pub time_base: Rational,
    pub start_time: i64,
    pub duration: i64,
    pub frames: i64,
    pub disposition: Disposition,
    pub rate: Rational,
    pub avg_frame_rate: Rational,
}

impl AudioStream {
    pub fn new(stream_iter: &ffmpeg::format::context::common::StreamIter) -> Option<AudioStream> {
        let audio_stream = stream_iter.best(ffmpeg::media::Type::Audio);

        match audio_stream {
            Some(audio_stream) => {
                if audio_stream.duration() > 0 || audio_stream.frames() > 0 {
                    Some(AudioStream {
                        index: audio_stream.index(),
                        time_base: audio_stream.time_base(),
                        start_time: audio_stream.start_time(),
                        duration: audio_stream.duration(),
                        frames: audio_stream.frames(),
                        disposition: audio_stream.disposition(),
                        rate: audio_stream.rate(),
                        avg_frame_rate: audio_stream.avg_frame_rate(),
                    })
                }
                else {
                    None
                }
            },
            None => None,
        }
    }
}
<commit_msg>Factorized Video and Audio Streams (#1)<commit_after>extern crate ffmpeg;

use std::path::Path;
use std::ops::{Deref, DerefMut};

use ffmpeg::Rational;
use ffmpeg::format::stream::Disposition;

pub struct Context {
    ffmpeg_context: ffmpeg::format::context::Input,
    pub name: String,
    pub description: String,
    pub video_stream: Option<VideoStream>,
    pub audio_stream: Option<AudioStream>,
}

impl Context {
    pub fn new(path: &Path) -> Result<Context, String> {
        match ffmpeg::format::input(&path) {
            Ok(ffmpeg_context) => {
                // for the moment, let's work on the best streams, if available
                let mut new_ctx = Context{
                    ffmpeg_context: ffmpeg_context,
                    name: String::new(),
                    description: String::new(),
                    video_stream: None,
                    audio_stream: None,
                };

                let stream_count;
                {
                    let format = new_ctx.ffmpeg_context.format();
                    new_ctx.name = String::from(format.name());
                    new_ctx.description = String::from(format.description());

                    let stream_iter = new_ctx.ffmpeg_context.streams();
                    stream_count = stream_iter.size_hint().0;

                    new_ctx.video_stream = VideoStream::new(&stream_iter);
                    new_ctx.audio_stream = AudioStream::new(&stream_iter);
                }

                // TODO: process metadata

                // TODO: see what we should do with subtitles

                println!("Input: {} - {}, {} streams",
                         &new_ctx.name, &new_ctx.description, stream_count
                );

                if stream_count > 0 {
                    // TODO: also check for misdetections (detection score)
                    Ok(new_ctx)
                }
                else {
                    Err("Couldn't find any video or audio stream".to_owned())
                }
            },
            Err(error) => {
                Err(format!("{:?}", error))
            },
        }
    }

}

pub struct Stream {
    pub index: usize,
    pub time_base: Rational,
    pub start_time: i64,
    pub duration: i64,
    pub frames: i64,
    pub disposition: Disposition,
    pub rate: Rational,
    pub avg_frame_rate: Rational,
}

impl Stream {
    pub fn new(stream_iter: &ffmpeg::format::context::common::StreamIter,
               media_type: ffmpeg::media::Type) -> Option<Stream> {
        let stream = stream_iter.best(media_type);
        match stream {
            Some(stream) => {
                Some(Stream {
                    index: stream.index(),
                    time_base: stream.time_base(),
                    start_time: stream.start_time(),
                    duration: stream.duration(),
                    frames: stream.frames(),
                    disposition: stream.disposition(),
                    rate: stream.rate(),
                    avg_frame_rate: stream.avg_frame_rate(),
                })
            },
            None => None,
        }
    }
}

pub struct VideoStream {
    pub stream: Stream,
}

impl VideoStream {
    pub fn new(stream_iter: &ffmpeg::format::context::common::StreamIter) -> Option<VideoStream> {
        let video_stream = Stream::new(stream_iter, ffmpeg::media::Type::Video);

        match video_stream {
            Some(video_stream) => {
                if video_stream.frames > 0 {
                    Some(VideoStream{ stream: video_stream, })
                }
                else {
                    None
                }
            },
            None => None,
        }
    }
}

impl Deref for VideoStream {
	type Target = Stream;

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

impl DerefMut for VideoStream {
	fn deref_mut(&mut self) -> &mut Self::Target {
		&mut self.stream
	}
}

pub struct AudioStream {
    pub stream: Stream,
}

impl AudioStream {
    pub fn new(stream_iter: &ffmpeg::format::context::common::StreamIter) -> Option<AudioStream> {
        let audio_stream = Stream::new(stream_iter, ffmpeg::media::Type::Audio);

        match audio_stream {
            Some(audio_stream) => {
                if audio_stream.frames > 0 || audio_stream.duration > 0 {
                    Some(AudioStream{ stream: audio_stream, })
                }
                else {
                    None
                }
            },
            None => None,
        }
   }
}

impl Deref for AudioStream {
	type Target = Stream;

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

impl DerefMut for AudioStream {
	fn deref_mut(&mut self) -> &mut Self::Target {
		&mut self.stream
	}
}
<|endoftext|>


<commit_before>use itertools::Itertools;

use model;

#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub struct MeanVar {
    pub mean: f64,
    pub var: f64
}

impl MeanVar {

    pub fn standard_deviation(&self) -> f64 {
        self.var.sqrt()
    }

    pub fn coefficient_of_variation(&self) -> f64 {
        self.standard_deviation() / self.mean
    }
}

pub fn cdf<T: PartialOrd, F: Fn(f64, f64) -> T>(cdfs: &[model::dist::CDF<f64>], value: F) -> model::dist::CDF<T> {
    let n = cdfs.len() as f64;
    let mut curr = Vec::new();
    let mut prev = {
        let mut pmf = Vec::new();
        for (&value, prob) in cdfs[0].iter_pmf() {
            pmf.push(((value, 0.0), prob));
        }
        model::dist::CDF::from_pmf(pmf)
    };

    for (k, cdf) in cdfs.iter().enumerate().skip(1) {
        let k = k as f64 + 1.0;

        for (&(m, s), p) in prev.sample(1000).iter_pmf() {
            for (&value, prob) in cdf.iter_pmf() {
                let p = p + prob;
                let mk = m + (value - m) / k;
                let sk = s + (value - m) * (value - mk);
                curr.push(((mk, sk), p));
            }
        }
        println!("{:?}", curr);
        prev = model::dist::CDF::from_pmf(curr);
        curr = Vec::new();
    }
    let pmf = prev.iter_pmf().map(|(&(m, s), p)| {
        (value(m, s / (n - 1.0)), p)
    }).collect_vec();
    model::dist::CDF::from_pmf(pmf)
}

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

    #[test]
    fn test_cdf() {
        let cdf1 = CDF::from_pmf(vec![(6.0, -1.0), (70.0, -0.45867514538708193)]);
        let cdf2 = CDF::from_pmf(vec![(3.0, -1.0), (70.0, -0.45867514538708193)]);
        let cdf3 = CDF::from_pmf(vec![(3.0, -1.0), (70.0, -0.45867514538708193)]);
        println!("{}", cdf1.map());
        println!("{}", cdf2.map());

        let cdf = cdf(&[cdf1, cdf2, cdf3], |mean, _| mean);

        println!("{:?}", cdf);
        println!("{}", cdf.map());
        println!("{}", cdf.expected_value());
        assert_eq!(*cdf.map(), 70.0);
    }
}
<commit_msg>Debugging.<commit_after>use itertools::Itertools;

use model;

#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub struct MeanVar {
    pub mean: f64,
    pub var: f64
}

impl MeanVar {

    pub fn standard_deviation(&self) -> f64 {
        self.var.sqrt()
    }

    pub fn coefficient_of_variation(&self) -> f64 {
        self.standard_deviation() / self.mean
    }
}

pub fn cdf<T: PartialOrd, F: Fn(f64, f64) -> T>(cdfs: &[model::dist::CDF<f64>], value: F) -> model::dist::CDF<T> {
    let n = cdfs.len() as f64;
    let mut curr = Vec::new();
    let mut prev = {
        let mut pmf = Vec::new();
        for (&value, prob) in cdfs[0].iter_pmf() {
            pmf.push(((value, 0.0), prob));
        }
        model::dist::CDF::from_pmf(pmf)
    };

    for (k, cdf) in cdfs.iter().enumerate().skip(1) {
        let k = k as f64 + 1.0;

        for (&(m, s), p) in prev.sample(1000).iter_pmf() {
            for (&value, prob) in cdf.iter_pmf() {
                let p = p + prob;
                let mk = m + (value - m) / k;
                let sk = s + (value - m) * (value - mk);
                curr.push(((mk, sk), p));
            }
        }
        println!("----------\n{:?}", &curr[..5]);
        prev = model::dist::CDF::from_pmf(curr);
        curr = Vec::new();
    }
    let pmf = prev.iter_pmf().map(|(&(m, s), p)| {
        (value(m, s / (n - 1.0)), p)
    }).collect_vec();
    model::dist::CDF::from_pmf(pmf)
}

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

    #[test]
    fn test_cdf() {
        let cdf1 = CDF::from_pmf(vec![(6.0, -1.0), (70.0, -0.45867514538708193)]);
        let cdf2 = CDF::from_pmf(vec![(3.0, -1.0), (70.0, -0.45867514538708193)]);
        let cdf3 = CDF::from_pmf(vec![(3.0, -1.0), (70.0, -0.45867514538708193)]);
        println!("{}", cdf1.map());
        println!("{}", cdf2.map());

        let cdf = cdf(&[cdf1, cdf2, cdf3], |mean, _| mean);

        println!("{:?}", cdf);
        println!("{}", cdf.map());
        println!("{}", cdf.expected_value());
        assert_eq!(*cdf.map(), 70.0);
    }
}
<|endoftext|>


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

use python::{Python, PythonObject, ToPythonPointer};
use err::{self, PyErr, PyResult};
use super::object::PyObject;
use super::exc;
use ffi::{self, Py_ssize_t};
use conversion::ToPyObject;
use std::slice;

/// Represents a Python tuple object.
pub struct PyTuple(PyObject);

pyobject_newtype!(PyTuple, PyTuple_Check, PyTuple_Type);

impl PyTuple {
    /// Construct a new tuple with the given elements.
    pub fn new(py: Python, elements: &[PyObject]) -> PyTuple {
        unsafe {
            let len = elements.len();
            let ptr = ffi::PyTuple_New(len as Py_ssize_t);
            let t = err::result_cast_from_owned_ptr::<PyTuple>(py, ptr).unwrap();
            for (i, e) in elements.iter().enumerate() {
                ffi::PyTuple_SetItem(ptr, i as Py_ssize_t, e.steal_ptr(py));
            }
            t
        }
    }

    /// Retrieves the empty tuple.
    pub fn empty(py: Python) -> PyTuple {
        unsafe {
            err::result_cast_from_owned_ptr::<PyTuple>(py, ffi::PyTuple_New(0)).unwrap()
        }
    }

    /// Gets the length of the tuple.
    #[inline]
    pub fn len(&self, _py: Python) -> usize {
        unsafe {
            // non-negative Py_ssize_t should always fit into Rust uint
            ffi::PyTuple_GET_SIZE(self.0.as_ptr()) as usize
        }
    }

    /// Gets the item at the specified index.
    ///
    /// Panics if the index is out of range.
    pub fn get_item(&self, py: Python, index: usize) -> PyObject {
        // TODO: reconsider whether we should panic
        // It's quite inconsistent that this method takes `Python` when `len()` does not.
        assert!(index < self.len(py));
        unsafe {
            PyObject::from_borrowed_ptr(py, ffi::PyTuple_GET_ITEM(self.0.as_ptr(), index as Py_ssize_t))
        }
    }

    #[inline]
    #[cfg(feature="nightly")] // needs unsafe_no_drop_flag
    pub fn as_slice<'a>(&'a self) -> &'a [PyObject] {
        // This is safe because PyObject has the same memory layout as *mut ffi::PyObject,
        // and because tuples are immutable.
        // (We don't even need a Python token, thanks to immutability)
        unsafe {
            let ptr = self.0.as_ptr() as *mut ffi::PyTupleObject;
            PyObject::borrow_from_owned_ptr_slice(
                slice::from_raw_parts(
                    (*ptr).ob_item.as_ptr(),
                    ffi::PyTuple_GET_SIZE(self.0.as_ptr()) as usize
                ))
        }
    }

    #[inline]
    pub fn iter<'a, 'p>(&'a self, py: Python<'p>) -> PyTupleIterator<'a, 'p> {
        PyTupleIterator {
            py: py,
            tuple: self,
            index: 0,
            end: self.len(py)
        }
    }
}

#[cfg(feature="nightly")] // needs unsafe_no_drop_flag
impl ::std::ops::Index<usize> for PyTuple {
    type Output = PyObject;

    #[inline]
    fn index(&self, index: usize) -> &PyObject {
        &self.as_slice()[index]
    }
}

#[cfg(feature="nightly")] // needs unsafe_no_drop_flag
impl <'a> IntoIterator for &'a PyTuple {
    type Item = &'a PyObject;
    type IntoIter = slice::Iter<'a, PyObject>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        self.as_slice().iter()
    }
}

/// Used by `PyTuple::iter()`.
pub struct PyTupleIterator<'a, 'p> {
    py: Python<'p>,
    tuple: &'a PyTuple,
    index: usize,
    end: usize
}

impl <'a, 'p> Iterator for PyTupleIterator<'a, 'p> {
    type Item = PyObject;

    #[inline]
    fn next(&mut self) -> Option<PyObject> {
        if self.index < self.end {
            let item = self.tuple.get_item(self.py, self.index);
            self.index += 1;
            Some(item)
        } else {
            None
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len(), Some(self.len()))
    }
}

impl <'a, 'p> ExactSizeIterator for PyTupleIterator<'a, 'p> {
    #[inline]
    fn len(&self) -> usize {
        self.end - self.index
    }
}

fn wrong_tuple_length(py: Python, t: &PyTuple, expected_length: usize) -> PyErr {
    let msg = format!("Expected tuple of length {}, but got tuple of length {}.", expected_length, t.len(py));
    PyErr::new_lazy_init(py.get_type::<exc::ValueError>(), Some(msg.to_py_object(py).into_object()))
}

macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+} => (
    impl <'p, $($T: ToPyObject),+> ToPyObject for ($($T,)+) {
        type ObjectType = PyTuple;

        fn to_py_object(&self, py: Python) -> PyTuple {
            PyTuple::new(py, &[
                $(py_coerce_expr!(self.$n.to_py_object(py)).into_object(),)+
            ])
        }

        fn into_py_object(self, py: Python) -> PyTuple {
            PyTuple::new(py, &[
                $(py_coerce_expr!(self.$n.into_py_object(py)).into_object(),)+
            ])
        }
    }

    /*TODO: reimplement this without slice matching
    impl <'p, 's, $($T: FromPyObject<'p, 's>),+> FromPyObject<'p, 's> for ($($T,)+) {
        fn from_py_object(s : &'s PyObject<'p>) -> PyResult<'p, ($($T,)+)> {
            let t = try!(s.cast_as::<PyTuple>());
            match t.as_slice() {
                [$(ref $refN,)+] => Ok((
                    $(try!($refN.extract::<$T>()),)+
                )),
                _ => Err(wrong_tuple_length(t, 2))
            }
        }
    }*/
));

tuple_conversion!(1, (ref0, 0, A));
tuple_conversion!(2, (ref0, 0, A), (ref1, 1, B));
tuple_conversion!(3, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C));
tuple_conversion!(4, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D));
tuple_conversion!(5, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
  (ref4, 4, E));
tuple_conversion!(6, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
  (ref4, 4, E), (ref5, 5, F));
tuple_conversion!(7, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
  (ref4, 4, E), (ref5, 5, F), (ref6, 6, G));
tuple_conversion!(8, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
  (ref4, 4, E), (ref5, 5, F), (ref6, 6, G), (ref7, 7, H));
tuple_conversion!(9, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
  (ref4, 4, E), (ref5, 5, F), (ref6, 6, G), (ref7, 7, H), (ref8, 8, I));

// Empty tuple:

/// An empty struct that represents the empty argument list.
/// Corresponds to the empty tuple `()` in Python.
///
/// # Example
/// ```
/// let gil_guard = cpython::Python::acquire_gil();
/// let py = gil_guard.python();
/// let os = py.import("os").unwrap();
/// let pid = os.call(py, "get_pid", cpython::NoArgs, None);
/// ```
#[derive(Copy, Clone, Debug)]
pub struct NoArgs;

/// Converts `NoArgs` to an empty Python tuple.
impl ToPyObject for NoArgs {
    type ObjectType = PyTuple;

    fn to_py_object(&self, py: Python) -> PyTuple {
        PyTuple::empty(py)
    }
}

/// Returns `Ok(NoArgs)` if the input is an empty Python tuple.
/// Otherwise, returns an error.
extract!(obj to NoArgs; py => {
    let t = try!(obj.cast_as::<PyTuple>(py));
    if t.len(py) == 0 {
        Ok(NoArgs)
    } else {
        Err(wrong_tuple_length(py, t, 0))
    }
});

#[cfg(test)]
mod test {
    use python::{Python, PythonObject};
    use conversion::ToPyObject;

    #[test]
    fn test_len() {
        let gil = Python::acquire_gil();
        let py = gil.python();
        let tuple = (1, 2, 3).to_py_object(py);
        assert_eq!(3, tuple.len(py));
    }
}

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

use python::{Python, PythonObject, ToPythonPointer, PyDrop};
use err::{self, PyErr, PyResult};
use super::object::PyObject;
use super::exc;
use ffi::{self, Py_ssize_t};
use conversion::{FromPyObject, ToPyObject};
use std::slice;

/// Represents a Python tuple object.
pub struct PyTuple(PyObject);

pyobject_newtype!(PyTuple, PyTuple_Check, PyTuple_Type);

impl PyTuple {
    /// Construct a new tuple with the given elements.
    pub fn new(py: Python, elements: &[PyObject]) -> PyTuple {
        unsafe {
            let len = elements.len();
            let ptr = ffi::PyTuple_New(len as Py_ssize_t);
            let t = err::result_cast_from_owned_ptr::<PyTuple>(py, ptr).unwrap();
            for (i, e) in elements.iter().enumerate() {
                ffi::PyTuple_SetItem(ptr, i as Py_ssize_t, e.steal_ptr(py));
            }
            t
        }
    }

    /// Retrieves the empty tuple.
    pub fn empty(py: Python) -> PyTuple {
        unsafe {
            err::result_cast_from_owned_ptr::<PyTuple>(py, ffi::PyTuple_New(0)).unwrap()
        }
    }

    /// Gets the length of the tuple.
    #[inline]
    pub fn len(&self, _py: Python) -> usize {
        unsafe {
            // non-negative Py_ssize_t should always fit into Rust uint
            ffi::PyTuple_GET_SIZE(self.0.as_ptr()) as usize
        }
    }

    /// Gets the item at the specified index.
    ///
    /// Panics if the index is out of range.
    pub fn get_item(&self, py: Python, index: usize) -> PyObject {
        // TODO: reconsider whether we should panic
        // It's quite inconsistent that this method takes `Python` when `len()` does not.
        assert!(index < self.len(py));
        unsafe {
            PyObject::from_borrowed_ptr(py, ffi::PyTuple_GET_ITEM(self.0.as_ptr(), index as Py_ssize_t))
        }
    }

    #[inline]
    #[cfg(feature="nightly")] // needs unsafe_no_drop_flag
    pub fn as_slice<'a>(&'a self) -> &'a [PyObject] {
        // This is safe because PyObject has the same memory layout as *mut ffi::PyObject,
        // and because tuples are immutable.
        // (We don't even need a Python token, thanks to immutability)
        unsafe {
            let ptr = self.0.as_ptr() as *mut ffi::PyTupleObject;
            PyObject::borrow_from_owned_ptr_slice(
                slice::from_raw_parts(
                    (*ptr).ob_item.as_ptr(),
                    ffi::PyTuple_GET_SIZE(self.0.as_ptr()) as usize
                ))
        }
    }

    #[inline]
    pub fn iter<'a, 'p>(&'a self, py: Python<'p>) -> PyTupleIterator<'a, 'p> {
        PyTupleIterator {
            py: py,
            tuple: self,
            index: 0,
            end: self.len(py)
        }
    }
}

#[cfg(feature="nightly")] // needs unsafe_no_drop_flag
impl ::std::ops::Index<usize> for PyTuple {
    type Output = PyObject;

    #[inline]
    fn index(&self, index: usize) -> &PyObject {
        &self.as_slice()[index]
    }
}

#[cfg(feature="nightly")] // needs unsafe_no_drop_flag
impl <'a> IntoIterator for &'a PyTuple {
    type Item = &'a PyObject;
    type IntoIter = slice::Iter<'a, PyObject>;

    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        self.as_slice().iter()
    }
}

/// Used by `PyTuple::iter()`.
pub struct PyTupleIterator<'a, 'p> {
    py: Python<'p>,
    tuple: &'a PyTuple,
    index: usize,
    end: usize
}

impl <'a, 'p> Iterator for PyTupleIterator<'a, 'p> {
    type Item = PyObject;

    #[inline]
    fn next(&mut self) -> Option<PyObject> {
        if self.index < self.end {
            let item = self.tuple.get_item(self.py, self.index);
            self.index += 1;
            Some(item)
        } else {
            None
        }
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len(), Some(self.len()))
    }
}

impl <'a, 'p> ExactSizeIterator for PyTupleIterator<'a, 'p> {
    #[inline]
    fn len(&self) -> usize {
        self.end - self.index
    }
}

fn wrong_tuple_length(py: Python, t: &PyTuple, expected_length: usize) -> PyErr {
    let msg = format!("Expected tuple of length {}, but got tuple of length {}.", expected_length, t.len(py));
    PyErr::new_lazy_init(py.get_type::<exc::ValueError>(), Some(msg.to_py_object(py).into_object()))
}

macro_rules! tuple_conversion ({$length:expr,$(($refN:ident, $n:tt, $T:ident)),+} => {
    impl <$($T: ToPyObject),+> ToPyObject for ($($T,)+) {
        type ObjectType = PyTuple;

        fn to_py_object(&self, py: Python) -> PyTuple {
            PyTuple::new(py, &[
                $(py_coerce_expr!(self.$n.to_py_object(py)).into_object(),)+
            ])
        }

        fn into_py_object(self, py: Python) -> PyTuple {
            PyTuple::new(py, &[
                $(py_coerce_expr!(self.$n.into_py_object(py)).into_object(),)+
            ])
        }
    }

    #[cfg(not(feature="nightly"))]
    impl <'s, $($T: for <'a> FromPyObject<'a>),+> FromPyObject<'s> for ($($T,)+) {
        fn extract(py: Python, obj: &'s PyObject) -> PyResult<Self> {
            let t = try!(obj.cast_as::<PyTuple>(py));
            if t.len(py) == $length {
                Ok((
                    $( py_coerce_expr! {{
                        let item = t.get_item(py, $n);
                        let r = try!(item.extract::<$T>(py));
                        item.release_ref(py);
                        r
                    }} ,)+
                ))
            } else {
                Err(wrong_tuple_length(py, t, $length))
            }
        }
    }

    #[cfg(feature="nightly")]
    impl <'s, $($T: FromPyObject<'s>),+> FromPyObject<'s> for ($($T,)+) {
        fn extract(py: Python, obj: &'s PyObject) -> PyResult<Self> {
            let t = try!(obj.cast_as::<PyTuple>(py));
            let slice = t.as_slice();
            if slice.len() == $length {
                Ok((
                    $( try!(slice[$n].extract::<$T>(py)), )+
                ))
            } else {
                Err(wrong_tuple_length(py, t, $length))
            }
        }
    }
});

tuple_conversion!(1, (ref0, 0, A));
tuple_conversion!(2, (ref0, 0, A), (ref1, 1, B));
tuple_conversion!(3, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C));
tuple_conversion!(4, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D));
tuple_conversion!(5, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
  (ref4, 4, E));
tuple_conversion!(6, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
  (ref4, 4, E), (ref5, 5, F));
tuple_conversion!(7, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
  (ref4, 4, E), (ref5, 5, F), (ref6, 6, G));
tuple_conversion!(8, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
  (ref4, 4, E), (ref5, 5, F), (ref6, 6, G), (ref7, 7, H));
tuple_conversion!(9, (ref0, 0, A), (ref1, 1, B), (ref2, 2, C), (ref3, 3, D),
  (ref4, 4, E), (ref5, 5, F), (ref6, 6, G), (ref7, 7, H), (ref8, 8, I));

// Empty tuple:

/// An empty struct that represents the empty argument list.
/// Corresponds to the empty tuple `()` in Python.
///
/// # Example
/// ```
/// let gil_guard = cpython::Python::acquire_gil();
/// let py = gil_guard.python();
/// let os = py.import("os").unwrap();
/// let pid = os.call(py, "get_pid", cpython::NoArgs, None);
/// ```
#[derive(Copy, Clone, Debug)]
pub struct NoArgs;

/// Converts `NoArgs` to an empty Python tuple.
impl ToPyObject for NoArgs {
    type ObjectType = PyTuple;

    fn to_py_object(&self, py: Python) -> PyTuple {
        PyTuple::empty(py)
    }
}

/// Returns `Ok(NoArgs)` if the input is an empty Python tuple.
/// Otherwise, returns an error.
extract!(obj to NoArgs; py => {
    let t = try!(obj.cast_as::<PyTuple>(py));
    if t.len(py) == 0 {
        Ok(NoArgs)
    } else {
        Err(wrong_tuple_length(py, t, 0))
    }
});

#[cfg(test)]
mod test {
    use python::{Python, PythonObject};
    use conversion::ToPyObject;

    #[test]
    fn test_len() {
        let gil = Python::acquire_gil();
        let py = gil.python();
        let tuple = (1, 2, 3).to_py_object(py);
        assert_eq!(3, tuple.len(py));
        assert_eq!((1, 2, 3), tuple.into_object().extract(py).unwrap());
    }
}

<|endoftext|>


<commit_before>pub struct BitField {
    pub index: usize,
    pub mask: u8,
}

impl BitField {
    #[inline]
    pub fn get(&self, data: &[u8]) -> Option<u8> {
        if let Some(val) = data.get(self.index) {
            return Some((val & self.mask) >> self.mask.trailing_zeros());
        }
        None
    }

    #[inline]
    pub fn nonzero(&self, data: &[u8]) -> Option<bool> {
        if let Some(val) = data.get(self.index) {
            return Some(0 != (val & self.mask));
        }
        None
    }
}

pub struct U16Field {
    pub index: usize
}

impl U16Field {
    #[inline]
    pub fn get(&self, data: &[u8]) -> Option<u16> {
        if let Some(hi) = data.get(self.index) {
            if let Some(lo) = data.get(self.index + 1) {
              return Some(((*hi as u16) << 8) + *lo as u16);
            }
        }
        None
    }
}

pub struct U32Field {
    pub index: usize
}

impl U32Field {
    #[inline]
    pub fn get(&self, data: &[u8]) -> Option<u32> {
        let hi = U16Field{index:self.index}.get(data);
        let lo = U16Field{index:self.index+2}.get(data);
        if let Some(a) = hi {
            if let Some(b) = lo {
              return Some(((a as u32) << 16) + b as u32);
            }
        }
        None
    }
}
<commit_msg>Revise bit access for generality.<commit_after>use std::ops::{Index, IndexMut, Range};

pub trait Data {
    type Slice: ?Sized + Index<usize,Output=u8>;

    fn get(&self, index: usize) -> Option<&u8>;
    fn get_range(&self, index: Range<usize>) -> Option<&Self::Slice>;
}

pub trait MutData: Data {
    type SliceMut: ?Sized + IndexMut<usize,Output=u8>;

    fn get_mut(&mut self, index: usize) -> Option<&mut u8>;
    fn get_mut_range(&mut self, index: Range<usize>) -> Option<&mut Self::SliceMut>;
}

impl Data for [u8] {
    type Slice = [u8];
    #[inline] fn get(&self, index: usize) -> Option<&u8> { (self as &[u8]).get(index) }

    #[inline]
    fn get_range(&self, index: Range<usize>) -> Option<&Self::Slice> {
        if index.end > self.len() { return None; }
        Some(&self[index])
    }
}

impl MutData for [u8] {
    type SliceMut = [u8];

    #[inline] fn get_mut(&mut self, index: usize) -> Option<&mut u8> { (self as &mut[u8]).get_mut(index) }

    #[inline]
    fn get_mut_range(&mut self, index: Range<usize>) -> Option<&mut Self::SliceMut> {
        if index.end > self.len() { return None; }
        Some(&mut self[index])
    }
}

type U8Slice = [u8];

impl Data for Vec<u8> {
    type Slice = [u8];

    #[inline] fn get(&self, index: usize) -> Option<&u8> { U8Slice::get(self, index) }

    #[inline]
    fn get_range(&self, index: Range<usize>) -> Option<&Self::Slice> {
        if index.end > self.len() { return None; }
        Some(&self[index])
    }
}

/// Bit field manipulation. Does not yet work across byte boundaries.
pub struct BitField {
    /// Byte offset from start of data.
    pub index: usize,
    /// Bits to extract from the target byte.
    pub mask: u8,
}

impl BitField {
    #[inline]
    pub fn get<T: Data + ?Sized>(&self, data: &T) -> Option<u8> {
        if let Some(val) = data.get(self.index) {
            return Some((val & self.mask) >> self.mask.trailing_zeros());
        }
        None
    }

    #[inline]
    pub fn nonzero<T: Data + ?Sized>(&self, data: &T) -> Option<bool> {
        if let Some(val) = data.get(self.index) {
            return Some(0 != (val & self.mask));
        }
        None
    }

    #[inline]
    pub fn set<T: MutData + ?Sized>(&self, data: &mut T, value: u8) {
        if let Some(elem) = data.get_mut(self.index) {
            *elem = (*elem & !self.mask) | ((value as u8 & self.mask) << self.mask.trailing_zeros());
        }
    }
}

pub struct BEU16Field {
    pub index: usize
}

impl BEU16Field {
    #[inline]
    pub fn get<T: Data + ?Sized>(&self, data: &T) -> Option<u16> {
        if let Some(split) = data.get_range(self.index..self.index+2) {
            return Some((split[0] as u16) << 8 + (split[1] as u16));
        }
        None
    }

    #[inline]
    pub fn set<T: MutData + ?Sized>(&self, data: &mut T, value: u16) {
        if let Some(split) = data.get_mut_range(self.index..self.index+2) {
            split[0] = ((value & 0xff00) >> 8) as u8;
            split[1] = (value & 0x00ff) as u8;
        }
    }
}

pub struct BEU32Field {
    pub index: usize
}

impl BEU32Field {
    #[inline]
    pub fn get<T: Data + ?Sized>(&self, data: &T) -> Option<u32> {
        if let Some(split) = data.get_range(self.index..self.index+4) {
            return Some(((split[0] as u32) << 24) +
                        ((split[1] as u32) << 16) +
                        ((split[2] as u32) << 8) +
                        ((split[3] as u32) << 0))
        }
        None
    }

    #[inline]
    pub fn set<T: MutData + ?Sized>(&self, data: &mut T, value: u32) {
        // TODO unsafe impl, once I can tell what the native endianness is.
        if let Some(split) = data.get_mut_range(self.index..self.index+4) {
            split[0] = ((value & 0xff000000) >> 24) as u8;
            split[1] = ((value & 0x00ff0000) >> 16) as u8;
            split[2] = ((value & 0x0000ff00) >> 8) as u8;
            split[3] = ((value & 0x000000ff) >> 0) as u8;
        }
    }
}

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

    #[test]
    fn bits0() {
        let data = [0xab, 0xcd];
        let view:&[u8] = &data[..];
        let field = BitField{index:0, mask:0xf0};
        assert_eq!(Some(0xa), field.get(view));
    }
    #[test]
    fn bits1() {
        let data = [0xab, 0xcd];
        let view:&[u8] = &data[..];
        let field = BitField{index:1, mask:0xf0};
        assert_eq!(Some(0xc), field.get(view));
    }
    #[test]
    fn bits1() {
        let data = [0xab, 0xcd];
        let view:&[u8] = &data[..];
        let field = BitField{index:1, mask:0xf0};
        assert_eq!(Some(0xc), field.get(view));
    }
}
<|endoftext|>


<commit_before>
// TODO: add tests
// Valid Values:
// [ us-west-1 | us-west-2 | eu-west-1 | eu-central-1 | ap-southeast-1 | ap-northeast-1 | ap-southeast-2 | sa-east-1 ]
pub fn region_is_valid(region: &str) -> bool {
    match region {
        "us-west-1" => return true,
        "us-west-2" => return true,
        "us-east-1" => return true,
        "eu-west-1" => return true,
        "eu-central-1" => return true,
        "ap-southeast-1" => return true,
        "ap-northeast-1" => return true,
        "ap-southeast-2" => return true,
        "sa-east-1" => return true,
        _ => return false
    }
}

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

	#[test]
	fn valid_regions_are_valid() {
        let valid_regions = vec!["us-west-1", "us-west-2", "eu-west-1", "eu-central-1", "ap-southeast-1", "ap-northeast-1", "ap-southeast-2", "sa-east-1"];
        for region in valid_regions.iter() {
            match region_is_valid(region) {
                true => continue,
                false => panic!("valid region returned as not valid"),
            }
        }
    }

    #[test]
	fn invalid_regions_are_invalid() {
        let valid_regions = vec!["us-west-100", "the-moon", "Jupiter"];
        for region in valid_regions.iter() {
            match region_is_valid(region) {
                true => panic!("invalid region returned as valid, broken!"),
                false => continue,
            }
        }
    }
}
<commit_msg>Removes TODO comment: now done.<commit_after>// Valid Values:
// [ us-west-1 | us-west-2 | eu-west-1 | eu-central-1 | ap-southeast-1 | ap-northeast-1 | ap-southeast-2 | sa-east-1 ]
pub fn region_is_valid(region: &str) -> bool {
    match region {
        "us-west-1" => return true,
        "us-west-2" => return true,
        "us-east-1" => return true,
        "eu-west-1" => return true,
        "eu-central-1" => return true,
        "ap-southeast-1" => return true,
        "ap-northeast-1" => return true,
        "ap-southeast-2" => return true,
        "sa-east-1" => return true,
        _ => return false
    }
}

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

	#[test]
	fn valid_regions_are_valid() {
        let valid_regions = vec!["us-west-1", "us-west-2", "eu-west-1", "eu-central-1", "ap-southeast-1", "ap-northeast-1", "ap-southeast-2", "sa-east-1"];
        for region in valid_regions.iter() {
            match region_is_valid(region) {
                true => continue,
                false => panic!("valid region returned as not valid"),
            }
        }
    }

    #[test]
	fn invalid_regions_are_invalid() {
        let valid_regions = vec!["us-west-100", "the-moon", "Jupiter"];
        for region in valid_regions.iter() {
            match region_is_valid(region) {
                true => panic!("invalid region returned as valid, broken!"),
                false => continue,
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Module for abstractions on drm device nodes

pub(crate) mod constants;

use constants::*;
use libc::dev_t;

use std::{
    fmt::{self, Display, Formatter},
    fs, io,
    os::unix::prelude::{AsRawFd, IntoRawFd, RawFd},
    path::{Path, PathBuf},
};

use nix::{
    sys::stat::{fstat, major, minor, stat},
    unistd::close,
};

/// A node which refers to a DRM device.
#[derive(Debug)]
pub struct DrmNode {
    // Always `Some`, None variant is used when taking ownership
    fd: Option<RawFd>,
    dev: dev_t,
    ty: NodeType,
}

impl DrmNode {
    /// Creates a DRM node from a file descriptor.
    ///
    /// This function takes ownership of the passed in file descriptor, which will be closed when
    /// dropped.
    pub fn from_fd<A: AsRawFd>(fd: A) -> Result<DrmNode, CreateDrmNodeError> {
        let fd = fd.as_raw_fd();
        let stat = fstat(fd).map_err(Into::<io::Error>::into)?;
        let dev = stat.st_rdev;
        let major = major(dev);
        let minor = minor(dev);

        if !is_device_drm(major, minor) {
            return Err(CreateDrmNodeError::NotDrmNode);
        }

        /*
        The type of the DRM node is determined by the minor number ranges.

        0-63 -> Primary
        64-127 -> Control
        128-255 -> Render
        */
        let ty = match minor >> 6 {
            0 => NodeType::Primary,
            1 => NodeType::Control,
            2 => NodeType::Render,
            _ => return Err(CreateDrmNodeError::NotDrmNode),
        };

        Ok(DrmNode {
            fd: Some(fd),
            dev,
            ty,
        })
    }

    /// Returns the type of the DRM node.
    pub fn ty(&self) -> NodeType {
        self.ty
    }

    /// Returns the device_id of the underlying DRM node.
    pub fn dev_id(&self) -> dev_t {
        self.dev
    }

    /// Returns the path of the open device if possible.
    pub fn dev_path(&self) -> Option<PathBuf> {
        node_path(self, self.ty).ok()
    }

    /// Returns the path of the specified node type matching the open device if possible.
    pub fn dev_path_with_type(&self, ty: NodeType) -> Option<PathBuf> {
        node_path(self, ty).ok()
    }

    /// Returns the major device number of the DRM device.
    pub fn major(&self) -> u64 {
        major(self.dev_id())
    }

    /// Returns the minor device number of the DRM device.
    pub fn minor(&self) -> u64 {
        minor(self.dev_id())
    }

    /// Returns whether the DRM device has render nodes.
    pub fn has_render(&self) -> bool {
        #[cfg(target_os = "linux")]
        {
            node_path(self, NodeType::Render).is_ok()
        }

        // TODO: More robust checks on non-linux.
        #[cfg(target_os = "freebsd")]
        {
            false
        }

        #[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
        {
            false
        }
    }
}

impl Display for DrmNode {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{}{}", self.ty.minor_name_prefix(), minor(self.dev_id()))
    }
}

impl IntoRawFd for DrmNode {
    fn into_raw_fd(mut self) -> RawFd {
        self.fd.take().unwrap()
    }
}

impl AsRawFd for DrmNode {
    fn as_raw_fd(&self) -> RawFd {
        self.fd.unwrap()
    }
}

impl Drop for DrmNode {
    fn drop(&mut self) {
        if let Some(fd) = self.fd {
            let _ = close(fd);
        }
    }
}

/// A type of node
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum NodeType {
    /// A primary node may be used to allocate buffers.
    ///
    /// If no other node is present, this may be used to post a buffer to an output with mode-setting.
    Primary,

    /// A control node may be used for mode-setting.
    ///
    /// This is almost never used since no DRM API for control nodes is available yet.
    Control,

    /// A render node may be used by a client to allocate buffers.
    ///
    /// Mode-setting is not possible with a render node.
    Render,
}

impl NodeType {
    /// Returns a string representing the prefix of a minor device's name.
    ///
    /// For example, on Linux with a primary node, the returned string would be `card`.
    pub fn minor_name_prefix(&self) -> &str {
        match self {
            NodeType::Primary => PRIMARY_NAME,
            NodeType::Control => CONTROL_NAME,
            NodeType::Render => RENDER_NAME,
        }
    }
}

impl Display for NodeType {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "{}",
            match self {
                NodeType::Primary => "Primary",
                NodeType::Control => "Control",
                NodeType::Render => "Render",
            }
        )
    }
}

/// An error that may occur when creating a DrmNode from a file descriptor.
#[derive(Debug, thiserror::Error)]
pub enum CreateDrmNodeError {
    /// Some underlying IO error occured while trying to create a DRM node.
    #[error("{0}")]
    Io(io::Error),

    /// The provided file descriptor does not refer to a DRM node.
    #[error("the provided file descriptor does not refer to a DRM node.")]
    NotDrmNode,
}

impl From<io::Error> for CreateDrmNodeError {
    fn from(err: io::Error) -> Self {
        CreateDrmNodeError::Io(err)
    }
}

/// Returns if the given device by major:minor pair is a drm device
#[cfg(target_os = "linux")]
pub fn is_device_drm(major: u64, minor: u64) -> bool {
    let path = format!("/sys/dev/char/{}:{}/device/drm", major, minor);
    stat(path.as_str()).is_ok()
}

/// Returns if the given device by major:minor pair is a drm device
#[cfg(target_os = "freebsd")]
pub fn is_device_drm(major: u64, _minor: u64) -> bool {
    use nix::sys::stat::makedev;
    use nix::sys::stat::SFlag;
    use std::ffi::CStr;
    use std::os::raw::{c_char, c_int};

    let dev_name = Vec::<c_char>::with_capacity(255); // Matching value of SPECNAMELEN in FreeBSD 13+

    let buf: *mut c_char = unsafe {
        libc::devname_r(
            makedev(major, minor),
            SFlag::S_IFCHR.bits(), // Must be S_IFCHR or S_IFBLK
            dev_name.as_mut_ptr(),
            dev_name.len() as c_int,
        )
    };

    // Buffer was too small (weird issue with the size of buffer) or the device could not be named.
    if buf.is_null() {
        return Err(CreateDrmNodeError::NotDrmNode);
    }

    // SAFETY: The buffer written to by devname_r is guaranteed to be NUL terminated.
    let dev_name = unsafe { CStr::from_ptr(buf) };
    let dev_name = dev_name.to_str().expect("Returned device name is not valid utf8");

    dev_name.starts_with("drm/")
        || dev_name.starts_with("dri/card")
        || dev_name.starts_with("dri/control")
        || dev_name.starts_with("dri/renderD")
}

/// Returns if the given device by major:minor pair is a drm device
#[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
pub fn is_device_drm(major: u64, _minor: u64) -> bool {
    major == DRM_MAJOR
}

/// Returns the path of a specific type of node from the same DRM device as another path of the same node.
#[cfg(target_os = "linux")]
pub fn path_to_type<P: AsRef<Path>>(path: P, ty: NodeType) -> io::Result<PathBuf> {
    let stat = stat(path.as_ref()).map_err(Into::<io::Error>::into)?;
    let dev = stat.st_rdev;
    let major = major(dev);
    let minor = minor(dev);

    dev_path(major, minor, ty)
}

/// Returns the path of a specific type of node from the same DRM device as an existing DrmNode.
#[cfg(target_os = "linux")]
pub fn node_path(node: &DrmNode, ty: NodeType) -> io::Result<PathBuf> {
    let major = node.major();
    let minor = node.minor();

    dev_path(major, minor, ty)
}

/// Returns the path of a specific type of node from the DRM device described by major and minor device numbers.
#[cfg(target_os = "linux")]
pub fn dev_path(major: u64, minor: u64, ty: NodeType) -> io::Result<PathBuf> {
    use std::io::ErrorKind;

    if !is_device_drm(major, minor) {
        return Err(io::Error::new(
            ErrorKind::NotFound,
            format!("{}:{} is no DRM device", major, minor),
        ));
    }

    let read = fs::read_dir(format!("/sys/dev/char/{}:{}/device/drm", major, minor))?;

    for entry in read.flatten() {
        let name = entry.file_name();
        let name = name.to_string_lossy();

        // Only 1 primary, control and render node may exist simultaneously, so the
        // first occurrence is good enough.
        if name.starts_with(ty.minor_name_prefix()) {
            let path = [r"/", "dev", "dri", &name].iter().collect::<PathBuf>();
            if path.exists() {
                return Ok(path);
            }
        }
    }

    Err(io::Error::new(
        ErrorKind::NotFound,
        format!(
            "Could not find node of type {} from DRM device {}:{}",
            ty, major, minor
        ),
    ))
}
<commit_msg>drm: Replace inner Option on DrmNode and use mem::forget<commit_after>//! Module for abstractions on drm device nodes

pub(crate) mod constants;

use constants::*;
use libc::dev_t;

use std::{
    fmt::{self, Display, Formatter},
    fs, io, mem,
    os::unix::prelude::{AsRawFd, IntoRawFd, RawFd},
    path::{Path, PathBuf},
};

use nix::{
    sys::stat::{fstat, major, minor, stat},
    unistd::close,
};

/// A node which refers to a DRM device.
#[derive(Debug)]
pub struct DrmNode {
    fd: RawFd,
    dev: dev_t,
    ty: NodeType,
}

impl DrmNode {
    /// Creates a DRM node from a file descriptor.
    ///
    /// This function takes ownership of the passed in file descriptor, which will be closed when
    /// dropped.
    pub fn from_fd<A: AsRawFd>(fd: A) -> Result<DrmNode, CreateDrmNodeError> {
        let fd = fd.as_raw_fd();
        let stat = fstat(fd).map_err(Into::<io::Error>::into)?;
        let dev = stat.st_rdev;
        let major = major(dev);
        let minor = minor(dev);

        if !is_device_drm(major, minor) {
            return Err(CreateDrmNodeError::NotDrmNode);
        }

        /*
        The type of the DRM node is determined by the minor number ranges.

        0-63 -> Primary
        64-127 -> Control
        128-255 -> Render
        */
        let ty = match minor >> 6 {
            0 => NodeType::Primary,
            1 => NodeType::Control,
            2 => NodeType::Render,
            _ => return Err(CreateDrmNodeError::NotDrmNode),
        };

        Ok(DrmNode { fd, dev, ty })
    }

    /// Returns the type of the DRM node.
    pub fn ty(&self) -> NodeType {
        self.ty
    }

    /// Returns the device_id of the underlying DRM node.
    pub fn dev_id(&self) -> dev_t {
        self.dev
    }

    /// Returns the path of the open device if possible.
    pub fn dev_path(&self) -> Option<PathBuf> {
        node_path(self, self.ty).ok()
    }

    /// Returns the path of the specified node type matching the open device if possible.
    pub fn dev_path_with_type(&self, ty: NodeType) -> Option<PathBuf> {
        node_path(self, ty).ok()
    }

    /// Returns the major device number of the DRM device.
    pub fn major(&self) -> u64 {
        major(self.dev_id())
    }

    /// Returns the minor device number of the DRM device.
    pub fn minor(&self) -> u64 {
        minor(self.dev_id())
    }

    /// Returns whether the DRM device has render nodes.
    pub fn has_render(&self) -> bool {
        #[cfg(target_os = "linux")]
        {
            node_path(self, NodeType::Render).is_ok()
        }

        // TODO: More robust checks on non-linux.
        #[cfg(target_os = "freebsd")]
        {
            false
        }

        #[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
        {
            false
        }
    }
}

impl Display for DrmNode {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "{}{}", self.ty.minor_name_prefix(), minor(self.dev_id()))
    }
}

impl IntoRawFd for DrmNode {
    fn into_raw_fd(self) -> RawFd {
        let fd = self.fd;
        mem::forget(self);
        fd
    }
}

impl AsRawFd for DrmNode {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}

impl Drop for DrmNode {
    fn drop(&mut self) {
        let _ = close(self.fd);
    }
}

/// A type of node
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum NodeType {
    /// A primary node may be used to allocate buffers.
    ///
    /// If no other node is present, this may be used to post a buffer to an output with mode-setting.
    Primary,

    /// A control node may be used for mode-setting.
    ///
    /// This is almost never used since no DRM API for control nodes is available yet.
    Control,

    /// A render node may be used by a client to allocate buffers.
    ///
    /// Mode-setting is not possible with a render node.
    Render,
}

impl NodeType {
    /// Returns a string representing the prefix of a minor device's name.
    ///
    /// For example, on Linux with a primary node, the returned string would be `card`.
    pub fn minor_name_prefix(&self) -> &str {
        match self {
            NodeType::Primary => PRIMARY_NAME,
            NodeType::Control => CONTROL_NAME,
            NodeType::Render => RENDER_NAME,
        }
    }
}

impl Display for NodeType {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "{}",
            match self {
                NodeType::Primary => "Primary",
                NodeType::Control => "Control",
                NodeType::Render => "Render",
            }
        )
    }
}

/// An error that may occur when creating a DrmNode from a file descriptor.
#[derive(Debug, thiserror::Error)]
pub enum CreateDrmNodeError {
    /// Some underlying IO error occured while trying to create a DRM node.
    #[error("{0}")]
    Io(io::Error),

    /// The provided file descriptor does not refer to a DRM node.
    #[error("the provided file descriptor does not refer to a DRM node.")]
    NotDrmNode,
}

impl From<io::Error> for CreateDrmNodeError {
    fn from(err: io::Error) -> Self {
        CreateDrmNodeError::Io(err)
    }
}

/// Returns if the given device by major:minor pair is a drm device
#[cfg(target_os = "linux")]
pub fn is_device_drm(major: u64, minor: u64) -> bool {
    let path = format!("/sys/dev/char/{}:{}/device/drm", major, minor);
    stat(path.as_str()).is_ok()
}

/// Returns if the given device by major:minor pair is a drm device
#[cfg(target_os = "freebsd")]
pub fn is_device_drm(major: u64, _minor: u64) -> bool {
    use nix::sys::stat::makedev;
    use nix::sys::stat::SFlag;
    use std::ffi::CStr;
    use std::os::raw::{c_char, c_int};

    let dev_name = Vec::<c_char>::with_capacity(255); // Matching value of SPECNAMELEN in FreeBSD 13+

    let buf: *mut c_char = unsafe {
        libc::devname_r(
            makedev(major, minor),
            SFlag::S_IFCHR.bits(), // Must be S_IFCHR or S_IFBLK
            dev_name.as_mut_ptr(),
            dev_name.len() as c_int,
        )
    };

    // Buffer was too small (weird issue with the size of buffer) or the device could not be named.
    if buf.is_null() {
        return Err(CreateDrmNodeError::NotDrmNode);
    }

    // SAFETY: The buffer written to by devname_r is guaranteed to be NUL terminated.
    let dev_name = unsafe { CStr::from_ptr(buf) };
    let dev_name = dev_name.to_str().expect("Returned device name is not valid utf8");

    dev_name.starts_with("drm/")
        || dev_name.starts_with("dri/card")
        || dev_name.starts_with("dri/control")
        || dev_name.starts_with("dri/renderD")
}

/// Returns if the given device by major:minor pair is a drm device
#[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
pub fn is_device_drm(major: u64, _minor: u64) -> bool {
    major == DRM_MAJOR
}

/// Returns the path of a specific type of node from the same DRM device as another path of the same node.
#[cfg(target_os = "linux")]
pub fn path_to_type<P: AsRef<Path>>(path: P, ty: NodeType) -> io::Result<PathBuf> {
    let stat = stat(path.as_ref()).map_err(Into::<io::Error>::into)?;
    let dev = stat.st_rdev;
    let major = major(dev);
    let minor = minor(dev);

    dev_path(major, minor, ty)
}

/// Returns the path of a specific type of node from the same DRM device as an existing DrmNode.
#[cfg(target_os = "linux")]
pub fn node_path(node: &DrmNode, ty: NodeType) -> io::Result<PathBuf> {
    let major = node.major();
    let minor = node.minor();

    dev_path(major, minor, ty)
}

/// Returns the path of a specific type of node from the DRM device described by major and minor device numbers.
#[cfg(target_os = "linux")]
pub fn dev_path(major: u64, minor: u64, ty: NodeType) -> io::Result<PathBuf> {
    use std::io::ErrorKind;

    if !is_device_drm(major, minor) {
        return Err(io::Error::new(
            ErrorKind::NotFound,
            format!("{}:{} is no DRM device", major, minor),
        ));
    }

    let read = fs::read_dir(format!("/sys/dev/char/{}:{}/device/drm", major, minor))?;

    for entry in read.flatten() {
        let name = entry.file_name();
        let name = name.to_string_lossy();

        // Only 1 primary, control and render node may exist simultaneously, so the
        // first occurrence is good enough.
        if name.starts_with(ty.minor_name_prefix()) {
            let path = [r"/", "dev", "dri", &name].iter().collect::<PathBuf>();
            if path.exists() {
                return Ok(path);
            }
        }
    }

    Err(io::Error::new(
        ErrorKind::NotFound,
        format!(
            "Could not find node of type {} from DRM device {}:{}",
            ty, major, minor
        ),
    ))
}
<|endoftext|>


<commit_before>//! Simple clipboard example
//!
//! From https://developer.gnome.org/gtkmm-tutorial/stable/sec-clipboard-examples.html.en
extern crate gdk;
extern crate gio;
extern crate gtk;

use std::cell::RefCell;
use std::env::args;

use gio::prelude::*;
use gtk::prelude::*;

// make moving clones into closures more convenient
macro_rules! clone {
    (@param _) => ( _ );
    (@param $x:ident) => ( $x );
    ($($n:ident),+ => move || $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move || $body
        }
    );
    ($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move |$(clone!(@param $p),)+| $body
        }
    );
}

struct Ui {
    pub button_a1: gtk::ToggleButton,
    pub button_a2: gtk::ToggleButton,
    pub button_b1: gtk::ToggleButton,
    pub button_b2: gtk::ToggleButton,
}

// Declare a new thread local storage key
thread_local!(
    static GLOBAL: RefCell<Option<Ui>> = RefCell::new(None)
);

fn build_ui(application: &gtk::Application) {
    let window = gtk::ApplicationWindow::new(application);

    // Create the whole window
    window.set_title("gtk::Clipboard Simple Example");
    window.connect_delete_event(clone!(window => move |_, _| {
        window.destroy();
        Inhibit(false)
    }));

    // Create the button grid
    let grid = gtk::Grid::new();
    grid.set_row_homogeneous(true);
    grid.set_column_homogeneous(true);
    let button_a1 = gtk::ToggleButton::new_with_label("A1");
    grid.attach(&button_a1, 0, 0, 1, 1);
    let button_a2 = gtk::ToggleButton::new_with_label("A2");
    grid.attach(&button_a2, 1, 0, 1, 1);
    let button_b1 = gtk::ToggleButton::new_with_label("B1");
    grid.attach(&button_b1, 0, 1, 1, 1);
    let button_b2 = gtk::ToggleButton::new_with_label("B2");
    grid.attach(&button_b2, 1, 1, 1, 1);

    // Add in the action buttons
    let copy_button = gtk::Button::new_with_mnemonic("_Copy");
    let paste_button = gtk::Button::new_with_mnemonic("_Paste");
    let button_box = gtk::ButtonBox::new(gtk::Orientation::Horizontal);
    button_box.set_layout(gtk::ButtonBoxStyle::End);
    button_box.pack_start(&copy_button, false, false, 0);
    button_box.pack_start(&paste_button, false, false, 0);

    // Pack widgets into the window and display everything
    let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
    vbox.set_spacing(6);
    let label = gtk::Label::new(Some(
        "Select cells in the grid, click Copy, then \
         open a second instance of this example to try \
         pasting the copied data.",
    ));
    vbox.pack_start(&label, true, true, 0);
    vbox.pack_start(&grid, true, true, 0);
    vbox.pack_start(&button_box, true, true, 0);
    window.add(&vbox);

    window.show_all();

    // Save out UI in thread-local storage so we can use it in callbacks later
    GLOBAL.with(move |global| {
        *global.borrow_mut() = Some(Ui {
            button_a1: button_a1,
            button_a2: button_a2,
            button_b1: button_b1,
            button_b2: button_b2,
        })
    });

    // Attach signal handlers
    copy_button.connect_clicked(|_| {
        let mut s = String::new();
        GLOBAL.with(|global| {
            if let Some(ref ui) = *global.borrow() {
                if ui.button_a1.get_active() {
                    s.push_str("1");
                } else {
                    s.push_str("0");
                }
                if ui.button_a2.get_active() {
                    s.push_str("1");
                } else {
                    s.push_str("0");
                }
                if ui.button_b1.get_active() {
                    s.push_str("1");
                } else {
                    s.push_str("0");
                }
                if ui.button_b2.get_active() {
                    s.push_str("1");
                } else {
                    s.push_str("0");
                }
            }
        });
        let clipboard = gtk::Clipboard::get(&gdk::SELECTION_CLIPBOARD);
        clipboard.set_text(&s);
    });
    paste_button.connect_clicked(|_| {
        let clipboard = gtk::Clipboard::get(&gdk::SELECTION_CLIPBOARD);
        clipboard.request_text(|_, t| {
            if t.is_some() {
                let t = t.unwrap();
                if t.len() >= 4 {
                    GLOBAL.with(|global| {
                        if let Some(ref ui) = *global.borrow() {
                            ui.button_a1.set_active(t.chars().nth(0).unwrap() == '1');
                            ui.button_a2.set_active(t.chars().nth(1).unwrap() == '1');
                            ui.button_b1.set_active(t.chars().nth(2).unwrap() == '1');
                            ui.button_b2.set_active(t.chars().nth(3).unwrap() == '1');
                        }
                    });
                }
            }
        });
    });
}

fn main() {
    let application = gtk::Application::new(
        Some("org.gtk-rs.example.clipboard_simple"),
        gio::ApplicationFlags::NON_UNIQUE,
    )
    .expect("Initialization failed...");

    application.connect_startup(|app| {
        build_ui(app);
    });
    application.connect_activate(|_| {});

    application.run(&args().collect::<Vec<_>>());
}
<commit_msg>remove useless clone macro usage<commit_after>//! Simple clipboard example
//!
//! From https://developer.gnome.org/gtkmm-tutorial/stable/sec-clipboard-examples.html.en
extern crate gdk;
extern crate gio;
extern crate gtk;

use std::cell::RefCell;
use std::env::args;

use gio::prelude::*;
use gtk::prelude::*;

struct Ui {
    pub button_a1: gtk::ToggleButton,
    pub button_a2: gtk::ToggleButton,
    pub button_b1: gtk::ToggleButton,
    pub button_b2: gtk::ToggleButton,
}

// Declare a new thread local storage key
thread_local!(
    static GLOBAL: RefCell<Option<Ui>> = RefCell::new(None)
);

fn build_ui(application: &gtk::Application) {
    let window = gtk::ApplicationWindow::new(application);

    // Create the whole window
    window.set_title("gtk::Clipboard Simple Example");
    window.connect_delete_event(|window, _| {
        window.destroy();
        Inhibit(false)
    });

    // Create the button grid
    let grid = gtk::Grid::new();
    grid.set_row_homogeneous(true);
    grid.set_column_homogeneous(true);
    let button_a1 = gtk::ToggleButton::new_with_label("A1");
    grid.attach(&button_a1, 0, 0, 1, 1);
    let button_a2 = gtk::ToggleButton::new_with_label("A2");
    grid.attach(&button_a2, 1, 0, 1, 1);
    let button_b1 = gtk::ToggleButton::new_with_label("B1");
    grid.attach(&button_b1, 0, 1, 1, 1);
    let button_b2 = gtk::ToggleButton::new_with_label("B2");
    grid.attach(&button_b2, 1, 1, 1, 1);

    // Add in the action buttons
    let copy_button = gtk::Button::new_with_mnemonic("_Copy");
    let paste_button = gtk::Button::new_with_mnemonic("_Paste");
    let button_box = gtk::ButtonBox::new(gtk::Orientation::Horizontal);
    button_box.set_layout(gtk::ButtonBoxStyle::End);
    button_box.pack_start(&copy_button, false, false, 0);
    button_box.pack_start(&paste_button, false, false, 0);

    // Pack widgets into the window and display everything
    let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
    vbox.set_spacing(6);
    let label = gtk::Label::new(Some(
        "Select cells in the grid, click Copy, then \
         open a second instance of this example to try \
         pasting the copied data.",
    ));
    vbox.pack_start(&label, true, true, 0);
    vbox.pack_start(&grid, true, true, 0);
    vbox.pack_start(&button_box, true, true, 0);
    window.add(&vbox);

    window.show_all();

    // Save out UI in thread-local storage so we can use it in callbacks later
    GLOBAL.with(move |global| {
        *global.borrow_mut() = Some(Ui {
            button_a1: button_a1,
            button_a2: button_a2,
            button_b1: button_b1,
            button_b2: button_b2,
        })
    });

    // Attach signal handlers
    copy_button.connect_clicked(|_| {
        let mut s = String::new();
        GLOBAL.with(|global| {
            if let Some(ref ui) = *global.borrow() {
                if ui.button_a1.get_active() {
                    s.push_str("1");
                } else {
                    s.push_str("0");
                }
                if ui.button_a2.get_active() {
                    s.push_str("1");
                } else {
                    s.push_str("0");
                }
                if ui.button_b1.get_active() {
                    s.push_str("1");
                } else {
                    s.push_str("0");
                }
                if ui.button_b2.get_active() {
                    s.push_str("1");
                } else {
                    s.push_str("0");
                }
            }
        });
        let clipboard = gtk::Clipboard::get(&gdk::SELECTION_CLIPBOARD);
        clipboard.set_text(&s);
    });
    paste_button.connect_clicked(|_| {
        let clipboard = gtk::Clipboard::get(&gdk::SELECTION_CLIPBOARD);
        clipboard.request_text(|_, t| {
            if t.is_some() {
                let t = t.unwrap();
                if t.len() >= 4 {
                    GLOBAL.with(|global| {
                        if let Some(ref ui) = *global.borrow() {
                            ui.button_a1.set_active(t.chars().nth(0).unwrap() == '1');
                            ui.button_a2.set_active(t.chars().nth(1).unwrap() == '1');
                            ui.button_b1.set_active(t.chars().nth(2).unwrap() == '1');
                            ui.button_b2.set_active(t.chars().nth(3).unwrap() == '1');
                        }
                    });
                }
            }
        });
    });
}

fn main() {
    let application = gtk::Application::new(
        Some("org.gtk-rs.example.clipboard_simple"),
        gio::ApplicationFlags::NON_UNIQUE,
    )
    .expect("Initialization failed...");

    application.connect_startup(|app| {
        build_ui(app);
    });
    application.connect_activate(|_| {});

    application.run(&args().collect::<Vec<_>>());
}
<|endoftext|>


<commit_before><commit_msg>remove . in line comment<commit_after><|endoftext|>


<commit_before>#![feature(type_alias_enum_variants)]

mod lexer;
mod token;
mod repl;
mod ast;
mod parser;
mod evaluation {
    pub mod object;
    pub mod evaluator;
    pub mod environment;
}
mod core {
    pub mod funcs;
}

fn main() {
    // how to get current user name in crossplatform style?
    let _username = "user".to_string();
    println!("Dear user, welcome to Renard REPL!");
    println!("Some more advanced description of what's going on here");
    repl::start();
}
<commit_msg>[repl] remove redundant line<commit_after>#![feature(type_alias_enum_variants)]

mod lexer;
mod token;
mod repl;
mod ast;
mod parser;
mod evaluation {
    pub mod object;
    pub mod evaluator;
    pub mod environment;
}
mod core {
    pub mod funcs;
}

fn main() {
    // how to get current user name in crossplatform style?
    let _username = "user".to_string();
    println!("Dear user, welcome to Renard REPL!");
    repl::start();
}
<|endoftext|>


<commit_before>/*
* rust-clean - Copyright (c) 2014 Gomez Guillaume.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim
*    that you wrote the original software. If you use this software in a product,
*    an acknowledgment in the product documentation would be appreciated but is
*    not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
*    misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/

use std::io::fs;
use std::os;
use std::path::posix::Path;

struct CleanOptions {
    recursive: bool,
    verbose: bool,
    confirmation: bool
}

fn ask_confirmation(file: &Path) -> bool {
    loop {
        print!("clean: remove \x1b[37;1m'{}'\x1b[0m (y/n) ? ", file.as_str().unwrap());
        match std::io::stdio::stdin().read_line() {
            Ok(s) => {
                let tmp_s = s.replace("\r\n", "").replace("\n", "");

                if tmp_s.as_slice() == "y" || tmp_s.as_slice() == "yes" {
                    return true;
                } else if tmp_s.as_slice() == "n" || tmp_s.as_slice() == "no" {
                    return false;
                }
            }
            Err(_) => {}
        }
    }
}

fn start_clean(options: &CleanOptions, entry: &Path) {
    if entry.exists() {
        if entry.is_dir() {
            if options.recursive || entry.as_str().unwrap() == "." {
                match fs::readdir(entry) {
                    Ok(res) => {
                        if options.verbose {
                            println!("\x1b[36;1m-> Entering {}\x1b[0m", entry.as_str().unwrap());
                        }
                        for tmp in res.iter() {
                            start_clean(options, tmp);
                        }
                        if options.verbose {
                            println!("\x1b[34;1m<- Leaving {}\x1b[0m", entry.as_str().unwrap());
                        }
                    }
                    Err(e) => {
                        println!("\x1b[31;1mProblem with this directory: {} -> {}\x1b[0m", entry.as_str().unwrap(), e);
                    }
                }
            }
        } else {
            match entry.filename() {
                Some(s) => {
                    if s.last().unwrap() == &('~' as u8) {
                        if !options.confirmation || ask_confirmation(&Path::new(s)) {
                            match fs::unlink(entry) {
                                Ok(_) => {
                                    if options.verbose {
                                        println!("\x1b[32;1m{} deleted\x1b[0m", entry.as_str().unwrap());
                                    }
                                }
                                Err(e) => {
                                    println!("\x1b[31;1mProblem with this file: {} -> {}\x1b[0m", entry.as_str().unwrap(), e);
                                }
                            }
                        }
                    }
                }
                None => {
                    println!("\x1b[31;1mProblem with this file: {}\x1b[0m", entry.as_str().unwrap());
                }
            }
        }
    } else {
        println!("\x1b[31;1mProblem with this entry: {}\x1b[0m", entry.as_str().unwrap());
    }
}

fn print_help() {
    println!("./clean [options] [files | dirs]");
    println!("    -r : recursive mode");
    println!("    -v : verbose mode");
    println!("    -i : prompt before every removal");
    println!("--help : print this help");
}

fn main() {
    let mut args = os::args().clone();
    let mut options = CleanOptions{recursive: false, verbose: false, confirmation: false};
    let mut files = Vec::new();

    args.remove(0);
    for tmp in args.iter() {
        if tmp.clone().into_bytes().get(0) == &('-' as u8) {
            let mut tmp_arg = String::from_str(tmp.as_slice());

            tmp_arg.shift_char();
            if tmp_arg.len() > 0 {
                for character in tmp_arg.into_bytes().iter() {
                    match *character as char {
                        '-' => {
                            if tmp.as_slice() == "--help" {
                                print_help();
                                return;
                            }
                        }
                        'r' => {
                            options.recursive = true;
                        }
                        'v' => {
                            options.verbose = true;
                        }
                        'i' => {
                            options.confirmation = true;
                        }
                        _ => {
                            fail!("Unknown option: '{}', to have the options list, please launch with '-h' option\n", character);
                        }
                    }
                }
            } else {
                files.push(Path::new(tmp.as_slice()));
            }
        }
    }
    if files.len() == 0 {
        files.push(Path::new(String::from_str(".").as_slice()));
    }
    if options.verbose {
        println!("\x1b[33;1m=== VERBOSE MODE ===\x1b[0m");
    }
    for tmp in files.iter() {
        start_clean(&options, tmp);
    }
    if options.verbose {
        println!("\x1b[33;1mEnd of execution\x1b[0m");
    }
}<commit_msg>Update to last rust compiler version<commit_after>/*
* rust-clean - Copyright (c) 2014 Gomez Guillaume.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim
*    that you wrote the original software. If you use this software in a product,
*    an acknowledgment in the product documentation would be appreciated but is
*    not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
*    misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/

use std::io::fs;
use std::os;
use std::path::posix::Path;

struct CleanOptions {
    recursive: bool,
    verbose: bool,
    confirmation: bool
}

fn ask_confirmation(file: &Path) -> bool {
    loop {
        print!("clean: remove \x1b[37;1m'{}'\x1b[0m (y/n) ? ", file.as_str().unwrap());
        match std::io::stdio::stdin().read_line() {
            Ok(s) => {
                let tmp_s = s.replace("\r\n", "").replace("\n", "");

                if tmp_s.as_slice() == "y" || tmp_s.as_slice() == "yes" {
                    return true;
                } else if tmp_s.as_slice() == "n" || tmp_s.as_slice() == "no" {
                    return false;
                }
            }
            Err(_) => {}
        }
    }
}

fn start_clean(options: &CleanOptions, entry: &Path) {
    if entry.exists() {
        if entry.is_dir() {
            if options.recursive || entry.as_str().unwrap() == "." {
                match fs::readdir(entry) {
                    Ok(res) => {
                        if options.verbose {
                            println!("\x1b[36;1m-> Entering {}\x1b[0m", entry.as_str().unwrap());
                        }
                        for tmp in res.iter() {
                            start_clean(options, tmp);
                        }
                        if options.verbose {
                            println!("\x1b[34;1m<- Leaving {}\x1b[0m", entry.as_str().unwrap());
                        }
                    }
                    Err(e) => {
                        println!("\x1b[31;1mProblem with this directory: {} -> {}\x1b[0m", entry.as_str().unwrap(), e);
                    }
                }
            }
        } else {
            match entry.filename() {
                Some(s) => {
                    if s.last().unwrap() == &('~' as u8) {
                        if !options.confirmation || ask_confirmation(&Path::new(s)) {
                            match fs::unlink(entry) {
                                Ok(_) => {
                                    if options.verbose {
                                        println!("\x1b[32;1m{} deleted\x1b[0m", entry.as_str().unwrap());
                                    }
                                }
                                Err(e) => {
                                    println!("\x1b[31;1mProblem with this file: {} -> {}\x1b[0m", entry.as_str().unwrap(), e);
                                }
                            }
                        }
                    }
                }
                None => {
                    println!("\x1b[31;1mProblem with this file: {}\x1b[0m", entry.as_str().unwrap());
                }
            }
        }
    } else {
        println!("\x1b[31;1mProblem with this entry: {}\x1b[0m", entry.as_str().unwrap());
    }
}

fn print_help() {
    println!("./clean [options] [files | dirs]");
    println!("    -r : recursive mode");
    println!("    -v : verbose mode");
    println!("    -i : prompt before every removal");
    println!("--help : print this help");
}

fn main() {
    let mut args = os::args().clone();
    let mut options = CleanOptions{recursive: false, verbose: false, confirmation: false};
    let mut files = Vec::new();

    args.remove(0);
    for tmp in args.iter() {
        if tmp.clone().into_bytes()[0] == '-' as u8 {
            let mut tmp_arg = String::from_str(tmp.as_slice());

            tmp_arg.shift_char();
            if tmp_arg.len() > 0 {
                for character in tmp_arg.into_bytes().iter() {
                    match *character as char {
                        '-' => {
                            if tmp.as_slice() == "--help" {
                                print_help();
                                return;
                            }
                        }
                        'r' => {
                            options.recursive = true;
                        }
                        'v' => {
                            options.verbose = true;
                        }
                        'i' => {
                            options.confirmation = true;
                        }
                        _ => {
                            fail!("Unknown option: '{}', to have the options list, please launch with '-h' option\n", character);
                        }
                    }
                }
            } else {
                files.push(Path::new(tmp.as_slice()));
            }
        }
    }
    if files.len() == 0 {
        files.push(Path::new(String::from_str(".").as_slice()));
    }
    if options.verbose {
        println!("\x1b[33;1m=== VERBOSE MODE ===\x1b[0m");
    }
    for tmp in files.iter() {
        start_clean(&options, tmp);
    }
    if options.verbose {
        println!("\x1b[33;1mEnd of execution\x1b[0m");
    }
}<|endoftext|>


<commit_before>//! Implementation of a simple uTP client and server.
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate getopts;
extern crate daemonize;
extern crate udt;
extern crate crypto;
extern crate byteorder;
extern crate rand;
extern crate sodiumoxide;
extern crate rustc_serialize;

use daemonize::{Daemonize};
use std::process;
use std::process::Command;
use std::thread;
use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr};
use std::net;
use std::str;
use std::env;
use std::fs::File;
use std::str::FromStr;
use std::path::Path;
use std::ffi::OsStr;
use std::io;
use std::io::{Cursor, Error, Seek, SeekFrom, ErrorKind, stdin, stdout, stderr, Read, Write};
use getopts::Options;
use crypto::{blake2b};
use udt::*;
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian};
use sodiumoxide::crypto::secretbox;
use sodiumoxide::crypto::secretbox::xsalsa20poly1305::Key;
use rustc_serialize::hex::{FromHex, ToHex};

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options] REMOTE-LOCATION", program);
    print!("{}", opts.usage(&brief));
}

fn send_file(stream: UdtSocket, filename: &str) -> Result<(), Error> {
    let mut f = File::open(filename).unwrap();

    let mut filesize = 0u64;
    let mut buf = vec![0; 1024 * 1024];
    loop {
        match try!(f.read(&mut buf)) {
            0    => { break },
            read => { filesize += read as u64 },
        }
    }

    let mut wtr = vec![];
    wtr.write_u64::<LittleEndian>(filesize).unwrap();
    match stream.sendmsg(&wtr[..]) {
        Ok(0) => {
            return Err(Error::new(ErrorKind::WriteZero, "failed to write filesize header before timeout"))
        },
        Err(e) => {
            return Err(Error::new(ErrorKind::Other, format!("{:?}", e)))
        }
        _ => {
            // println!("wrote filesize of {:.2}kb.", filesize as f64 / 1024f64);
        }
    }
    let mut total = 0;
    let mut payload = vec![0; 1300];
    f.seek(SeekFrom::Start(0));
    loop {
        match f.read(&mut payload) {
            Ok(0) => {
                // println!("\nEOF.");
                stream.sendmsg(&vec![0;0]);
                break;
            }
            Ok(read) => {
                match stream.sendmsg(&payload[0..read]) {
                    Ok(written) => {
                        total += written;
                        // print!("\rwritten {}kb / {}kb ({:.1}%)", total/1024, filesize/1024, (total as f64/1024f64) / (filesize as f64/1024f64) * 100f64);
                    },
                    Err(e) => {
                        stream.close().expect("Error closing stream");
                        // panic!("{:?}", e);
                    }
                }
            },
            Err(e) => {
                stream.close().expect("Error closing stream");
                // panic!("{}", e);
            }
        }
    }

    stream.close().expect("Error closing stream.");
    // println!("all done!");
    Ok(())
}

fn recv_file(sock: UdtSocket, filesize: u64, filename: &str) -> Result<(), Error> {
    let mut f = File::create(filename).unwrap();
    let mut total = 0u64;
    loop {
        let buf = try!(sock.recvmsg(1300).map_err(|e| Error::new(ErrorKind::Other, format!("{:?}", e))));
        total += buf.len() as u64;
        f.write_all(&buf[..]);
        print!("\rreceived {}kb / {}kb ({:.1}%)", total/1024, filesize/1024, (total as f64/1024f64) / (filesize as f64/1024f64) * 100f64);
        if total >= filesize {
            println!("\nEOF");
            break;
        }
    }
    sock.close();
    Ok(())
}

fn main() {

    // This example may run in either server or client mode.
    // Using an enum tends to make the code cleaner and easier to read.
    enum Mode {Server, Client}

    // Start logging
    env_logger::init().expect("Error starting logger");

    // Fetch arguments
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    // opts.optopt("o", "output", "set output file name", "NAME");
    opts.optflag("s", "server", "server mode");
    opts.optflag("p", "port-range", "server listening port range");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };

    // Parse the mode argument
    let mode: Mode = match matches.opt_present("s") {
        true => Mode::Server,
        false => Mode::Client
    };

    match mode {
        Mode::Server => {
            let key = secretbox::gen_key();
            match key {
                Key(keybytes) => { println!("{}", keybytes.to_hex()) }
            }

            udt::init();
            let sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
            sock.setsockopt(UdtOpts::UDP_RCVBUF, 5590000i32);
            sock.setsockopt(UdtOpts::UDP_SNDBUF, 5590000i32);
            sock.bind(SocketAddr::V4(SocketAddrV4::from_str("0.0.0.0:55000").unwrap())).unwrap();
            let my_addr = sock.getsockname().unwrap();
            // dbg(format!("Server bound to {:?}", my_addr));

            sock.listen(1).unwrap();

            let (mut stream, peer) = sock.accept().unwrap();
            // dbg(format!("Received new connection from peer {:?}", peer));

            let daemonize = Daemonize::new();
            match daemonize.start() {
                Ok(_) => { let _ = writeln!(&mut stderr(), "daemonized"); }
                Err(e) => { let _ = writeln!(&mut stderr(), "RWRWARWARARRR"); }
            }

            let mut clientversion = vec![0; 1];
            if let Ok(version) = stream.recvmsg(1) {
                // dbg(format!("frand using protocol version {}.", version[0]));
                if version[0] == 0x00 {
                    send_file(stream, &input);
                } else {
                    panic!("Unrecognized version.");
                }
            } else {
                panic!("Failed to receive version byte from client.");
            }
        }
        Mode::Client => {
            let sections: Vec<&str> = input.split(":").collect();
            let addr: String = sections[0].to_owned();
            let path: String = sections[1].to_owned();
            let cmd = format!("~/bin/shoop -s {}", path);
            println!("addr: {}, path: {}, cmd: {}", addr, path, cmd);

            let output = Command::new("ssh")
                                 .arg(addr.to_owned())
                                 .arg(cmd)
                                 .output()
                                 .unwrap_or_else(|e| {
                                     panic!("failed to execute process: {}", e);
                                 });
            let key = String::from_utf8_lossy(&output.stdout).trim().to_owned();
            println!("got key {}", key);

            // Create a stream and try to connect to the remote address
            //println!("shoop server told us to connect to {}", udp_addr);
            //udt::init();
            //let sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
            //sock.setsockopt(UdtOpts::UDP_RCVBUF, 5590000i32);
            //sock.setsockopt(UdtOpts::UDP_SNDBUF, 5590000i32);
            //let addr: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from_str(&addr).unwrap(), 55000));
            //sock.bind(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from_str("0.0.0.0").unwrap(), 0)));
            //match sock.connect(addr) {
            //    Ok(()) => {
            //        println!("connected!");
            //    },
            //    Err(e) => {
            //        panic!("errrrrrrr {:?}", e);
            //    }
            //}

            //sock.sendmsg(&[0u8; 1]);
            //println!("checking if server is frand");

            //match sock.recvmsg(8) {
            //    Ok(msg) => {
            //        if msg.len() == 0 {
            //            panic!("failed to get filesize from server, probable timeout.");
            //        }
            //        let mut rdr = Cursor::new(msg);
            //        let filesize = rdr.read_u64::<LittleEndian>().unwrap();
            //        println!("got reported filesize of {}", filesize);
            //        let filename = Path::new(&path).file_name().unwrap_or(OsStr::new("outfile")).to_str().unwrap_or("outfile");
            //        println!("writing to {}", filename);
            //        recv_file(sock, filesize, filename);
            //    }
            //    Err(e) => {
            //        panic!("{:?}", e);
            //    }
            //}
        }
    }
}

<commit_msg>except daemonize the right way<commit_after>//! Implementation of a simple uTP client and server.
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate getopts;
extern crate daemonize;
extern crate udt;
extern crate crypto;
extern crate byteorder;
extern crate rand;
extern crate sodiumoxide;
extern crate rustc_serialize;

use daemonize::{Daemonize};
use std::process;
use std::process::Command;
use std::thread;
use std::net::{SocketAddr, SocketAddrV4, Ipv4Addr};
use std::net;
use std::str;
use std::env;
use std::fs::File;
use std::str::FromStr;
use std::path::Path;
use std::ffi::OsStr;
use std::io;
use std::io::{Cursor, Error, Seek, SeekFrom, ErrorKind, stdin, stdout, stderr, Read, Write};
use getopts::Options;
use crypto::{blake2b};
use udt::*;
use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian};
use sodiumoxide::crypto::secretbox;
use sodiumoxide::crypto::secretbox::xsalsa20poly1305::Key;
use rustc_serialize::hex::{FromHex, ToHex};

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options] REMOTE-LOCATION", program);
    print!("{}", opts.usage(&brief));
}

fn send_file(stream: UdtSocket, filename: &str) -> Result<(), Error> {
    let mut f = File::open(filename).unwrap();

    let mut filesize = 0u64;
    let mut buf = vec![0; 1024 * 1024];
    loop {
        match try!(f.read(&mut buf)) {
            0    => { break },
            read => { filesize += read as u64 },
        }
    }

    let mut wtr = vec![];
    wtr.write_u64::<LittleEndian>(filesize).unwrap();
    match stream.sendmsg(&wtr[..]) {
        Ok(0) => {
            return Err(Error::new(ErrorKind::WriteZero, "failed to write filesize header before timeout"))
        },
        Err(e) => {
            return Err(Error::new(ErrorKind::Other, format!("{:?}", e)))
        }
        _ => {
            // println!("wrote filesize of {:.2}kb.", filesize as f64 / 1024f64);
        }
    }
    let mut total = 0;
    let mut payload = vec![0; 1300];
    f.seek(SeekFrom::Start(0));
    loop {
        match f.read(&mut payload) {
            Ok(0) => {
                // println!("\nEOF.");
                stream.sendmsg(&vec![0;0]);
                break;
            }
            Ok(read) => {
                match stream.sendmsg(&payload[0..read]) {
                    Ok(written) => {
                        total += written;
                        // print!("\rwritten {}kb / {}kb ({:.1}%)", total/1024, filesize/1024, (total as f64/1024f64) / (filesize as f64/1024f64) * 100f64);
                    },
                    Err(e) => {
                        stream.close().expect("Error closing stream");
                        // panic!("{:?}", e);
                    }
                }
            },
            Err(e) => {
                stream.close().expect("Error closing stream");
                // panic!("{}", e);
            }
        }
    }

    stream.close().expect("Error closing stream.");
    // println!("all done!");
    Ok(())
}

fn recv_file(sock: UdtSocket, filesize: u64, filename: &str) -> Result<(), Error> {
    let mut f = File::create(filename).unwrap();
    let mut total = 0u64;
    loop {
        let buf = try!(sock.recvmsg(1300).map_err(|e| Error::new(ErrorKind::Other, format!("{:?}", e))));
        total += buf.len() as u64;
        f.write_all(&buf[..]);
        print!("\rreceived {}kb / {}kb ({:.1}%)", total/1024, filesize/1024, (total as f64/1024f64) / (filesize as f64/1024f64) * 100f64);
        if total >= filesize {
            println!("\nEOF");
            break;
        }
    }
    sock.close();
    Ok(())
}

fn main() {

    // This example may run in either server or client mode.
    // Using an enum tends to make the code cleaner and easier to read.
    enum Mode {Server, Client}

    // Start logging
    env_logger::init().expect("Error starting logger");

    // Fetch arguments
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let mut opts = Options::new();
    // opts.optopt("o", "output", "set output file name", "NAME");
    opts.optflag("s", "server", "server mode");
    opts.optflag("p", "port-range", "server listening port range");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    let input = if !matches.free.is_empty() {
        matches.free[0].clone()
    } else {
        print_usage(&program, opts);
        return;
    };

    // Parse the mode argument
    let mode: Mode = match matches.opt_present("s") {
        true => Mode::Server,
        false => Mode::Client
    };

    match mode {
        Mode::Server => {
            let key = secretbox::gen_key();
            match key {
                Key(keybytes) => { println!("{}", keybytes.to_hex()) }
            }

            let daemonize = Daemonize::new();
            match daemonize.start() {
                Ok(_) => { let _ = writeln!(&mut stderr(), "daemonized"); }
                Err(e) => { let _ = writeln!(&mut stderr(), "RWRWARWARARRR"); }
            }

            udt::init();
            let sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
            sock.setsockopt(UdtOpts::UDP_RCVBUF, 5590000i32);
            sock.setsockopt(UdtOpts::UDP_SNDBUF, 5590000i32);
            sock.bind(SocketAddr::V4(SocketAddrV4::from_str("0.0.0.0:55000").unwrap())).unwrap();
            let my_addr = sock.getsockname().unwrap();
            // dbg(format!("Server bound to {:?}", my_addr));

            sock.listen(1).unwrap();

            let (mut stream, peer) = sock.accept().unwrap();
            // dbg(format!("Received new connection from peer {:?}", peer));

            let mut clientversion = vec![0; 1];
            if let Ok(version) = stream.recvmsg(1) {
                // dbg(format!("frand using protocol version {}.", version[0]));
                if version[0] == 0x00 {
                    send_file(stream, &input);
                } else {
                    panic!("Unrecognized version.");
                }
            } else {
                panic!("Failed to receive version byte from client.");
            }
        }
        Mode::Client => {
            let sections: Vec<&str> = input.split(":").collect();
            let addr: String = sections[0].to_owned();
            let path: String = sections[1].to_owned();
            let cmd = format!("~/bin/shoop -s {}", path);
            println!("addr: {}, path: {}, cmd: {}", addr, path, cmd);

            let output = Command::new("ssh")
                                 .arg(addr.to_owned())
                                 .arg(cmd)
                                 .output()
                                 .unwrap_or_else(|e| {
                                     panic!("failed to execute process: {}", e);
                                 });
            let key = String::from_utf8_lossy(&output.stdout).trim().to_owned();
            println!("got key {}", key);

            // Create a stream and try to connect to the remote address
            //println!("shoop server told us to connect to {}", udp_addr);
            //udt::init();
            //let sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap();
            //sock.setsockopt(UdtOpts::UDP_RCVBUF, 5590000i32);
            //sock.setsockopt(UdtOpts::UDP_SNDBUF, 5590000i32);
            //let addr: SocketAddr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from_str(&addr).unwrap(), 55000));
            //sock.bind(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from_str("0.0.0.0").unwrap(), 0)));
            //match sock.connect(addr) {
            //    Ok(()) => {
            //        println!("connected!");
            //    },
            //    Err(e) => {
            //        panic!("errrrrrrr {:?}", e);
            //    }
            //}

            //sock.sendmsg(&[0u8; 1]);
            //println!("checking if server is frand");

            //match sock.recvmsg(8) {
            //    Ok(msg) => {
            //        if msg.len() == 0 {
            //            panic!("failed to get filesize from server, probable timeout.");
            //        }
            //        let mut rdr = Cursor::new(msg);
            //        let filesize = rdr.read_u64::<LittleEndian>().unwrap();
            //        println!("got reported filesize of {}", filesize);
            //        let filename = Path::new(&path).file_name().unwrap_or(OsStr::new("outfile")).to_str().unwrap_or("outfile");
            //        println!("writing to {}", filename);
            //        recv_file(sock, filesize, filename);
            //    }
            //    Err(e) => {
            //        panic!("{:?}", e);
            //    }
            //}
        }
    }
}

<|endoftext|>