<commit_before>//! The loader module
//!
//! Provides the Loader struct which is used to read data into
//! DataTables.

use std::io;
use std::io::prelude::*;
use std::io::{BufReader, Error, ErrorKind};
use std::fs::File;
use datatable::*;

/// Loader struct
///
/// Used to load and process data files into tables.
pub struct Loader<'a> {
    /// True if there are headers present in the file
    pub has_header: bool,
    file: &'a str,
    /// The delimiter character
    pub delimiter: char,
}

impl<'a> Loader<'a> {
    /// Constructs a new Loader.
    pub fn new(has_header: bool, file: &str, delimiter: char) -> Loader {
        Loader {
            has_header: has_header,
            file: file,
            delimiter: delimiter,
        }
    }

    /// Creates a loader with default settings from a file string.
    ///
    /// The default settings are as follows:
    ///
    /// - has_header : false
    /// - delimiter : ','
    pub fn from_file_string(file_string: &str) -> Loader {
        Loader {
            has_header: false,
            file: file_string,
            delimiter: ',',
        }
    }

    /// Load the file from the loader with given delimiter.
    ///
    /// Pretty rudimentary with poor error handling.
    ///
    /// # Panics
    ///
    /// - The input data is not a float.
    ///
    /// # Failures
    ///
    /// - The input data is malformed (missing data, non-uniform rows etc.)
    pub fn load_file(self) -> Result<DataTable, io::Error> {
        let f = try!(File::open(self.file));
        let reader = BufReader::new(f);

        let mut table = DataTable::empty();

        let mut lines = reader.lines();

        if self.has_header {
            if let Some(line) = lines.next() {
                let line = try!(line);
                let values = line.split(self.delimiter);

                for val in values {
                    let mut column = DataColumn::empty();
                    column.name = Some(val.to_owned());
                    table.data_cols.push(column);
                }
            }
        } else {
            if let Some(line) = lines.next() {
                let line = try!(line);
                let values = line.split(self.delimiter);

                for val in values {
                    let mut column = DataColumn::empty();
                    column.push(val);

                    table.data_cols.push(column);
                }
            }
        }

        for line in lines {
            let line = try!(line);
            let values = line.split(self.delimiter);

            let mut idx = 0usize;

            for (i, val) in values.enumerate() {
                idx = i;
                if idx > table.cols() {
                    return Err(Error::new(ErrorKind::InvalidInput, "Malformed data format."));
                }

                table.data_cols[idx].push(val);
            }

            if idx != table.cols() - 1 {
                return Err(Error::new(ErrorKind::InvalidInput, "Malformed data format."));
            }
        }

        table.shrink_to_fit();
        Ok(table)
    }
}

/// Load the specified file to a DataTable.
///
/// # Examples
///
/// ```no_run
/// use rusty_data::loader::load_file;
///
/// let table = load_file("path/to/file.data");
/// ```
pub fn load_file(file: &str) -> DataTable {
    let loader = Loader {
        has_header: false,
        file: file,
        delimiter: ',',
    };

    loader.load_file().unwrap()

}
<commit_msg>Implementing options and advanced line stripping<commit_after>//! The loader module
//!
//! Provides the Loader struct which is used to read data into
//! DataTables.

use std::io;
use std::io::prelude::*;
use std::io::{BufReader, Error, ErrorKind};
use std::fs::File;

use datatable::*;

pub struct LoaderOptions {
    /// True if there are headers present in the file
    pub has_header: bool,
    /// The delimiter character
    pub delimiter: char,
    /// The quote character
    pub quote_marker: Option<char>,
}

impl Default for LoaderOptions {
    fn default() -> LoaderOptions {
        LoaderOptions {
            has_header: false,
            delimiter: ',',
            quote_marker: None,
        }
    }
}
/// Loader struct
///
/// Used to load and process data files into tables.
pub struct Loader<'a> {
    file: &'a str,
    options: LoaderOptions,
}

impl<'a> Loader<'a> {
    /// Constructs a new Loader.
    pub fn new(has_header: bool, file: &str, delimiter: char) -> Loader {
        let options = LoaderOptions {
            has_header: has_header,
            delimiter: delimiter,
            quote_marker: None,
        };

        Loader {
            file: file,
            options: options,
        }
    }

    /// Creates a loader with default settings from a file string.
    ///
    /// The default settings are as follows:
    ///
    /// - has_header : false
    /// - delimiter : ','
    pub fn from_file_string(file_string: &str) -> Loader {
        Loader {
            file: file_string,
            options: LoaderOptions::default(),
        }
    }

    /// Load the file from the loader with given delimiter.
    ///
    /// Pretty rudimentary with poor error handling.
    ///
    /// # Panics
    ///
    /// - The input data is not a float.
    ///
    /// # Failures
    ///
    /// - The input data is malformed (missing data, non-uniform rows etc.)
    pub fn load_file(self) -> Result<DataTable, io::Error> {
        let f = try!(File::open(self.file));
        let reader = BufReader::new(f);

        let mut table = DataTable::empty();

        let mut lines = reader.lines();

        if self.options.has_header {
            if let Some(line) = lines.next() {
                let line = try!(line);
                let values = LineSplitIter::new(line.to_string(),
                                                self.options.quote_marker,
                                                self.options.delimiter);

                for val in values {
                    let mut column = DataColumn::empty();
                    column.name = Some(val);
                    table.data_cols.push(column);
                }
            }
        } else {
            if let Some(line) = lines.next() {
                let line = try!(line);
                let values = LineSplitIter::new(line.to_string(),
                                                self.options.quote_marker,
                                                self.options.delimiter);

                for val in values {
                    let mut column = DataColumn::empty();
                    column.push(val);

                    table.data_cols.push(column);
                }
            }
        }

        for line in lines {
            let line = try!(line);
            let values = LineSplitIter::new(line.to_string(),
                                                self.options.quote_marker,
                                                self.options.delimiter);

            let mut idx = 0usize;

            for (i, val) in values.enumerate() {
                idx = i;
                if idx > table.cols() {
                    return Err(Error::new(ErrorKind::InvalidInput, "Malformed data format."));
                }

                table.data_cols[idx].push(val);
            }

            if idx != table.cols() - 1 {
                return Err(Error::new(ErrorKind::InvalidInput, "Malformed data format."));
            }
        }

        table.shrink_to_fit();
        Ok(table)
    }
}

pub struct LineSplitIter {
    line: String,
    quote_char: Option<char>,
    delimiter: char,
}

impl LineSplitIter {
    pub fn new(line: String, quote_char: Option<char>, delimiter: char) -> LineSplitIter {
        LineSplitIter {
            line: line,
            quote_char: quote_char,
            delimiter: delimiter,
        }
    }
}

impl Iterator for LineSplitIter {
    type Item = String;

    fn next(&mut self) -> Option<Self::Item> {
        if self.line.len() == 0 {
            return None;
        }

        let drain_offset: Option<usize>;
        if let Some(quote_char) = self.quote_char {
            let mut in_quotes = false;

            drain_offset = self.line
                               .find(|c| {
                                   if c == quote_char {
                                       in_quotes = !in_quotes;
                                       false
                                   } else if c == self.delimiter && !in_quotes {
                                       true
                                   } else {
                                       false
                                   }
                               });

        } else {
            drain_offset = self.line.find(self.delimiter);
        }

        if let Some(offset) = drain_offset {
            let t: String = self.line.drain(..offset).collect();
            self.line = self.line[1..].to_string();

            match self.quote_char {
                None => Some(t),
                Some(quote_char) => Some(t.trim_matches(quote_char).to_string()),
            }
        } else {
            Some(self.line.drain(..).collect())
        }
    }
}

/// Load the specified file to a DataTable.
///
/// # Examples
///
/// ```no_run
/// use rusty_data::loader::load_file;
///
/// let table = load_file("path/to/file.data");
/// ```
pub fn load_file(file: &str) -> DataTable {
    let loader = Loader::from_file_string(file);

    loader.load_file().unwrap()

}
<|endoftext|>


<commit_before>use std;
use std::{ mem, slice, string };
use handle::Owned;
use raw;
use raw::{ IV, UV, NV };
use raw::{ SVt_PVAV, SVt_PVHV, SVt_PVCV, SVt_PVGV };
use array::{ AV };
use hash::{ HV };
use convert::{ IntoSV, FromSV, TryFromSV };

/// Perl scalar object.
pub struct SV(Owned<raw::SV>);

impl SV {
    method! {
        /// Return true if SV is a real scalar value.
        simple fn is_scalar() -> bool = sv_type() < SVt_PVAV
    }
    method! {
        /// Return true if SV contains array.
        simple fn is_array() -> bool = sv_type() == SVt_PVAV
    }
    method! {
        /// Return true if SV contains hash.
        simple fn is_hash() -> bool = sv_type() == SVt_PVHV
    }
    method! {
        /// Return true if SV contains subroutine.
        simple fn is_code() -> bool = sv_type() == SVt_PVCV
    }
    method! {
        /// Return true if SV contains glob.
        simple fn is_glob() -> bool = sv_type() == SVt_PVGV
    }
    method! {
        /// Return true if SV is defined.
        ///
        /// [`SvOK`](http://perldoc.perl.org/perlapi.html#SvOK).
        simple fn ok() -> bool = sv_ok() != 0
    }
    method! {
        /// Return true if SV contains a signed integer.
        ///
        /// Perl macro:[`SvIOK`](http://perldoc.perl.org/perlapi.html#SvIOK).
        simple fn iv_ok() -> bool = sv_iok() != 0
    }
    method! {
        /// Coerce the given SV to an integer and return it.
        ///
        /// Perl macro: [`SvIV`](http://perldoc.perl.org/perlapi.html#SvIV).
        simple fn iv() -> IV = sv_iv()
    }
    method! {
        /// Return true if SV contains a unsigned integer.
        ///
        /// Perl macro:[`SvUOK`](http://perldoc.perl.org/perlapi.html#SvUOK).
        simple fn uv_ok() -> bool = sv_uok() != 0
    }
    method! {
        /// Coerce the given SV to an unsigned integer and return it.
        ///
        /// Perl macro: [`SvUV`](http://perldoc.perl.org/perlapi.html#SvUV).
        simple fn uv() -> UV = sv_uv()
    }
    method! {
        /// Return true if SV contains a floating point value.
        ///
        /// Perl macro:[`SvNOK`](http://perldoc.perl.org/perlapi.html#SvNOK).
        simple fn nv_ok() -> bool = sv_nok() != 0
    }
    method! {
        /// Coerce the given SV to a floating point value and return it.
        ///
        /// Perl macro: [`SvNV`](http://perldoc.perl.org/perlapi.html#SvNV).
        simple fn nv() -> NV = sv_nv()
    }
    method! {
        /// Return true if SV contains a string.
        ///
        /// Perl macro:[`SvPOK`](http://perldoc.perl.org/perlapi.html#SvPOK).
        simple fn pv_ok() -> bool = sv_pok() != 0
    }
    method! {
        /// Return UTF8 flag on the SV.
        ///
        /// You should use this after a call to `pv()` or `str()`, in case any call to string
        /// overloading updates the internal flag.
        ///
        /// Perl macro: [`SvUTF8`](http://perldoc.perl.org/perlapi.html#SvUTF8).
        simple fn utf8() -> bool = sv_utf8() != 0
    }

    /// Return a copy of string in the SV as a vector of bytes.
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    #[inline]
    pub fn pv(&self) -> Vec<u8> {
        unsafe {
            let mut len = 0;
            let ptr = self.pthx().sv_pv(self.as_ptr(), &mut len);
            slice::from_raw_parts(ptr as *const u8, len as usize).to_owned()
        }
    }

    /// Return a copy of string in the SV.
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    pub fn str(&self) -> Result<String, string::FromUtf8Error> {
        String::from_utf8(self.pv())
    }

    method! {
        /// Return true if SV contains a Perl reference.
        ///
        /// Perl macro:[`SvROK`](http://perldoc.perl.org/perlapi.html#SvROK).
        simple fn rv_ok() -> bool = sv_rok() != 0
    }

    #[inline]
    unsafe fn deref_raw(&self) -> *mut raw::SV {
        self.pthx().sv_rv(self.as_ptr())
    }

    /// Dereference RV.
    ///
    /// Return `None` if `self` is not a valid Perl reference.
    #[inline]
    pub fn deref(&self) -> Option<SV> {
        if self.rv_ok() {
            Some(unsafe { SV::from_raw_borrowed(self.pthx(), self.deref_raw()) })
        } else {
            None
        }
    }

    /// Dereference RV into AV.
    ///
    /// Return `None` if `self` is not an array reference.
    #[inline]
    pub fn deref_av(&self) -> Option<AV> {
        self.deref().and_then(|sv| sv.into_av())
    }

    /// Dereference RV into HV.
    ///
    /// Return `None` if `self` is not a hash reference.
    #[inline]
    pub fn deref_hv(&self) -> Option<HV> {
        self.deref().and_then(|sv| sv.into_hv())
    }

    /// Cast SV into AV.
    #[inline]
    pub fn into_av(self) -> Option<AV> {
        if self.is_array() {
            Some(unsafe { AV::from_raw_owned(self.pthx(), self.into_raw() as *mut _) })
        } else {
            None
        }
    }

    /// Cast SV into HV.
    #[inline]
    pub fn into_hv(self) -> Option<HV> {
        if self.is_hash() {
            Some(unsafe { HV::from_raw_owned(self.pthx(), self.into_raw() as *mut _) })
        } else {
            None
        }
    }

    /// Consume SV and convert into raw pointer.
    ///
    /// Does not decrement reference count. Returned pointer must be correctly disposed of to avoid
    /// memory leaks.
    #[inline]
    pub fn into_raw(self) -> *mut raw::SV {
        let raw = self.0.as_ptr();
        mem::forget(self);
        raw
    }

    /// Construct new instance from a raw SV pointer without incrementing reference counter.
    ///
    /// Owned SV pointers are returned by assorted
    /// [`newSV`](http://perldoc.perl.org/perlapi.html#newSV) functions.
    #[inline]
    pub unsafe fn from_raw_owned(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_owned(pthx, raw))
    }

    /// Construct new instance from a raw SV pointer and increment reference counter.
    ///
    /// Borrowed SV pointers exist on stack and are returned by functions like
    /// [`av_fetch`](http://perldoc.perl.org/perlapi.html#av_fetch) or
    /// [`hv_fetch`](http://perldoc.perl.org/perlapi.html#hv_fetch).
    #[inline]
    pub unsafe fn from_raw_borrowed(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_borrowed(pthx, raw))
    }

    fn pthx(&self) -> raw::Interpreter { self.0.pthx() }

    fn as_ptr(&self) -> *mut raw::SV { self.0.as_ptr() }
}

impl FromSV for IV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> IV {
        pthx.sv_iv(raw)
    }
}

impl FromSV for UV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> UV {
        pthx.sv_uv(raw)
    }
}

impl FromSV for NV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> NV {
        pthx.sv_nv(raw)
    }
}

impl FromSV for SV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV::from_raw_borrowed(pthx, raw)
    }
}

impl TryFromSV for String {
    type Error = std::str::Utf8Error;

    #[inline]
    unsafe fn try_from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> Result<Self, Self::Error> {
        let mut len = 0;
        let ptr = pthx.sv_pv(raw, &mut len);
        let bytes = slice::from_raw_parts(ptr as *const u8, len as usize);
        Ok(try!(std::str::from_utf8(bytes)).to_owned())
    }
}

impl IntoSV for IV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_iv(self)) }
    }
}

impl IntoSV for UV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_uv(self)) }
    }
}

impl IntoSV for NV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_nv(self)) }
    }
}

impl IntoSV for bool {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe {
            let raw = if self { pthx.sv_yes() } else { pthx.sv_no() };
            SV::from_raw_owned(pthx, raw)
        }
    }
}

impl IntoSV for String {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        (&self[..]).into_sv(pthx)
    }
}

impl<'a> IntoSV for &'a str {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe {
            let svp = pthx.new_sv_pvn(self.as_ptr() as *const i8,
                                      self.len() as raw::STRLEN,
                                      raw::SVf_UTF8 as raw::U32);
            SV::from_raw_owned(pthx, svp)
        }
    }
}

impl IntoSV for SV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        assert!(self.pthx() == pthx);
        self
    }
}
<commit_msg>Add unsafe method to get SV string buffer.<commit_after>use std;
use std::{ mem, slice, string };
use handle::Owned;
use raw;
use raw::{ IV, UV, NV };
use raw::{ SVt_PVAV, SVt_PVHV, SVt_PVCV, SVt_PVGV };
use array::{ AV };
use hash::{ HV };
use convert::{ IntoSV, FromSV, TryFromSV };

/// Perl scalar object.
pub struct SV(Owned<raw::SV>);

impl SV {
    method! {
        /// Return true if SV is a real scalar value.
        simple fn is_scalar() -> bool = sv_type() < SVt_PVAV
    }
    method! {
        /// Return true if SV contains array.
        simple fn is_array() -> bool = sv_type() == SVt_PVAV
    }
    method! {
        /// Return true if SV contains hash.
        simple fn is_hash() -> bool = sv_type() == SVt_PVHV
    }
    method! {
        /// Return true if SV contains subroutine.
        simple fn is_code() -> bool = sv_type() == SVt_PVCV
    }
    method! {
        /// Return true if SV contains glob.
        simple fn is_glob() -> bool = sv_type() == SVt_PVGV
    }
    method! {
        /// Return true if SV is defined.
        ///
        /// [`SvOK`](http://perldoc.perl.org/perlapi.html#SvOK).
        simple fn ok() -> bool = sv_ok() != 0
    }
    method! {
        /// Return true if SV contains a signed integer.
        ///
        /// Perl macro:[`SvIOK`](http://perldoc.perl.org/perlapi.html#SvIOK).
        simple fn iv_ok() -> bool = sv_iok() != 0
    }
    method! {
        /// Coerce the given SV to an integer and return it.
        ///
        /// Perl macro: [`SvIV`](http://perldoc.perl.org/perlapi.html#SvIV).
        simple fn iv() -> IV = sv_iv()
    }
    method! {
        /// Return true if SV contains a unsigned integer.
        ///
        /// Perl macro:[`SvUOK`](http://perldoc.perl.org/perlapi.html#SvUOK).
        simple fn uv_ok() -> bool = sv_uok() != 0
    }
    method! {
        /// Coerce the given SV to an unsigned integer and return it.
        ///
        /// Perl macro: [`SvUV`](http://perldoc.perl.org/perlapi.html#SvUV).
        simple fn uv() -> UV = sv_uv()
    }
    method! {
        /// Return true if SV contains a floating point value.
        ///
        /// Perl macro:[`SvNOK`](http://perldoc.perl.org/perlapi.html#SvNOK).
        simple fn nv_ok() -> bool = sv_nok() != 0
    }
    method! {
        /// Coerce the given SV to a floating point value and return it.
        ///
        /// Perl macro: [`SvNV`](http://perldoc.perl.org/perlapi.html#SvNV).
        simple fn nv() -> NV = sv_nv()
    }
    method! {
        /// Return true if SV contains a string.
        ///
        /// Perl macro:[`SvPOK`](http://perldoc.perl.org/perlapi.html#SvPOK).
        simple fn pv_ok() -> bool = sv_pok() != 0
    }
    method! {
        /// Return UTF8 flag on the SV.
        ///
        /// You should use this after a call to `pv()` or `str()`, in case any call to string
        /// overloading updates the internal flag.
        ///
        /// Perl macro: [`SvUTF8`](http://perldoc.perl.org/perlapi.html#SvUTF8).
        simple fn utf8() -> bool = sv_utf8() != 0
    }

    /// Get a slice of the internal string buffer of the SV.
    ///
    /// This method is unsafe, because the buffer may be changed, moved or freed by the interpreter
    /// whenever this SV is accessed or modified. To be safe, code that uses this method should not
    /// access interpreter context, this or any other perl value while the slice is in scope.
    ///
    /// For example, this use is okay:
    ///
    /// ```ignore
    /// let chars = unsafe { sv.as_slice().chars().count() };
    /// ```
    ///
    /// And this code may potentially access freed memory:
    ///
    /// ```ignore
    /// let msg = unsafe { sv1.as_slice() };
    /// let pos = sv2.iv();
    /// println!("{}", &msg[pos..]);
    /// ```
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    #[inline]
    pub unsafe fn as_slice(&self) -> &[u8] {
        let mut len = 0;
        let ptr = self.pthx().sv_pv(self.as_ptr(), &mut len);
        slice::from_raw_parts(ptr as *const u8, len as usize)
    }

    /// Return a copy of string in the SV as a vector of bytes.
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    #[inline]
    pub fn pv(&self) -> Vec<u8> {
        unsafe {
            self.as_slice().to_owned()
        }
    }

    /// Return a copy of string in the SV.
    ///
    /// Perl macro: [`SvPV`](http://perldoc.perl.org/perlapi.html#SvPV).
    pub fn str(&self) -> Result<String, string::FromUtf8Error> {
        String::from_utf8(self.pv())
    }

    method! {
        /// Return true if SV contains a Perl reference.
        ///
        /// Perl macro:[`SvROK`](http://perldoc.perl.org/perlapi.html#SvROK).
        simple fn rv_ok() -> bool = sv_rok() != 0
    }

    #[inline]
    unsafe fn deref_raw(&self) -> *mut raw::SV {
        self.pthx().sv_rv(self.as_ptr())
    }

    /// Dereference RV.
    ///
    /// Return `None` if `self` is not a valid Perl reference.
    #[inline]
    pub fn deref(&self) -> Option<SV> {
        if self.rv_ok() {
            Some(unsafe { SV::from_raw_borrowed(self.pthx(), self.deref_raw()) })
        } else {
            None
        }
    }

    /// Dereference RV into AV.
    ///
    /// Return `None` if `self` is not an array reference.
    #[inline]
    pub fn deref_av(&self) -> Option<AV> {
        self.deref().and_then(|sv| sv.into_av())
    }

    /// Dereference RV into HV.
    ///
    /// Return `None` if `self` is not a hash reference.
    #[inline]
    pub fn deref_hv(&self) -> Option<HV> {
        self.deref().and_then(|sv| sv.into_hv())
    }

    /// Cast SV into AV.
    #[inline]
    pub fn into_av(self) -> Option<AV> {
        if self.is_array() {
            Some(unsafe { AV::from_raw_owned(self.pthx(), self.into_raw() as *mut _) })
        } else {
            None
        }
    }

    /// Cast SV into HV.
    #[inline]
    pub fn into_hv(self) -> Option<HV> {
        if self.is_hash() {
            Some(unsafe { HV::from_raw_owned(self.pthx(), self.into_raw() as *mut _) })
        } else {
            None
        }
    }

    /// Consume SV and convert into raw pointer.
    ///
    /// Does not decrement reference count. Returned pointer must be correctly disposed of to avoid
    /// memory leaks.
    #[inline]
    pub fn into_raw(self) -> *mut raw::SV {
        let raw = self.0.as_ptr();
        mem::forget(self);
        raw
    }

    /// Construct new instance from a raw SV pointer without incrementing reference counter.
    ///
    /// Owned SV pointers are returned by assorted
    /// [`newSV`](http://perldoc.perl.org/perlapi.html#newSV) functions.
    #[inline]
    pub unsafe fn from_raw_owned(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_owned(pthx, raw))
    }

    /// Construct new instance from a raw SV pointer and increment reference counter.
    ///
    /// Borrowed SV pointers exist on stack and are returned by functions like
    /// [`av_fetch`](http://perldoc.perl.org/perlapi.html#av_fetch) or
    /// [`hv_fetch`](http://perldoc.perl.org/perlapi.html#hv_fetch).
    #[inline]
    pub unsafe fn from_raw_borrowed(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV(Owned::from_raw_borrowed(pthx, raw))
    }

    fn pthx(&self) -> raw::Interpreter { self.0.pthx() }

    fn as_ptr(&self) -> *mut raw::SV { self.0.as_ptr() }
}

impl FromSV for IV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> IV {
        pthx.sv_iv(raw)
    }
}

impl FromSV for UV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> UV {
        pthx.sv_uv(raw)
    }
}

impl FromSV for NV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> NV {
        pthx.sv_nv(raw)
    }
}

impl FromSV for SV {
    #[inline]
    unsafe fn from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> SV {
        SV::from_raw_borrowed(pthx, raw)
    }
}

impl TryFromSV for String {
    type Error = std::str::Utf8Error;

    #[inline]
    unsafe fn try_from_sv(pthx: raw::Interpreter, raw: *mut raw::SV) -> Result<Self, Self::Error> {
        let mut len = 0;
        let ptr = pthx.sv_pv(raw, &mut len);
        let bytes = slice::from_raw_parts(ptr as *const u8, len as usize);
        Ok(try!(std::str::from_utf8(bytes)).to_owned())
    }
}

impl IntoSV for IV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_iv(self)) }
    }
}

impl IntoSV for UV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_uv(self)) }
    }
}

impl IntoSV for NV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe { SV::from_raw_owned(pthx, pthx.new_sv_nv(self)) }
    }
}

impl IntoSV for bool {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe {
            let raw = if self { pthx.sv_yes() } else { pthx.sv_no() };
            SV::from_raw_owned(pthx, raw)
        }
    }
}

impl IntoSV for String {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        (&self[..]).into_sv(pthx)
    }
}

impl<'a> IntoSV for &'a str {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        unsafe {
            let svp = pthx.new_sv_pvn(self.as_ptr() as *const i8,
                                      self.len() as raw::STRLEN,
                                      raw::SVf_UTF8 as raw::U32);
            SV::from_raw_owned(pthx, svp)
        }
    }
}

impl IntoSV for SV {
    #[inline]
    fn into_sv(self, pthx: raw::Interpreter) -> SV {
        assert!(self.pthx() == pthx);
        self
    }
}
<|endoftext|>


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

// See docs of the `procedural-masquerade` crate.
define_invoke_proc_macro!(cssparser_internal__invoke_proc_macro);

/// Expands to a `match` expression with string patterns,
/// matching case-insensitively in the ASCII range.
///
/// The patterns must not contain ASCII upper case letters. (They must be already be lower-cased.)
///
/// # Example
///
/// ```rust
/// #[macro_use] extern crate cssparser;
///
/// # fn main() {}  // Make doctest not wrap everythig in its own main
/// # fn dummy(function_name: &String) { let _ =
/// match_ignore_ascii_case! { &function_name,
///     "rgb" => parse_rgb(..),
///     "rgba" => parse_rgba(..),
///     "hsl" => parse_hsl(..),
///     "hsla" => parse_hsla(..),
///     _ => Err(format!("unknown function: {}", function_name))
/// }
/// # ;}
/// # use std::ops::RangeFull;
/// # fn parse_rgb(_: RangeFull) -> Result<(), String> { Ok(()) }
/// # fn parse_rgba(_: RangeFull) -> Result<(), String> { Ok(()) }
/// # fn parse_hsl(_: RangeFull) -> Result<(), String> { Ok(()) }
/// # fn parse_hsla(_: RangeFull) -> Result<(), String> { Ok(()) }
/// ```
#[macro_export]
macro_rules! match_ignore_ascii_case {
    ( $input:expr, $( $match_body:tt )* ) => {
        {
            cssparser_internal__invoke_proc_macro! {
                cssparser_internal__assert_ascii_lowercase__max_len!( $( $match_body )* )
            }

            {
                // MAX_LENGTH is generated by cssparser_internal__assert_ascii_lowercase__max_len
                cssparser_internal__to_lowercase!($input, MAX_LENGTH => lowercase);
                // "A" is a short string that we know is different for every string pattern,
                // since we’ve verified that none of them include ASCII upper case letters.
                match lowercase.unwrap_or("A") {
                    $( $match_body )*
                }
            }
        }
    };
}

/// Define a function `$name(&str) -> Option<&'static $ValueType>`
///
/// The function finds a match for the input string
/// in a [`phf` map](https://github.com/sfackler/rust-phf)
/// and returns a reference to the corresponding value.
/// Matching is case-insensitive in the ASCII range.
///
/// ## Example:
///
/// ```rust
/// #[macro_use] extern crate cssparser;
///
/// # fn main() {}  // Make doctest not wrap everything in its own main
///
/// fn color_rgb(input: &str) -> Option<(u8, u8, u8)> {
///     ascii_case_insensitive_phf_map! {
///         keyword -> (u8, u8, u8) = {
///             "red" => (255, 0, 0),
///             "green" => (0, 255, 0),
///             "blue" => (0, 0, 255),
///         }
///     }
///     keyword(input).cloned()
/// }
#[macro_export]
macro_rules! ascii_case_insensitive_phf_map {
    ($name: ident -> $ValueType: ty = { $( $key: expr => $value: expr ),* }) => {
        ascii_case_insensitive_phf_map!($name -> $ValueType = { $( $key => $value, )* })
    };
    ($name: ident -> $ValueType: ty = { $( $key: expr => $value: expr, )* }) => {
        pub fn $name(input: &str) -> Option<&'static $ValueType> {
            cssparser_internal__invoke_proc_macro! {
                cssparser_internal__phf_map!( ($ValueType) $( $key ($value) )+ )
            }

            {
                cssparser_internal__invoke_proc_macro! {
                    cssparser_internal__max_len!( $( $key )+ )
                }
                // MAX_LENGTH is generated by cssparser_internal__max_len
                cssparser_internal__to_lowercase!(input, MAX_LENGTH => lowercase);
                lowercase.and_then(|s| MAP.get(s))
            }
        }
    }
}

/// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
///
/// **This macro is not part of the public API. It can change or be removed between any versions.**
///
/// Define a local variable named `$output`
/// and assign it the result of calling `_internal__to_lowercase`
/// with a stack-allocated buffer of length `$BUFFER_SIZE`.
#[macro_export]
#[doc(hidden)]
macro_rules! cssparser_internal__to_lowercase {
    ($input: expr, $BUFFER_SIZE: expr => $output: ident) => {
        let mut buffer;
        // Safety: `buffer` is only used in `_internal__to_lowercase`,
        // which initializes with `copy_from_slice` the part of the buffer it uses,
        // before it uses it.
        #[allow(unsafe_code)]
        let buffer = unsafe {
            // FIXME: remove this when we require Rust 1.36
            #[cfg(not(has_std__mem__MaybeUninit))]
            {
                buffer = ::std::mem::uninitialized::<[u8; $BUFFER_SIZE]>();
                &mut buffer
            }
            #[cfg(has_std__mem__MaybeUninit)]
            {
                buffer = ::std::mem::MaybeUninit::<[u8; $BUFFER_SIZE]>::uninit();
                &mut *(buffer.as_mut_ptr())
            }
        };
        let input: &str = $input;
        let $output = $crate::_internal__to_lowercase(buffer, input);
    };
}

/// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
///
/// **This function is not part of the public API. It can change or be removed between any verisons.**
///
/// If `input` is larger than buffer, return `None`.
/// Otherwise, return `input` ASCII-lowercased, using `buffer` as temporary space if necessary.
#[doc(hidden)]
#[allow(non_snake_case)]
pub fn _internal__to_lowercase<'a>(buffer: &'a mut [u8], input: &'a str) -> Option<&'a str> {
    if let Some(buffer) = buffer.get_mut(..input.len()) {
        if let Some(first_uppercase) = input.bytes().position(|byte| matches!(byte, b'A'..=b'Z')) {
            buffer.copy_from_slice(input.as_bytes());
            buffer[first_uppercase..].make_ascii_lowercase();
            // `buffer` was initialized to a copy of `input` (which is &str so well-formed UTF-8)
            // then lowercased (which preserves UTF-8 well-formedness)
            unsafe { Some(::std::str::from_utf8_unchecked(buffer)) }
        } else {
            // Input is already lower-case
            Some(input)
        }
    } else {
        // Input is longer than buffer, which has the length of the longest expected string:
        // none of the expected strings would match.
        None
    }
}

#[cfg(feature = "dummy_match_byte")]
macro_rules! match_byte {
    ($value:expr, $($rest:tt)* ) => {
        match $value {
            $(
                $rest
            )+
        }
    };
}
<commit_msg>Make #252 work from a different crate<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// See docs of the `procedural-masquerade` crate.
define_invoke_proc_macro!(cssparser_internal__invoke_proc_macro);

/// Expands to a `match` expression with string patterns,
/// matching case-insensitively in the ASCII range.
///
/// The patterns must not contain ASCII upper case letters. (They must be already be lower-cased.)
///
/// # Example
///
/// ```rust
/// #[macro_use] extern crate cssparser;
///
/// # fn main() {}  // Make doctest not wrap everythig in its own main
/// # fn dummy(function_name: &String) { let _ =
/// match_ignore_ascii_case! { &function_name,
///     "rgb" => parse_rgb(..),
///     "rgba" => parse_rgba(..),
///     "hsl" => parse_hsl(..),
///     "hsla" => parse_hsla(..),
///     _ => Err(format!("unknown function: {}", function_name))
/// }
/// # ;}
/// # use std::ops::RangeFull;
/// # fn parse_rgb(_: RangeFull) -> Result<(), String> { Ok(()) }
/// # fn parse_rgba(_: RangeFull) -> Result<(), String> { Ok(()) }
/// # fn parse_hsl(_: RangeFull) -> Result<(), String> { Ok(()) }
/// # fn parse_hsla(_: RangeFull) -> Result<(), String> { Ok(()) }
/// ```
#[macro_export]
macro_rules! match_ignore_ascii_case {
    ( $input:expr, $( $match_body:tt )* ) => {
        {
            cssparser_internal__invoke_proc_macro! {
                cssparser_internal__assert_ascii_lowercase__max_len!( $( $match_body )* )
            }

            {
                // MAX_LENGTH is generated by cssparser_internal__assert_ascii_lowercase__max_len
                cssparser_internal__to_lowercase!($input, MAX_LENGTH => lowercase);
                // "A" is a short string that we know is different for every string pattern,
                // since we’ve verified that none of them include ASCII upper case letters.
                match lowercase.unwrap_or("A") {
                    $( $match_body )*
                }
            }
        }
    };
}

/// Define a function `$name(&str) -> Option<&'static $ValueType>`
///
/// The function finds a match for the input string
/// in a [`phf` map](https://github.com/sfackler/rust-phf)
/// and returns a reference to the corresponding value.
/// Matching is case-insensitive in the ASCII range.
///
/// ## Example:
///
/// ```rust
/// #[macro_use] extern crate cssparser;
///
/// # fn main() {}  // Make doctest not wrap everything in its own main
///
/// fn color_rgb(input: &str) -> Option<(u8, u8, u8)> {
///     ascii_case_insensitive_phf_map! {
///         keyword -> (u8, u8, u8) = {
///             "red" => (255, 0, 0),
///             "green" => (0, 255, 0),
///             "blue" => (0, 0, 255),
///         }
///     }
///     keyword(input).cloned()
/// }
#[macro_export]
macro_rules! ascii_case_insensitive_phf_map {
    ($name: ident -> $ValueType: ty = { $( $key: expr => $value: expr ),* }) => {
        ascii_case_insensitive_phf_map!($name -> $ValueType = { $( $key => $value, )* })
    };
    ($name: ident -> $ValueType: ty = { $( $key: expr => $value: expr, )* }) => {
        pub fn $name(input: &str) -> Option<&'static $ValueType> {
            cssparser_internal__invoke_proc_macro! {
                cssparser_internal__phf_map!( ($ValueType) $( $key ($value) )+ )
            }

            {
                cssparser_internal__invoke_proc_macro! {
                    cssparser_internal__max_len!( $( $key )+ )
                }
                // MAX_LENGTH is generated by cssparser_internal__max_len
                cssparser_internal__to_lowercase!(input, MAX_LENGTH => lowercase);
                lowercase.and_then(|s| MAP.get(s))
            }
        }
    }
}

/// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
///
/// **This macro is not part of the public API. It can change or be removed between any versions.**
///
/// Define a local variable named `$output`
/// and assign it the result of calling `_internal__to_lowercase`
/// with a stack-allocated buffer of length `$BUFFER_SIZE`.
#[macro_export]
#[doc(hidden)]
macro_rules! cssparser_internal__to_lowercase {
    ($input: expr, $BUFFER_SIZE: expr => $output: ident) => {
        let mut buffer;
        // Safety: `buffer` is only used in `_internal__to_lowercase`,
        // which initializes with `copy_from_slice` the part of the buffer it uses,
        // before it uses it.
        #[allow(unsafe_code)]
        let buffer = unsafe { cssparser_internal__uninit!(buffer, $BUFFER_SIZE) };
        let input: &str = $input;
        let $output = $crate::_internal__to_lowercase(buffer, input);
    };
}

#[cfg(has_std__mem__MaybeUninit)]
#[macro_export]
#[doc(hidden)]
macro_rules! cssparser_internal__uninit {
    ($buffer: ident, $BUFFER_SIZE: expr) => {
        {
            $buffer = ::std::mem::MaybeUninit::<[u8; $BUFFER_SIZE]>::uninit();
            &mut *($buffer.as_mut_ptr())
        }
    }
}

// FIXME: remove this when we require Rust 1.36
#[cfg(not(has_std__mem__MaybeUninit))]
#[macro_export]
#[doc(hidden)]
macro_rules! cssparser_internal__uninit {
    ($buffer: ident, $BUFFER_SIZE: expr) => {
        {
            $buffer = ::std::mem::uninitialized::<[u8; $BUFFER_SIZE]>();
            &mut $buffer
        }
    }
}

/// Implementation detail of match_ignore_ascii_case! and ascii_case_insensitive_phf_map! macros.
///
/// **This function is not part of the public API. It can change or be removed between any verisons.**
///
/// If `input` is larger than buffer, return `None`.
/// Otherwise, return `input` ASCII-lowercased, using `buffer` as temporary space if necessary.
#[doc(hidden)]
#[allow(non_snake_case)]
pub fn _internal__to_lowercase<'a>(buffer: &'a mut [u8], input: &'a str) -> Option<&'a str> {
    if let Some(buffer) = buffer.get_mut(..input.len()) {
        if let Some(first_uppercase) = input.bytes().position(|byte| matches!(byte, b'A'..=b'Z')) {
            buffer.copy_from_slice(input.as_bytes());
            buffer[first_uppercase..].make_ascii_lowercase();
            // `buffer` was initialized to a copy of `input` (which is &str so well-formed UTF-8)
            // then lowercased (which preserves UTF-8 well-formedness)
            unsafe { Some(::std::str::from_utf8_unchecked(buffer)) }
        } else {
            // Input is already lower-case
            Some(input)
        }
    } else {
        // Input is longer than buffer, which has the length of the longest expected string:
        // none of the expected strings would match.
        None
    }
}

#[cfg(feature = "dummy_match_byte")]
macro_rules! match_byte {
    ($value:expr, $($rest:tt)* ) => {
        match $value {
            $(
                $rest
            )+
        }
    };
}
<|endoftext|>


<commit_before>use std::fmt;

pub struct Memory {
    rom: u8,
    ram_0x4000_0x7FFF: usize,
    ram_0x8000_0xBFFF: usize,
    ram_0xC000_0xFFFF: usize,

    rom0: Vec<u8>,
    rom1: Vec<u8>,
    bank: [Vec<u8>; 8],
}

impl Memory {
    pub fn new(_rom0: Vec<u8>, _rom1: Vec<u8>) -> Memory {
        Memory {
            rom: 0,
            ram_0x4000_0x7FFF: 5,
            ram_0x8000_0xBFFF: 2,
            ram_0xC000_0xFFFF: 0,

            rom0: _rom0,
            rom1: _rom1,

            bank: [
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024]
            ]
        }
    }

    pub fn read_word(&self, addr: u16) -> u8 {
        if addr <= 0x3FFF {
            match self.rom {
                0 => self.rom0[addr as usize],
                1 => self.rom1[addr as usize],
                _ => unreachable!()
            }
        } else if addr >= 0x4000 && addr <= 0x7FFF {
            self.bank[self.ram_0x4000_0x7FFF][(addr - 0x4000) as usize]
        } else if addr >= 0x8000 && addr <= 0xBFFF {
            self.bank[self.ram_0x8000_0xBFFF][(addr - 0x8000) as usize]
        } else if addr >= 0xC000 {
            self.bank[self.ram_0xC000_0xFFFF][(addr - 0xC000) as usize]
        } else {
            panic!("Trying to read from unrecognized address: {:#x}", addr);
        }
    }

    pub fn write_word(&mut self, addr: u16, val: u8) {
        if addr >= 0xC000 {
            self.bank[self.ram_0xC000_0xFFFF][(addr - 0xC000) as usize] = val;
        } else if addr >= 0x8000 && addr <= 0xBFFF {
            self.bank[self.ram_0x8000_0xBFFF][(addr - 0x8000) as usize] = val;
        } else if addr >= 0x4000 && addr <= 0x7FFF {
            self.bank[self.ram_0x4000_0x7FFF][(addr - 0x4000) as usize] = val;
        } else {
            panic!("Trying to write to unrecognized address: {:#x}", addr);
        }
    }

    pub fn change_bank(&mut self, val: u8) {
        self.ram_0xC000_0xFFFF = val as usize;
    }

    pub fn change_rom_bank(&mut self, val: u8) {
        self.rom = val;
    }
}

impl fmt::Debug for Memory {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "ram_0xC000_0xFFFF: {}
                     ram_0x8000_0xBFFF: {}
                     ram_0x4000_0x7FFF: {}
                     rom: {}
                    ",
                    self.ram_0xC000_0xFFFF,
                    self.ram_0x8000_0xBFFF,
                    self.ram_0x4000_0x7FFF,
                    self.rom)
    }
}
<commit_msg>Add debug messages to memory module<commit_after>use std::fmt;

pub struct Memory {
    rom: u8,
    ram_0x4000_0x7FFF: usize,
    ram_0x8000_0xBFFF: usize,
    ram_0xC000_0xFFFF: usize,

    rom0: Vec<u8>,
    rom1: Vec<u8>,
    bank: [Vec<u8>; 8],
}

impl Memory {
    pub fn new(_rom0: Vec<u8>, _rom1: Vec<u8>) -> Memory {
        Memory {
            rom: 0,
            ram_0x4000_0x7FFF: 5,
            ram_0x8000_0xBFFF: 2,
            ram_0xC000_0xFFFF: 0,

            rom0: _rom0,
            rom1: _rom1,

            bank: [
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024],
                vec![0; 16 * 1024]
            ]
        }
    }

    pub fn read_word(&self, addr: u16) -> u8 {
        let mut val = 0;
        if addr <= 0x3FFF {
            match self.rom {
                0 => { val = self.rom0[addr as usize]; },
                1 => { val = self.rom1[addr as usize]; },
                _ => unreachable!()
            }
        } else if addr >= 0x4000 && addr <= 0x7FFF {
            val = self.bank[self.ram_0x4000_0x7FFF][(addr - 0x4000) as usize];
        } else if addr >= 0x8000 && addr <= 0xBFFF {
            val = self.bank[self.ram_0x8000_0xBFFF][(addr - 0x8000) as usize];
        } else if addr >= 0xC000 {
            val = self.bank[self.ram_0xC000_0xFFFF][(addr - 0xC000) as usize];
        } else {
            panic!("Trying to read from unrecognized address: {:#x}", addr);
        }

        debug!("                Read value {:#04X} from address {:#06X}", val, addr);
        val
    }

    pub fn write_word(&mut self, addr: u16, val: u8) {
        if addr >= 0xC000 {
            self.bank[self.ram_0xC000_0xFFFF][(addr - 0xC000) as usize] = val;
        } else if addr >= 0x8000 && addr <= 0xBFFF {
            self.bank[self.ram_0x8000_0xBFFF][(addr - 0x8000) as usize] = val;
        } else if addr >= 0x4000 && addr <= 0x7FFF {
            self.bank[self.ram_0x4000_0x7FFF][(addr - 0x4000) as usize] = val;
        } else {
            panic!("Trying to write to unrecognized address: {:#x}", addr);
        }

        debug!("                Write value {:#04X} to address {:#06X}", val, addr);
    }

    pub fn change_bank(&mut self, val: u8) {
        self.ram_0xC000_0xFFFF = val as usize;
    }

    pub fn change_rom_bank(&mut self, val: u8) {
        self.rom = val;
    }
}

impl fmt::Debug for Memory {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "ram_0xC000_0xFFFF: {}
                     ram_0x8000_0xBFFF: {}
                     ram_0x4000_0x7FFF: {}
                     rom: {}
                    ",
                    self.ram_0xC000_0xFFFF,
                    self.ram_0x8000_0xBFFF,
                    self.ram_0x4000_0x7FFF,
                    self.rom)
    }
}
<|endoftext|>


<commit_before>//! A set of objects which automatically change their register or coil value when they go out of scope
//!
//! # Examples
//!
//! When the `auto` object goes out of scope and is dropped, the value of coil `10` is switched `On`:
//!
//! ```
//! # extern crate modbus;
//! # extern crate test_server;
//! # use test_server::start_dummy_server;
//! # fn main() {
//! use modbus::{Client, Coil};
//! use modbus::tcp;
//! use modbus::scoped::{ScopedCoil, CoilDropFunction};
//! # if cfg!(feature = "modbus-server-tests") {
//! # let (_s, port) = start_dummy_server(Some(22222));
//!
//! // let port = 502;
//! let mut client = tcp::Transport::new_with_port("127.0.0.1", port).unwrap();
//! {
//!    let mut auto = ScopedCoil::new(&mut client, 10, CoilDropFunction::On).unwrap();
//!    assert_eq!(auto.mut_transport().read_coils(10, 1).unwrap(), vec![Coil::Off]);
//! }
//! assert_eq!(client.read_coils(10, 1).unwrap(), vec![Coil::On]);
//! # }
//! # }
//! ```
//!
//! When the `auto` object goes out of scope and is dropped, the value of register `10` is modified by
//! function `fun`:
//!
//! ```
//! # extern crate modbus;
//! # extern crate test_server;
//! # use test_server::start_dummy_server;
//! # fn main() {
//! use modbus::{Client, Coil};
//! use modbus::tcp;
//! use modbus::scoped::{ScopedRegister, RegisterDropFunction};
//! # if cfg!(feature = "modbus-server-tests") {
//! # let (_s, port) = start_dummy_server(Some(22223));
//!
//! // let port = 502;
//! let mut client = tcp::Transport::new_with_port("127.0.0.1", port).unwrap();
//! client.write_single_register(10, 1);
//! {
//!     let fun = |v| v + 5;
//!     let mut auto = ScopedRegister::new(&mut client, 10, RegisterDropFunction::Fun(&fun)).unwrap();
//!     assert_eq!(auto.mut_transport().read_holding_registers(10, 1).unwrap(), vec![1]);
//! }
//! assert_eq!(client.read_holding_registers(10, 1).unwrap(), vec![6]);
//! # }
//! # }
//! ```

use {Coil, Transport, Client, Result};

/// Action to perform when the `ScopedCoil` is dropped.
pub enum CoilDropFunction {
    /// Set the coil to `Coil::On`
    On,
    /// Set the coil to `Coil::Off`
    Off,
    /// Toggle the current value.
    Toggle,
}

/// Action to perform when the `ScopedRegister` is dropped.
pub enum RegisterDropFunction<'a> {
    /// Set the register to zero value
    Zero,
    /// Increment the current register value by 1
    Increment,
    /// Decrement the current register value by 1
    Decrement,
    /// Set the register value to the given value.
    Value(u16),
    /// Execute the given function on the current value, setting the register with the result value.
    Fun(&'a Fn(u16) -> u16),
}

/// Auto object which modifies it's coil value depending on a given modification function if it
/// goes out of scope.
pub struct ScopedCoil<'a> {
    address: u16,
    fun: CoilDropFunction,
    transport: &'a mut Transport,
}

impl<'a> Drop for ScopedCoil<'a> {
    fn drop(&mut self) {
        // assume everything works as expected, we can't return an error
        let value = self.transport.read_coils(self.address, 1).unwrap()[0];
        let drop_value = match self.fun {
            CoilDropFunction::On => Coil::On,
            CoilDropFunction::Off => Coil::Off,
            CoilDropFunction::Toggle => if value == Coil::On {
                Coil::Off
            } else {
                Coil::On
            },
        };
        self.transport.write_single_coil(self.address, drop_value).unwrap()
    }
}

impl<'a> ScopedCoil<'a> {
    /// Create a new `ScopedCoil` object with `address` and drop function when the object goes
    /// out of scope.
    pub fn new(transport: &mut Transport,
               address: u16,
               fun: CoilDropFunction)
               -> Result<ScopedCoil> {
        Ok(ScopedCoil {
            address: address,
            fun: fun,
            transport: transport,
        })
    }

    pub fn mut_transport(&mut self) -> &mut Transport {
        self.transport
    }
}

/// Auto object which modifies it's register value depending on a given modification function if it
/// goes out of scope.
pub struct ScopedRegister<'a> {
    address: u16,
    fun: RegisterDropFunction<'a>,
    transport: &'a mut Transport,
}

impl<'a> Drop for ScopedRegister<'a> {
    fn drop(&mut self) {
        // assume everything works as expected, we can't return an error
        let value = self.transport.read_holding_registers(self.address, 1).unwrap()[0];
        let drop_value = match self.fun {
            RegisterDropFunction::Zero => 0u16,
            RegisterDropFunction::Increment => value + 1,
            RegisterDropFunction::Decrement => value - 1,
            RegisterDropFunction::Value(v) => v,
            RegisterDropFunction::Fun(f) => f(value),
        };
        self.transport.write_single_register(self.address, drop_value).unwrap()
    }
}

impl<'a> ScopedRegister<'a> {
    /// Create a new `ScopedRegister` object with `address` and drop function when the object goes
    /// out of scope.
    pub fn new<'b>(transport: &'b mut Transport,
                   address: u16,
                   fun: RegisterDropFunction<'b>)
                   -> Result<ScopedRegister<'b>> {
        Ok(ScopedRegister {
            address: address,
            fun: fun,
            transport: transport,
        })
    }

    pub fn mut_transport(&mut self) -> &mut Transport {
        self.transport
    }
}
<commit_msg>avoid panics due to unwrap calls<commit_after>//! A set of objects which automatically change their register or coil value when they go out of scope
//!
//! # Examples
//!
//! When the `auto` object goes out of scope and is dropped, the value of coil `10` is switched `On`:
//!
//! ```
//! # extern crate modbus;
//! # extern crate test_server;
//! # use test_server::start_dummy_server;
//! # fn main() {
//! use modbus::{Client, Coil};
//! use modbus::tcp;
//! use modbus::scoped::{ScopedCoil, CoilDropFunction};
//! # if cfg!(feature = "modbus-server-tests") {
//! # let (_s, port) = start_dummy_server(Some(22222));
//!
//! // let port = 502;
//! let mut client = tcp::Transport::new_with_port("127.0.0.1", port).unwrap();
//! {
//!    let mut auto = ScopedCoil::new(&mut client, 10, CoilDropFunction::On).unwrap();
//!    assert_eq!(auto.mut_transport().read_coils(10, 1).unwrap(), vec![Coil::Off]);
//! }
//! assert_eq!(client.read_coils(10, 1).unwrap(), vec![Coil::On]);
//! # }
//! # }
//! ```
//!
//! When the `auto` object goes out of scope and is dropped, the value of register `10` is modified by
//! function `fun`:
//!
//! ```
//! # extern crate modbus;
//! # extern crate test_server;
//! # use test_server::start_dummy_server;
//! # fn main() {
//! use modbus::{Client, Coil};
//! use modbus::tcp;
//! use modbus::scoped::{ScopedRegister, RegisterDropFunction};
//! # if cfg!(feature = "modbus-server-tests") {
//! # let (_s, port) = start_dummy_server(Some(22223));
//!
//! // let port = 502;
//! let mut client = tcp::Transport::new_with_port("127.0.0.1", port).unwrap();
//! client.write_single_register(10, 1);
//! {
//!     let fun = |v| v + 5;
//!     let mut auto = ScopedRegister::new(&mut client, 10, RegisterDropFunction::Fun(&fun)).unwrap();
//!     assert_eq!(auto.mut_transport().read_holding_registers(10, 1).unwrap(), vec![1]);
//! }
//! assert_eq!(client.read_holding_registers(10, 1).unwrap(), vec![6]);
//! # }
//! # }
//! ```

use {Coil, Transport, Client, Result};

/// Action to perform when the `ScopedCoil` is dropped.
pub enum CoilDropFunction {
    /// Set the coil to `Coil::On`
    On,
    /// Set the coil to `Coil::Off`
    Off,
    /// Toggle the current value.
    Toggle,
}

/// Action to perform when the `ScopedRegister` is dropped.
pub enum RegisterDropFunction<'a> {
    /// Set the register to zero value
    Zero,
    /// Increment the current register value by 1
    Increment,
    /// Decrement the current register value by 1
    Decrement,
    /// Set the register value to the given value.
    Value(u16),
    /// Execute the given function on the current value, setting the register with the result value.
    Fun(&'a Fn(u16) -> u16),
}

/// Auto object which modifies it's coil value depending on a given modification function if it
/// goes out of scope.
pub struct ScopedCoil<'a> {
    address: u16,
    fun: CoilDropFunction,
    transport: &'a mut Transport,
}

impl<'a> Drop for ScopedCoil<'a> {
    fn drop(&mut self) {
        let _ = self.transport
            .read_coils(self.address, 1)
            .and_then(|value| match value.len() {
                1 => {
                    let drop_value = match self.fun {
                        CoilDropFunction::On  => Coil::On,
                        CoilDropFunction::Off => Coil::Off,
                        CoilDropFunction::Toggle => match value[0] {
                          Coil::On  => Coil::Off,
                          Coil::Off => Coil::On
                        }
                    };
                    let _ = self.transport.write_single_coil(self.address, drop_value);
                    Ok(())
                },
                _ => Ok(())
        });
    }
}

impl<'a> ScopedCoil<'a> {
    /// Create a new `ScopedCoil` object with `address` and drop function when the object goes
    /// out of scope.
    pub fn new(transport: &mut Transport,
               address: u16,
               fun: CoilDropFunction)
               -> Result<ScopedCoil> {
        Ok(ScopedCoil {
            address: address,
            fun: fun,
            transport: transport,
        })
    }

    pub fn mut_transport(&mut self) -> &mut Transport {
        self.transport
    }
}

/// Auto object which modifies it's register value depending on a given modification function if it
/// goes out of scope.
pub struct ScopedRegister<'a> {
    address: u16,
    fun: RegisterDropFunction<'a>,
    transport: &'a mut Transport,
}

impl<'a> Drop for ScopedRegister<'a> {
    fn drop(&mut self) {
        let _ = self.transport
            .read_holding_registers(self.address, 1)
            .and_then(|value| match value.len() {
                1 => {
                    let drop_value = match self.fun {
                        RegisterDropFunction::Zero => 0u16,
                        RegisterDropFunction::Increment => value[0] + 1,
                        RegisterDropFunction::Decrement => value[0] - 1,
                        RegisterDropFunction::Value(v) => v,
                        RegisterDropFunction::Fun(f) => f(value[0]),
                    };
                    let _ = self.transport.write_single_register(self.address, drop_value);
                    Ok(())
                },
                _ => Ok(())
        });
    }
}

impl<'a> ScopedRegister<'a> {
    /// Create a new `ScopedRegister` object with `address` and drop function when the object goes
    /// out of scope.
    pub fn new<'b>(transport: &'b mut Transport,
                   address: u16,
                   fun: RegisterDropFunction<'b>)
                   -> Result<ScopedRegister<'b>> {
        Ok(ScopedRegister {
            address: address,
            fun: fun,
            transport: transport,
        })
    }

    pub fn mut_transport(&mut self) -> &mut Transport {
        self.transport
    }
}
<|endoftext|>


<commit_before>//! `Server` listens for HTTP requests.
//!
//!```rust
//!# use rustful::server::Server;
//!# use rustful::router::Router;
//!# let routes = [];
//!let server = Server {
//!	handlers: Router::from_routes(routes),
//!	port: 8080
//!};
//!
//!server.run();
//!```

use router::Router;
use request::Request;
use response::Response;
use response::status::NotFound;

use http;
use http::server::{ResponseWriter, Config};
use http::server::request::{AbsoluteUri, AbsolutePath};
use http::headers::content_type::MediaType;
use http::method::Post;

use std::io::net::ip::{SocketAddr, Ipv4Addr, Port};
use std::str::from_utf8_owned;
use std::uint;
use std::io::BufReader;
use std::vec::Vec;

use collections::hashmap::HashMap;

use time;

use HTTP = http::server::Server;

///A handler function for routing.
pub type HandlerFn = fn(&Request, &mut Response);

#[deriving(Clone)]
pub struct Server {
	///A routing tree with response handlers
	pub handlers: Router<HandlerFn>,

	///The port where the server will listen for requests
	pub port: Port
}

impl Server {
	///Start the server and run forever.
	///This will only return if the initial connection fails.
	pub fn run(&self) {
		self.clone().serve_forever();
	}
}

impl HTTP for Server {
	fn get_config(&self) -> Config {
		Config {
			bind_address: SocketAddr {
				ip: Ipv4Addr(0, 0, 0, 0),
				port: self.port
			}
		}
	}

	fn handle_request(&self, request: &http::server::request::Request, writer: &mut ResponseWriter) {
		let mut response = Response::new(writer);
		response.headers.date = Some(time::now_utc());
		response.headers.content_type = Some(MediaType {
			type_: StrBuf::from_str("text"),
			subtype: StrBuf::from_str("plain"),
			parameters: vec!((StrBuf::from_str("charset"), StrBuf::from_str("UTF-8")))
		});
		response.headers.server = Some(StrBuf::from_str("rustful"));

		let found = match build_request(request) {
			Some(mut request) => match self.handlers.find(request.method.clone(), request.path) {
				Some((&handler, variables)) => {
					request.variables = variables;
					handler(&request, &mut response);
					true
				},
				None => false
			},
			None => false
		};

		if !found {
			let content = bytes!("File not found");
			response.headers.content_length = Some(content.len());
			response.status = NotFound;
			match response.write(content) {
				Err(e) => println!("error while writing 404: {}", e),
				_ => {}
			}
		}

		response.end();
	}
}

fn build_request<'a>(request: &'a http::server::request::Request) -> Option<Request<'a>> {
	let path = match request.request_uri {
		AbsoluteUri(ref url) => {
			Some((url.path.as_slice(), url.query.iter().map(|v| v.clone()).collect(), url.fragment.as_ref().map(|v| v.as_slice())))
		},
		AbsolutePath(ref path) => Some(parse_path(path.as_slice())),
		_ => None
	};

	match path {
		Some((path, query, fragment)) => {
			let post = if request.method == Post {
				parse_parameters(request.body.as_slice())
			} else {
				HashMap::new()
			};

			Some(Request {
				headers: *request.headers.clone(),
				method: request.method.clone(),
				path: path,
				variables: HashMap::new(),
				post: post,
				query: query,
				fragment: fragment,
				body: request.body.as_slice()
			})
		}
		None => None
	}
}

fn parse_parameters(source: &str) -> HashMap<~str, ~str> {
	let mut parameters = HashMap::new();
	for parameter in source.split('&') {
		let parts: Vec<&str> = parameter.split('=').collect();
		match parts.as_slice() {
			[name, value] => {
				parameters.insert(url_decode(name), url_decode(value));
			},
			[name] => {
				parameters.insert(url_decode(name), "".to_owned());
			},
			[name, value, ..] => {
				parameters.insert(url_decode(name), url_decode(value));
			},
			[] => {}
		}
	}

	parameters
}

fn parse_path<'a>(path: &'a str) -> (&'a str, HashMap<~str, ~str>, Option<&'a str>) {
	match path.find('?') {
		Some(index) => {
			let (query, fragment) = parse_fragment(path.slice(index+1, path.len()));
			(path.slice(0, index), parse_parameters(query), fragment)
		},
		None => {
			let (path, fragment) = parse_fragment(path);
			(path, HashMap::new(), fragment)
		}
	}
}

fn parse_fragment<'a>(path: &'a str) -> (&'a str, Option<&'a str>) {
	match path.find('#') {
		Some(index) => (path.slice(0, index), Some(path.slice(index+1, path.len()))),
		None => (path, None)
	}
}

fn url_decode(string: &str) -> ~str {
	let mut rdr = BufReader::new(string.as_bytes());
	let mut out = Vec::new();

	loop {
		let mut buf = [0];
		let ch = match rdr.read(buf) {
			Err(..) => break,
			Ok(..) => buf[0] as char
		};
		match ch {
			'+' => out.push(' ' as u8),
			'%' => {
				let mut bytes = [0, 0];
				match rdr.read(bytes) {
					Ok(2) => {}
					_ => fail!()
				}
				let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8;
				out.push(ch);
			}
			ch => out.push(ch as u8)
		}
	}

	from_utf8_owned(out.as_slice().to_owned()).unwrap_or(string.to_owned())
}

#[test]
fn parsing_parameters() {
	let parameters = parse_parameters("a=1&aa=2&ab=202");
	let a = "1".to_owned();
	let aa = "2".to_owned();
	let ab = "202".to_owned();
	assert_eq!(parameters.find(&"a".to_owned()), Some(&a));
	assert_eq!(parameters.find(&"aa".to_owned()), Some(&aa));
	assert_eq!(parameters.find(&"ab".to_owned()), Some(&ab));
}

#[test]
fn parsing_parameters_with_plus() {
	let parameters = parse_parameters("a=1&aa=2+%2B+extra+meat&ab=202+fifth+avenue");
	let a = "1".to_owned();
	let aa = "2 + extra meat".to_owned();
	let ab = "202 fifth avenue".to_owned();
	assert_eq!(parameters.find(&"a".to_owned()), Some(&a));
	assert_eq!(parameters.find(&"aa".to_owned()), Some(&aa));
	assert_eq!(parameters.find(&"ab".to_owned()), Some(&ab));
}

#[test]
fn parsing_strange_parameters() {
	let parameters = parse_parameters("a=1=2&=2&ab=");
	let a = "1".to_owned();
	let aa = "2".to_owned();
	let ab = "".to_owned();
	assert_eq!(parameters.find(&"a".to_owned()), Some(&a));
	assert_eq!(parameters.find(&"".to_owned()), Some(&aa));
	assert_eq!(parameters.find(&"ab".to_owned()), Some(&ab));
}

#[test]
fn parse_path_parts() {
	let with = "this".to_owned();
	let and = "that".to_owned();
	let (path, query, fragment) = parse_path("/path/to/something?with=this&and=that#lol");
	assert_eq!(path, "/path/to/something");
	assert_eq!(query.find(&"with".to_owned()), Some(&with));
	assert_eq!(query.find(&"and".to_owned()), Some(&and));
	assert_eq!(fragment, Some("lol"));
}

#[test]
fn parse_strange_path() {
	let with = "this".to_owned();
	let and = "what?".to_owned();
	let (path, query, fragment) = parse_path("/path/to/something?with=this&and=what?#");
	assert_eq!(path, "/path/to/something");
	assert_eq!(query.find(&"with".to_owned()), Some(&with));
	assert_eq!(query.find(&"and".to_owned()), Some(&and));
	assert_eq!(fragment, Some(""));
}

#[test]
fn parse_missing_path_parts() {
	let with = "this".to_owned();
	let and = "that".to_owned();
	let (path, query, fragment) = parse_path("/path/to/something?with=this&and=that");
	assert_eq!(path, "/path/to/something");
	assert_eq!(query.find(&"with".to_owned()), Some(&with));
	assert_eq!(query.find(&"and".to_owned()), Some(&and));
	assert_eq!(fragment, None);

	let (path, query, fragment) = parse_path("/path/to/something#lol");
	assert_eq!(path, "/path/to/something");
	assert_eq!(query.len(), 0);
	assert_eq!(fragment, Some("lol"));

	let (path, query, fragment) = parse_path("?with=this&and=that#lol");
	assert_eq!(path, "");
	assert_eq!(query.find(&"with".to_owned()), Some(&with));
	assert_eq!(query.find(&"and".to_owned()), Some(&and));
	assert_eq!(fragment, Some("lol"));
}<commit_msg>Rewrote parse_parameters to be more lazy<commit_after>//! `Server` listens for HTTP requests.
//!
//!```rust
//!# use rustful::server::Server;
//!# use rustful::router::Router;
//!# let routes = [];
//!let server = Server {
//!	handlers: Router::from_routes(routes),
//!	port: 8080
//!};
//!
//!server.run();
//!```

use router::Router;
use request::Request;
use response::Response;
use response::status::NotFound;

use http;
use http::server::{ResponseWriter, Config};
use http::server::request::{AbsoluteUri, AbsolutePath};
use http::headers::content_type::MediaType;
use http::method::Post;

use std::io::net::ip::{SocketAddr, Ipv4Addr, Port};
use std::str::from_utf8_owned;
use std::uint;
use std::io::BufReader;
use std::vec::Vec;

use collections::hashmap::HashMap;

use time;

use HTTP = http::server::Server;

///A handler function for routing.
pub type HandlerFn = fn(&Request, &mut Response);

#[deriving(Clone)]
pub struct Server {
	///A routing tree with response handlers
	pub handlers: Router<HandlerFn>,

	///The port where the server will listen for requests
	pub port: Port
}

impl Server {
	///Start the server and run forever.
	///This will only return if the initial connection fails.
	pub fn run(&self) {
		self.clone().serve_forever();
	}
}

impl HTTP for Server {
	fn get_config(&self) -> Config {
		Config {
			bind_address: SocketAddr {
				ip: Ipv4Addr(0, 0, 0, 0),
				port: self.port
			}
		}
	}

	fn handle_request(&self, request: &http::server::request::Request, writer: &mut ResponseWriter) {
		let mut response = Response::new(writer);
		response.headers.date = Some(time::now_utc());
		response.headers.content_type = Some(MediaType {
			type_: StrBuf::from_str("text"),
			subtype: StrBuf::from_str("plain"),
			parameters: vec!((StrBuf::from_str("charset"), StrBuf::from_str("UTF-8")))
		});
		response.headers.server = Some(StrBuf::from_str("rustful"));

		let found = match build_request(request) {
			Some(mut request) => match self.handlers.find(request.method.clone(), request.path) {
				Some((&handler, variables)) => {
					request.variables = variables;
					handler(&request, &mut response);
					true
				},
				None => false
			},
			None => false
		};

		if !found {
			let content = bytes!("File not found");
			response.headers.content_length = Some(content.len());
			response.status = NotFound;
			match response.write(content) {
				Err(e) => println!("error while writing 404: {}", e),
				_ => {}
			}
		}

		response.end();
	}
}

fn build_request<'a>(request: &'a http::server::request::Request) -> Option<Request<'a>> {
	let path = match request.request_uri {
		AbsoluteUri(ref url) => {
			Some((url.path.as_slice(), url.query.iter().map(|v| v.clone()).collect(), url.fragment.as_ref().map(|v| v.as_slice())))
		},
		AbsolutePath(ref path) => Some(parse_path(path.as_slice())),
		_ => None
	};

	match path {
		Some((path, query, fragment)) => {
			let post = if request.method == Post {
				parse_parameters(request.body.as_slice())
			} else {
				HashMap::new()
			};

			Some(Request {
				headers: *request.headers.clone(),
				method: request.method.clone(),
				path: path,
				variables: HashMap::new(),
				post: post,
				query: query,
				fragment: fragment,
				body: request.body.as_slice()
			})
		}
		None => None
	}
}

fn parse_parameters(source: &str) -> HashMap<~str, ~str> {
	let mut parameters = HashMap::new();
	for parameter in source.split('&') {
		let mut parts = parameter.split('=');
		parts.next().map(|name|
			parameters.insert(
				url_decode(name),
				parts.next().map(|v| url_decode(v)).unwrap_or_else(|| "".to_owned())
			)
		);
	}

	parameters
}

fn parse_path<'a>(path: &'a str) -> (&'a str, HashMap<~str, ~str>, Option<&'a str>) {
	match path.find('?') {
		Some(index) => {
			let (query, fragment) = parse_fragment(path.slice(index+1, path.len()));
			(path.slice(0, index), parse_parameters(query), fragment)
		},
		None => {
			let (path, fragment) = parse_fragment(path);
			(path, HashMap::new(), fragment)
		}
	}
}

fn parse_fragment<'a>(path: &'a str) -> (&'a str, Option<&'a str>) {
	match path.find('#') {
		Some(index) => (path.slice(0, index), Some(path.slice(index+1, path.len()))),
		None => (path, None)
	}
}

fn url_decode(string: &str) -> ~str {
	let mut rdr = BufReader::new(string.as_bytes());
	let mut out = Vec::new();

	loop {
		let mut buf = [0];
		let ch = match rdr.read(buf) {
			Err(..) => break,
			Ok(..) => buf[0] as char
		};
		match ch {
			'+' => out.push(' ' as u8),
			'%' => {
				let mut bytes = [0, 0];
				match rdr.read(bytes) {
					Ok(2) => {}
					_ => fail!()
				}
				let ch = uint::parse_bytes(bytes, 16u).unwrap() as u8;
				out.push(ch);
			}
			ch => out.push(ch as u8)
		}
	}

	from_utf8_owned(out.as_slice().to_owned()).unwrap_or(string.to_owned())
}

#[test]
fn parsing_parameters() {
	let parameters = parse_parameters("a=1&aa=2&ab=202");
	let a = "1".to_owned();
	let aa = "2".to_owned();
	let ab = "202".to_owned();
	assert_eq!(parameters.find(&"a".to_owned()), Some(&a));
	assert_eq!(parameters.find(&"aa".to_owned()), Some(&aa));
	assert_eq!(parameters.find(&"ab".to_owned()), Some(&ab));
}

#[test]
fn parsing_parameters_with_plus() {
	let parameters = parse_parameters("a=1&aa=2+%2B+extra+meat&ab=202+fifth+avenue");
	let a = "1".to_owned();
	let aa = "2 + extra meat".to_owned();
	let ab = "202 fifth avenue".to_owned();
	assert_eq!(parameters.find(&"a".to_owned()), Some(&a));
	assert_eq!(parameters.find(&"aa".to_owned()), Some(&aa));
	assert_eq!(parameters.find(&"ab".to_owned()), Some(&ab));
}

#[test]
fn parsing_strange_parameters() {
	let parameters = parse_parameters("a=1=2&=2&ab=");
	let a = "1".to_owned();
	let aa = "2".to_owned();
	let ab = "".to_owned();
	assert_eq!(parameters.find(&"a".to_owned()), Some(&a));
	assert_eq!(parameters.find(&"".to_owned()), Some(&aa));
	assert_eq!(parameters.find(&"ab".to_owned()), Some(&ab));
}

#[test]
fn parse_path_parts() {
	let with = "this".to_owned();
	let and = "that".to_owned();
	let (path, query, fragment) = parse_path("/path/to/something?with=this&and=that#lol");
	assert_eq!(path, "/path/to/something");
	assert_eq!(query.find(&"with".to_owned()), Some(&with));
	assert_eq!(query.find(&"and".to_owned()), Some(&and));
	assert_eq!(fragment, Some("lol"));
}

#[test]
fn parse_strange_path() {
	let with = "this".to_owned();
	let and = "what?".to_owned();
	let (path, query, fragment) = parse_path("/path/to/something?with=this&and=what?#");
	assert_eq!(path, "/path/to/something");
	assert_eq!(query.find(&"with".to_owned()), Some(&with));
	assert_eq!(query.find(&"and".to_owned()), Some(&and));
	assert_eq!(fragment, Some(""));
}

#[test]
fn parse_missing_path_parts() {
	let with = "this".to_owned();
	let and = "that".to_owned();
	let (path, query, fragment) = parse_path("/path/to/something?with=this&and=that");
	assert_eq!(path, "/path/to/something");
	assert_eq!(query.find(&"with".to_owned()), Some(&with));
	assert_eq!(query.find(&"and".to_owned()), Some(&and));
	assert_eq!(fragment, None);

	let (path, query, fragment) = parse_path("/path/to/something#lol");
	assert_eq!(path, "/path/to/something");
	assert_eq!(query.len(), 0);
	assert_eq!(fragment, Some("lol"));

	let (path, query, fragment) = parse_path("?with=this&and=that#lol");
	assert_eq!(path, "");
	assert_eq!(query.find(&"with".to_owned()), Some(&with));
	assert_eq!(query.find(&"and".to_owned()), Some(&and));
	assert_eq!(fragment, Some("lol"));
}<|endoftext|>


<commit_before>use std::net::TcpListener;
use std::net::TcpStream;
use std::fmt;
use std::io::Cursor;
use std::io::Read;

use solicit::server::SimpleServer;
use solicit::http::server::StreamFactory;
use solicit::http::server::ServerConnection;
use solicit::http::server::ServerSession;
use solicit::http::HttpScheme;
use solicit::http::StreamId;
use solicit::http::Header;
use solicit::http::OwnedHeader;
use solicit::http::HttpResult;
use solicit::http::priority::SimplePrioritizer;
use solicit::http::connection::HttpConnection;
use solicit::http::connection::EndStream;
use solicit::http::connection::SendStatus;
use solicit::http::connection::SendFrame;
use solicit::http::session::SessionState;
use solicit::http::session::DefaultSessionState;
use solicit::http::session::DefaultStream;
use solicit::http::session::Stream;
use solicit::http::session::Server;
use solicit::http::session::StreamState;
use solicit::http::session::StreamDataChunk;
use solicit::http::session::StreamDataError;
use solicit::http::transport::TransportStream;
use solicit::http::transport::TransportReceiveFrame;

use grpc;
use method::ServerServiceDefinition;

struct BsDebug<'a>(&'a [u8]);

impl<'a> fmt::Debug for BsDebug<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(fmt, "b\""));
        let u8a: &[u8] = self.0;
        for &c in u8a {
            // ASCII printable
            if c >= 0x20 && c < 0x7f {
                try!(write!(fmt, "{}", c as char));
            } else {
                try!(write!(fmt, "\\x{:02x}", c));
            }
        }
        try!(write!(fmt, "\""));
    	Ok(())
    }
}

struct HeaderDebug<'a>(&'a Header<'a, 'a>);

impl<'a> fmt::Debug for HeaderDebug<'a> {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
	    write!(fmt, "Header {{ name: {:?}, value: {:?} }}",
	    	BsDebug(self.0.name()), BsDebug(self.0.value()))
	}
}

struct GrpcStream {
    stream_id: Option<StreamId>,
    headers: Option<Vec<Header<'static, 'static>>>,
    body: Vec<u8>,
    state: StreamState,
    data: Option<Cursor<Vec<u8>>>,

    buf: Vec<u8>,
    resp: Vec<u8>,
    service_definition: ServerServiceDefinition,
    path: String,
}

impl GrpcStream {
    fn with_id(stream_id: StreamId) -> Self {
        println!("new stream {}", stream_id);
        GrpcStream {
            stream_id: Some(stream_id),
            headers: None,
            body: Vec::new(),
            state: StreamState::Open,
            data: None,
            buf: Vec::new(),
            resp: Vec::new(),
            service_definition: ServerServiceDefinition::new(Vec::new()),
            path: String::new(),
        }
    }

    fn process_buf(&mut self) {
        loop {
            let (r, pos) = match grpc::parse_frame(&self.buf) {
                Some((frame, pos)) => {
                    let r = self.service_definition.handle_method(&self.path, frame);
                    (r, pos)
                }
                None => return,
            };

            self.buf.drain(..pos);
            self.resp.extend(r);
        }
    }
}

impl Stream for GrpcStream {
    fn set_headers(&mut self, headers: Vec<Header>) {
        for h in &headers {
            if h.name() == b":path" {
                self.path = String::from_utf8(h.value().to_owned()).unwrap();
            }
        }
        println!("headers: {:?}", headers.iter().map(|h| HeaderDebug(h)).collect::<Vec<_>>());
        self.headers = Some(headers.into_iter().map(|h| {
            let owned: OwnedHeader = h.into();
            owned.into()
        }).collect());
    }

    fn new_data_chunk(&mut self, data: &[u8]) {
        println!("hooray! data: {:?}", data);
        self.buf.extend(data);
        self.process_buf();
        println!("{:?}", grpc::parse_frame(data));
        self.body.extend(data.to_vec().into_iter());
    }

    fn set_state(&mut self, state: StreamState) {
        println!("set_state: {:?}", state);
        self.state = state;
        println!("s: {:?}", BsDebug(&self.body));
    }

    fn get_data_chunk(&mut self, buf: &mut [u8]) -> Result<StreamDataChunk, StreamDataError> {
        println!("get_data_chunk");
        if self.is_closed_local() {
            return Err(StreamDataError::Closed);
        }
        let chunk = match self.data.as_mut() {
            // No data associated to the stream, but it's open => nothing available for writing
            None => StreamDataChunk::Unavailable,
            Some(d) =>  {
                // For the `Vec`-backed reader, this should never fail, so unwrapping is
                // fine.
                let read = d.read(buf).unwrap();
                if (d.position() as usize) == d.get_ref().len() {
                    StreamDataChunk::Last(read)
                } else {
                    StreamDataChunk::Chunk(read)
                }
            }
        };
        // Transition the stream state to locally closed if we've extracted the final data chunk.
        match chunk {
            StreamDataChunk::Last(_) => self.close_local(),
            _ => {},
        };

        Ok(chunk)
    }

    fn state(&self) -> StreamState {
        self.state
    }
}

/*
struct GrpcSessionState {
    default_state: DefaultSessionState,
}

impl GrpcSessionState {
    fn new() -> Self {
        GrpcSessionState {
            default_state: DefaultSessionState::new(),
        }
    }
}
*/

struct GrpcStreamFactory;

impl StreamFactory for GrpcStreamFactory {
	type Stream = GrpcStream;

	fn create(&mut self, id: StreamId) -> GrpcStream {
		GrpcStream::with_id(id)
	}
}

struct GrpcServerConnection {
    conn: HttpConnection,
    factory: GrpcStreamFactory,
    state: DefaultSessionState<Server, GrpcStream>,
    receiver: TcpStream,
    sender: TcpStream,
}

impl GrpcServerConnection {
    fn new(mut stream: TcpStream) -> GrpcServerConnection {
        let mut preface = [0; 24];

        (&mut stream as &mut Read).read_exact(&mut preface).unwrap();
        if &preface != b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" {
            panic!();
        }

        let conn = HttpConnection::new(HttpScheme::Http);

		let mut xx: TcpStream = stream.try_split().unwrap();
        let mut r = GrpcServerConnection {
            conn: conn,
            state: DefaultSessionState::<Server, _>::new(),
            receiver: xx,
            sender: stream,
            factory: GrpcStreamFactory,
        };

        //r.server_conn.init().unwrap();
        r
    }

    fn handle_requests(&mut self) -> HttpResult<Vec<(StreamId, Vec<u8>)>> {
        Ok(self.state.iter().flat_map(|(&id, s)| {
            if s.resp.is_empty() {
                None
            } else {
                Some((id, s.resp.clone()))
            }
        }).collect())
    }

    pub fn send_headers<'n, 'v>(
            &mut self,
            headers: Vec<Header<'n, 'v>>,
            stream_id: StreamId,
            end_stream: EndStream)
            -> HttpResult<()>
    {
        self.conn.sender(&mut self.sender).send_headers(
            headers,
            stream_id,
            end_stream)
    }

    fn prepare_responses(&mut self, responses: Vec<(StreamId, Vec<u8>)>) -> HttpResult<()> {
        for r in responses {
            try!(self.send_headers(
                Vec::new(),
                r.0,
                EndStream::No
            ));
            let mut stream = self.state.get_stream_mut(r.0).unwrap();
            stream.data = Some(Cursor::new(r.1));
        }
        Ok(())
    }

    fn send_next_data(&mut self) -> HttpResult<SendStatus> {
        const MAX_CHUNK_SIZE: usize = 8 * 1024;
        let mut buf = [0; MAX_CHUNK_SIZE];

        // TODO: Additionally account for the flow control windows.
        let mut prioritizer = SimplePrioritizer::new(&mut self.state, &mut buf);

        self.conn.sender(&mut self.sender).send_next_data(&mut prioritizer)
    }

    fn flush_streams(&mut self) -> HttpResult<()> {
        while let SendStatus::Sent = try!(self.send_next_data()) {}

        Ok(())
    }

    fn reap_streams(&mut self) {
        // Moves the streams out of the state and then drops them
        let closed = self.state.get_closed();
        println!("closed: {:?}", closed.iter().map(|s| s.stream_id).collect::<Vec<_>>());
    }

    pub fn handle_next_frame(&mut self) -> HttpResult<()> {
        let mut rx = TransportReceiveFrame::new(&mut self.receiver);
        let mut session = ServerSession::new(&mut self.state, &mut self.factory, &mut self.sender);
        self.conn.handle_next_frame(&mut rx, &mut session)
    }

    fn handle_next(&mut self) -> HttpResult<()> {
        try!(self.handle_next_frame());

        let responses = try!(self.handle_requests());

		try!(self.prepare_responses(responses));

        try!(self.flush_streams());
        self.reap_streams();

        Ok(())
    }

    fn run(&mut self) {
        loop {
            let r = self.handle_next();
            match r {
                e @ Err(..) => {
                    println!("{:?}", e);
                    return;
                }
                _ => {},
            }
        }
    }
}

pub struct GrpcServer {
    listener: TcpListener,
}

impl GrpcServer {
    pub fn new() -> GrpcServer {
        GrpcServer {
            listener: TcpListener::bind("127.0.0.1:50051").unwrap(),
        }
    }

    pub fn run(&mut self) {
        for mut stream in self.listener.incoming().map(|s| s.unwrap()) {
            println!("client connected!");
            GrpcServerConnection::new(stream).run();
        }
    }
}

<commit_msg>backup<commit_after>use std::net::TcpListener;
use std::net::TcpStream;
use std::fmt;
use std::io::Cursor;
use std::io::Read;

use solicit::server::SimpleServer;
use solicit::http::server::StreamFactory;
use solicit::http::server::ServerConnection;
use solicit::http::server::ServerSession;
use solicit::http::HttpScheme;
use solicit::http::StreamId;
use solicit::http::Header;
use solicit::http::OwnedHeader;
use solicit::http::HttpResult;
use solicit::http::priority::SimplePrioritizer;
use solicit::http::connection::HttpConnection;
use solicit::http::connection::EndStream;
use solicit::http::connection::SendStatus;
use solicit::http::connection::SendFrame;
use solicit::http::session::SessionState;
use solicit::http::session::DefaultSessionState;
use solicit::http::session::DefaultStream;
use solicit::http::session::Stream;
use solicit::http::session::Server;
use solicit::http::session::StreamState;
use solicit::http::session::StreamDataChunk;
use solicit::http::session::StreamDataError;
use solicit::http::transport::TransportStream;
use solicit::http::transport::TransportReceiveFrame;

use grpc;
use method::ServerServiceDefinition;

struct BsDebug<'a>(&'a [u8]);

impl<'a> fmt::Debug for BsDebug<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        try!(write!(fmt, "b\""));
        let u8a: &[u8] = self.0;
        for &c in u8a {
            // ASCII printable
            if c >= 0x20 && c < 0x7f {
                try!(write!(fmt, "{}", c as char));
            } else {
                try!(write!(fmt, "\\x{:02x}", c));
            }
        }
        try!(write!(fmt, "\""));
    	Ok(())
    }
}

struct HeaderDebug<'a>(&'a Header<'a, 'a>);

impl<'a> fmt::Debug for HeaderDebug<'a> {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
	    write!(fmt, "Header {{ name: {:?}, value: {:?} }}",
	    	BsDebug(self.0.name()), BsDebug(self.0.value()))
	}
}

struct GrpcStream {
    stream_id: Option<StreamId>,
    headers: Option<Vec<Header<'static, 'static>>>,
    body: Vec<u8>,
    state: StreamState,
    data: Option<Cursor<Vec<u8>>>,

    buf: Vec<u8>,
    resp: Vec<u8>,
    service_definition: ServerServiceDefinition,
    path: String,
}

impl GrpcStream {
    fn with_id(stream_id: StreamId) -> Self {
        println!("new stream {}", stream_id);
        GrpcStream {
            stream_id: Some(stream_id),
            headers: None,
            body: Vec::new(),
            state: StreamState::Open,
            data: None,
            buf: Vec::new(),
            resp: Vec::new(),
            service_definition: ServerServiceDefinition::new(Vec::new()),
            path: String::new(),
        }
    }

    fn process_buf(&mut self) {
        loop {
            let (r, pos) = match grpc::parse_frame(&self.buf) {
                Some((frame, pos)) => {
                    let r = self.service_definition.handle_method(&self.path, frame);
                    (r, pos)
                }
                None => return,
            };

            self.buf.drain(..pos);
            self.resp.extend(r);
        }
    }
}

impl Stream for GrpcStream {
    fn set_headers(&mut self, headers: Vec<Header>) {
        for h in &headers {
            if h.name() == b":path" {
                self.path = String::from_utf8(h.value().to_owned()).unwrap();
            }
        }
        println!("headers: {:?}", headers.iter().map(|h| HeaderDebug(h)).collect::<Vec<_>>());
        self.headers = Some(headers.into_iter().map(|h| {
            let owned: OwnedHeader = h.into();
            owned.into()
        }).collect());
    }

    fn new_data_chunk(&mut self, data: &[u8]) {
        println!("hooray! data: {:?}", data);
        self.buf.extend(data);
        self.process_buf();
        println!("{:?}", grpc::parse_frame(data));
        self.body.extend(data.to_vec().into_iter());
    }

    fn set_state(&mut self, state: StreamState) {
        println!("set_state: {:?}", state);
        self.state = state;
        println!("s: {:?}", BsDebug(&self.body));
    }

    fn get_data_chunk(&mut self, buf: &mut [u8]) -> Result<StreamDataChunk, StreamDataError> {
        println!("get_data_chunk");
        if self.is_closed_local() {
            return Err(StreamDataError::Closed);
        }
        let chunk = match self.data.as_mut() {
            // No data associated to the stream, but it's open => nothing available for writing
            None => StreamDataChunk::Unavailable,
            Some(d) =>  {
                // For the `Vec`-backed reader, this should never fail, so unwrapping is
                // fine.
                let read = d.read(buf).unwrap();
                if (d.position() as usize) == d.get_ref().len() {
                    StreamDataChunk::Last(read)
                } else {
                    StreamDataChunk::Chunk(read)
                }
            }
        };
        // Transition the stream state to locally closed if we've extracted the final data chunk.
        match chunk {
            StreamDataChunk::Last(_) => self.close_local(),
            _ => {},
        };

        Ok(chunk)
    }

    fn state(&self) -> StreamState {
        self.state
    }
}

/*
struct GrpcSessionState {
    default_state: DefaultSessionState,
}

impl GrpcSessionState {
    fn new() -> Self {
        GrpcSessionState {
            default_state: DefaultSessionState::new(),
        }
    }
}
*/

struct GrpcStreamFactory;

impl StreamFactory for GrpcStreamFactory {
	type Stream = GrpcStream;

	fn create(&mut self, id: StreamId) -> GrpcStream {
		GrpcStream::with_id(id)
	}
}

struct GrpcServerConnection {
    conn: HttpConnection,
    factory: GrpcStreamFactory,
    state: DefaultSessionState<Server, GrpcStream>,
    receiver: TcpStream,
    sender: TcpStream,
}

impl GrpcServerConnection {
    fn new(mut stream: TcpStream) -> GrpcServerConnection {
        let mut preface = [0; 24];

        (&mut stream as &mut Read).read_exact(&mut preface).unwrap();
        if &preface != b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" {
            panic!();
        }

        let conn = HttpConnection::new(HttpScheme::Http);

		let mut xx: TcpStream = stream.try_split().unwrap();
        let mut r = GrpcServerConnection {
            conn: conn,
            state: DefaultSessionState::<Server, _>::new(),
            receiver: xx,
            sender: stream,
            factory: GrpcStreamFactory,
        };

        //r.server_conn.init().unwrap();
        r
    }

    fn handle_requests(&mut self) -> HttpResult<Vec<(StreamId, Vec<u8>)>> {
        Ok(self.state.iter().flat_map(|(&id, s)| {
            if s.resp.is_empty() {
                None
            } else {
                Some((id, s.resp.clone()))
            }
        }).collect())
    }

    fn prepare_responses(&mut self, responses: Vec<(StreamId, Vec<u8>)>) -> HttpResult<()> {
        for r in responses {
            try!(self.conn.sender(&mut self.sender).send_headers(
                Vec::new(),
                r.0,
                EndStream::No));
            let mut stream = self.state.get_stream_mut(r.0).unwrap();
            stream.data = Some(Cursor::new(r.1));
        }
        Ok(())
    }

    fn send_next_data(&mut self) -> HttpResult<SendStatus> {
        const MAX_CHUNK_SIZE: usize = 8 * 1024;
        let mut buf = [0; MAX_CHUNK_SIZE];

        // TODO: Additionally account for the flow control windows.
        let mut prioritizer = SimplePrioritizer::new(&mut self.state, &mut buf);

        self.conn.sender(&mut self.sender).send_next_data(&mut prioritizer)
    }

    fn flush_streams(&mut self) -> HttpResult<()> {
        while let SendStatus::Sent = try!(self.send_next_data()) {}

        Ok(())
    }

    fn reap_streams(&mut self) {
        // Moves the streams out of the state and then drops them
        let closed = self.state.get_closed();
        println!("closed: {:?}", closed.iter().map(|s| s.stream_id).collect::<Vec<_>>());
    }

    pub fn handle_next_frame(&mut self) -> HttpResult<()> {
        let mut rx = TransportReceiveFrame::new(&mut self.receiver);
        let mut session = ServerSession::new(&mut self.state, &mut self.factory, &mut self.sender);
        self.conn.handle_next_frame(&mut rx, &mut session)
    }

    fn handle_next(&mut self) -> HttpResult<()> {
        try!(self.handle_next_frame());

        let responses = try!(self.handle_requests());

		try!(self.prepare_responses(responses));

        try!(self.flush_streams());
        self.reap_streams();

        Ok(())
    }

    fn run(&mut self) {
        loop {
            let r = self.handle_next();
            match r {
                e @ Err(..) => {
                    println!("{:?}", e);
                    return;
                }
                _ => {},
            }
        }
    }
}

pub struct GrpcServer {
    listener: TcpListener,
}

impl GrpcServer {
    pub fn new() -> GrpcServer {
        GrpcServer {
            listener: TcpListener::bind("127.0.0.1:50051").unwrap(),
        }
    }

    pub fn run(&mut self) {
        for mut stream in self.listener.incoming().map(|s| s.unwrap()) {
            println!("client connected!");
            GrpcServerConnection::new(stream).run();
        }
    }
}

<|endoftext|>


<commit_before>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `IMPL` Low level signal support.

use libc::{c_void, c_uint, c_ulong};

use gobject_ffi::{self, GCallback};
use ffi::{gboolean, GQuark};
use object::{IsA, Object};
use source::CallbackGuard;
use translate::{from_glib, FromGlib, ToGlib, ToGlibPtr};

/// The id of a signal that is returned by `connect`.
#[derive(Debug, Eq, PartialEq)]
pub struct SignalHandlerId(c_ulong);

impl ToGlib for SignalHandlerId {
    type GlibType = c_ulong;

    #[inline]
    fn to_glib(&self) -> c_ulong {
        self.0
    }
}

impl FromGlib<c_ulong> for SignalHandlerId {
    #[inline]
    fn from_glib(val: c_ulong) -> SignalHandlerId {
        assert_ne!(val, 0);
        SignalHandlerId(val)
    }
}

/// Whether to propagate the signal to the default handler.
///
/// Don't inhibit default handlers without a reason, they're usually helpful.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Inhibit(pub bool);

#[doc(hidden)]
impl ToGlib for Inhibit {
    type GlibType = gboolean;

    #[inline]
    fn to_glib(&self) -> gboolean {
        self.0.to_glib()
    }
}

pub unsafe fn connect(receiver: *mut gobject_ffi::GObject, signal_name: &str, trampoline: GCallback,
                      closure: *mut Box<Fn() + 'static>) -> SignalHandlerId {
    let handle = gobject_ffi::g_signal_connect_data(receiver, signal_name.to_glib_none().0,
        trampoline, closure as *mut _, Some(destroy_closure),
        gobject_ffi::GConnectFlags::empty());
    assert!(handle > 0);
    from_glib(handle)
}

pub fn signal_handler_block<T: IsA<Object>>(instance: &T, handler_id: &SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_block(instance.to_glib_none().0, handler_id.to_glib());
    }
}

pub fn signal_handler_unblock<T: IsA<Object>>(instance: &T, handler_id: &SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_unblock(instance.to_glib_none().0, handler_id.to_glib());
    }
}

pub fn signal_handler_disconnect<T: IsA<Object>>(instance: &T, handler_id: SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_disconnect(instance.to_glib_none().0, handler_id.to_glib());
    }
}

pub fn signal_stop_emission<T: IsA<Object>>(instance: &T, signal_id: u32, detail: GQuark) {
    unsafe {
        gobject_ffi::g_signal_stop_emission(instance.to_glib_none().0, signal_id as c_uint, detail);
    }
}

pub fn signal_stop_emission_by_name<T: IsA<Object>>(instance: &T, signal_name: &str) {
    unsafe {
        gobject_ffi::g_signal_stop_emission_by_name(instance.to_glib_none().0, signal_name.to_glib_none().0);
    }
}

unsafe extern "C" fn destroy_closure(ptr: *mut c_void, _: *mut gobject_ffi::GClosure) {
    let _guard = CallbackGuard::new();
    // destroy
    Box::<Box<Fn()>>::from_raw(ptr as *mut _);
}
<commit_msg>Fix flag usage<commit_after>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! `IMPL` Low level signal support.

use libc::{c_void, c_uint, c_ulong};

use gobject_ffi::{self, GCallback};
use ffi::{gboolean, GQuark};
use object::{IsA, Object};
use source::CallbackGuard;
use translate::{from_glib, FromGlib, ToGlib, ToGlibPtr};

/// The id of a signal that is returned by `connect`.
#[derive(Debug, Eq, PartialEq)]
pub struct SignalHandlerId(c_ulong);

impl ToGlib for SignalHandlerId {
    type GlibType = c_ulong;

    #[inline]
    fn to_glib(&self) -> c_ulong {
        self.0
    }
}

impl FromGlib<c_ulong> for SignalHandlerId {
    #[inline]
    fn from_glib(val: c_ulong) -> SignalHandlerId {
        assert_ne!(val, 0);
        SignalHandlerId(val)
    }
}

/// Whether to propagate the signal to the default handler.
///
/// Don't inhibit default handlers without a reason, they're usually helpful.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Inhibit(pub bool);

#[doc(hidden)]
impl ToGlib for Inhibit {
    type GlibType = gboolean;

    #[inline]
    fn to_glib(&self) -> gboolean {
        self.0.to_glib()
    }
}

pub unsafe fn connect(receiver: *mut gobject_ffi::GObject, signal_name: &str, trampoline: GCallback,
                      closure: *mut Box<Fn() + 'static>) -> SignalHandlerId {
    let handle = gobject_ffi::g_signal_connect_data(receiver, signal_name.to_glib_none().0,
        trampoline, closure as *mut _, Some(destroy_closure), 0);
    assert!(handle > 0);
    from_glib(handle)
}

pub fn signal_handler_block<T: IsA<Object>>(instance: &T, handler_id: &SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_block(instance.to_glib_none().0, handler_id.to_glib());
    }
}

pub fn signal_handler_unblock<T: IsA<Object>>(instance: &T, handler_id: &SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_unblock(instance.to_glib_none().0, handler_id.to_glib());
    }
}

pub fn signal_handler_disconnect<T: IsA<Object>>(instance: &T, handler_id: SignalHandlerId) {
    unsafe {
        gobject_ffi::g_signal_handler_disconnect(instance.to_glib_none().0, handler_id.to_glib());
    }
}

pub fn signal_stop_emission<T: IsA<Object>>(instance: &T, signal_id: u32, detail: GQuark) {
    unsafe {
        gobject_ffi::g_signal_stop_emission(instance.to_glib_none().0, signal_id as c_uint, detail);
    }
}

pub fn signal_stop_emission_by_name<T: IsA<Object>>(instance: &T, signal_name: &str) {
    unsafe {
        gobject_ffi::g_signal_stop_emission_by_name(instance.to_glib_none().0, signal_name.to_glib_none().0);
    }
}

unsafe extern "C" fn destroy_closure(ptr: *mut c_void, _: *mut gobject_ffi::GClosure) {
    let _guard = CallbackGuard::new();
    // destroy
    Box::<Box<Fn()>>::from_raw(ptr as *mut _);
}
<|endoftext|>