<commit_before>use redox::Vec;

use super::from_bytes::FromBytes;
use super::metaslab::{Metaslab, MetaslabGroup};
use super::nvpair::{NvList, NvValue};
use super::zfs;

#[repr(packed)]
pub struct VdevLabel {
    pub blank: [u8; 8 * 1024],
    pub boot_header: [u8; 8 * 1024],
    pub nv_pairs: [u8; 112 * 1024],
    pub uberblocks: [u8; 128 * 1024],
}

impl FromBytes for VdevLabel { }

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

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AllocType {
    Load = 0,
    Add,
    Spare,
    L2Cache,
    RootPool,
    Split,
    Attach,
}

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

/// States are ordered from least to most healthy.
/// Vdevs `CannotOpen` and worse are considered unusable.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum State {
    Unknown,    // Uninitialized vdev
    Closed,     // Not currently open
    Offline,    // Not allowed to open
    Removed,    // Explicitly removed from the system
    CannotOpen, // Tried top open, but failed
    Faulted,    // External request to fault device
    Degraded,   // Replicated vdev with unhealthy kids
    Healthy,    // Presumed good
}

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

pub struct Vdev {
    id: u64, // child number in vdev parent
    guid: u64, // unique ID for this vdev
    guid_sum: u64, // self guid + all child guids
    orig_guid: u64, // orig. guid prior to remove
    asize: u64, // allocatable device capacity
    min_asize: u64, // min acceptable asize
    max_asize: u64, // max acceptable asize
    ashift: u64, // block alignment shift
    state: State,
    prev_state: State,
    //ops: VdevOps,

    // Top level only
    ms_array_object: u64,
    ms_group: MetaslabGroup,
    metaslabs: Vec<Metaslab>,
    is_hole: bool,

    // Leaf only
}

impl Vdev {
    pub fn new(id: u64, guid: u64) -> Self {
        Vdev {
            id: id,
            guid: guid,
            guid_sum: guid, // No children yet, so guid_sum is just my guid
            orig_guid: 0,
            asize: 0,
            min_asize: 0,
            max_asize: 0,
            ashift: 0,
            state: State::Closed,
            prev_state: State::Unknown,

            // Top level only
            ms_array_object: 0,
            ms_group: MetaslabGroup,
            metaslabs: vec![],
            is_hole: false, // TODO: zol checks vdev_ops for this, but idk what to do yet
        }
    }

    pub fn load(nv: &NvList, id: u64, alloc_type: AllocType) -> zfs::Result<Self> {
        if alloc_type == AllocType::Load {
            // Verify the provided id matches the id written in the MOS
            let label_id = try!(nv.find("id").ok_or(zfs::Error::Invalid));
            match *label_id {
                NvValue::Uint64(label_id) => {
                    if label_id != id { return Err(zfs::Error::Invalid); }
                },
                _ => { },
            }
        }

        /*let guid =
            match alloc_type {
                AllocType::Load | AllocType::Spare | AllocType::L2Cache | AllocType::RootPool => {
                    Some(try!(nv.find("guid").ok_or(zfs::Error::Invalid)))
                },
                _ => { None },
            };*/

        //Ok(Self::new(id, guid))
        Ok(Self::new(id, 0))
    }
}
<commit_msg>Split vdev top and leaf data<commit_after>use redox::{String, ToString, Vec};

use super::from_bytes::FromBytes;
use super::metaslab::{Metaslab, MetaslabGroup};
use super::nvpair::{NvList, NvValue};
use super::zfs;

#[repr(packed)]
pub struct VdevLabel {
    pub blank: [u8; 8 * 1024],
    pub boot_header: [u8; 8 * 1024],
    pub nv_pairs: [u8; 112 * 1024],
    pub uberblocks: [u8; 128 * 1024],
}

impl FromBytes for VdevLabel { }

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

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AllocType {
    Load = 0,
    Add,
    Spare,
    L2Cache,
    RootPool,
    Split,
    Attach,
}

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

/// States are ordered from least to most healthy.
/// Vdevs `CannotOpen` and worse are considered unusable.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum State {
    Unknown,    // Uninitialized vdev
    Closed,     // Not currently open
    Offline,    // Not allowed to open
    Removed,    // Explicitly removed from the system
    CannotOpen, // Tried top open, but failed
    Faulted,    // External request to fault device
    Degraded,   // Replicated vdev with unhealthy kids
    Healthy,    // Presumed good
}

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

// Stuff that only top level vdevs have
pub struct Top {
    ms_array_object: u64,
    ms_group: MetaslabGroup,
    metaslabs: Vec<Metaslab>,
    is_hole: bool,
}

impl Top {
    pub fn new() -> Self {
        Top {
            ms_array_object: 0,
            ms_group: MetaslabGroup,
            metaslabs: vec![],
            is_hole: false, // TODO: zol checks vdev_ops for this, but idk what to do yet
        }
    }
}

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

pub struct Leaf {
    whole_disk: u64,
    path: String,
}

impl Leaf {
    pub fn new() -> Self {
        Leaf {
            whole_disk: 0,
            path: "".to_string(),
        }
    }
}

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

// Note that a vdev can be a top-level, a leaf, both, or neither
pub struct Vdev {
    id: u64, // child number in vdev parent
    guid: u64, // unique ID for this vdev
    guid_sum: u64, // self guid + all child guids
    orig_guid: u64, // orig. guid prior to remove
    asize: u64, // allocatable device capacity
    min_asize: u64, // min acceptable asize
    max_asize: u64, // max acceptable asize
    ashift: u64, // block alignment shift
    state: State,
    prev_state: State,
    //ops: VdevOps,
    create_txg: u64, // txg when top-level was added

    top: Option<Top>,
    leaf: Option<Leaf>,
}

impl Vdev {
    pub fn new(id: u64, guid: Option<u64>) -> Self {
        let guid =
            guid.unwrap_or_else(|| {
                // TODO: generate a guid
                0
            });
        Vdev {
            id: id,
            guid: guid,
            guid_sum: guid, // No children yet, so guid_sum is just my guid
            orig_guid: 0,
            asize: 0,
            min_asize: 0,
            max_asize: 0,
            ashift: 0,
            state: State::Closed,
            prev_state: State::Unknown,
            create_txg: 0,

            top: None,
            leaf: None,
        }
    }

    pub fn load(nv: &NvList, id: u64, alloc_type: AllocType) -> zfs::Result<Self> {
        let vdev_type = try!(nv.get::<&String>("type").ok_or(zfs::Error::Invalid)).clone();

        if alloc_type == AllocType::Load {
            // Verify the provided id matches the id written in the MOS
            let label_id: u64 = try!(nv.get("id").ok_or(zfs::Error::Invalid));
            if label_id != id { return Err(zfs::Error::Invalid); }
        }

        // If this is some sort of load, then we read the guid from the nvpairs. Otherwise,
        // Vdev::new will generate one for us
        let guid =
            match alloc_type {
                AllocType::Load | AllocType::Spare | AllocType::L2Cache | AllocType::RootPool => {
                    Some(try!(nv.get("guid").ok_or(zfs::Error::Invalid)))
                },
                _ => { None },
            };

        Ok(Self::new(id, guid))
    }
}
<|endoftext|>


<commit_before>extern crate bindgen;
extern crate pkg_config;

use std::io::Write;
use pkg_config::Error;
use std::env;
use std::path::PathBuf;

fn main() {
    let package_name = "cfitsio";
    match pkg_config::probe_library(package_name) {
        Ok(_) => {
            let bindings = bindgen::Builder::default()
                .no_unstable_rust()
                .header("wrapper.h")
                .generate()
                .expect("Unable to generate bindings");
            let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
            bindings
                .write_to_file(out_path.join("bindings.rs"))
                .expect("Couldn't write bindings");
        }
        Err(Error::Failure { output, .. }) => {
            // Handle the case where the user has not installed cfitsio, and thusly it is not on
            // the PKG_CONFIG_PATH
            let stderr = String::from_utf8(output.stderr).unwrap();
            if stderr.contains::<&str>(
                format!(
                    "{} was not found in the pkg-config search path",
                    package_name
                ).as_ref(),
            ) {
                let err_msg = format!(
                    "
Cannot find {} on the pkg-config search path.  Consider installing the library for your
system (e.g. through homebrew, apt-get etc.).  Alternatively if it is installed, then add
the directory that contains `cfitsio.pc` on your PKG_CONFIG_PATH, e.g.:

PKG_CONFIG_PATH=<blah> cargo build
",
                    package_name
                );
                std::io::stderr().write(err_msg.as_bytes()).unwrap();
                std::process::exit(output.status.code().unwrap());
            }
        }
        Err(e) => panic!("Unhandled error: {:?}", e),
    };
}
<commit_msg>Update bindgen and remove unused old feature<commit_after>extern crate bindgen;
extern crate pkg_config;

use std::io::Write;
use pkg_config::Error;
use std::env;
use std::path::PathBuf;

fn main() {
    let package_name = "cfitsio";
    match pkg_config::probe_library(package_name) {
        Ok(_) => {
            let bindings = bindgen::Builder::default()
                .header("wrapper.h")
                .generate()
                .expect("Unable to generate bindings");
            let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
            bindings
                .write_to_file(out_path.join("bindings.rs"))
                .expect("Couldn't write bindings");
        }
        Err(Error::Failure { output, .. }) => {
            // Handle the case where the user has not installed cfitsio, and thusly it is not on
            // the PKG_CONFIG_PATH
            let stderr = String::from_utf8(output.stderr).unwrap();
            if stderr.contains::<&str>(
                format!(
                    "{} was not found in the pkg-config search path",
                    package_name
                ).as_ref(),
            ) {
                let err_msg = format!(
                    "
Cannot find {} on the pkg-config search path.  Consider installing the library for your
system (e.g. through homebrew, apt-get etc.).  Alternatively if it is installed, then add
the directory that contains `cfitsio.pc` on your PKG_CONFIG_PATH, e.g.:

PKG_CONFIG_PATH=<blah> cargo build
",
                    package_name
                );
                std::io::stderr().write(err_msg.as_bytes()).unwrap();
                std::process::exit(output.status.code().unwrap());
            }
        }
        Err(e) => panic!("Unhandled error: {:?}", e),
    };
}
<|endoftext|>


<commit_before>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! The server-side abstraction for multipart requests. Enabled with the `server` feature.
//!
//! Use this when you are implementing an HTTP server and want to
//! to accept, parse, and serve HTTP `multipart/form-data` requests (file uploads).
//!
//! See the `Multipart` struct for more info.

extern crate buf_redux;
extern crate httparse;
extern crate twoway;

use std::borrow::Borrow;
use std::io::prelude::*;
use std::path::Path;
use std::io;

use tempdir::TempDir;

use self::boundary::BoundaryReader;

use self::field::PrivReadEntry;

pub use self::field::{MultipartField, MultipartFile, MultipartData, ReadEntry, ReadEntryResult};

use self::save::SaveBuilder;

pub use self::save::{Entries, SaveResult, SavedFile};

use self::save::EntriesSaveResult;

macro_rules! try_opt (
    ($expr:expr) => (
        match $expr {
            Some(val) => val,
            None => return None,
        }
    );
    ($expr:expr, $before_ret:expr) => (
        match $expr {
            Some(val) => val,
            None => {
                $before_ret;
                return None;
            }
        }
    )
);

macro_rules! try_read_entry {
    ($self_:expr; $try:expr) => (
        match $try {
            Ok(res) => res,
            Err(err) => return ::server::ReadEntryResult::Error($self_, err),
        }
    )
}

mod boundary;
mod field;

#[cfg(feature = "hyper")]
pub mod hyper;

#[cfg(feature = "iron")]
pub mod iron;

#[cfg(feature = "tiny_http")]
pub mod tiny_http;

pub mod save;

/// The server-side implementation of `multipart/form-data` requests.
///
/// Implements `Borrow<R>` to allow access to the request body, if desired.
pub struct Multipart<R> {
    reader: BoundaryReader<R>,
}

impl Multipart<()> {
    /// If the given `HttpRequest` is a multipart/form-data POST request,
    /// return the request body wrapped in the multipart reader. Otherwise,
    /// returns the original request.
    pub fn from_request<R: HttpRequest>(req: R) -> Result<Multipart<R::Body>, R> {
        //FIXME: move `map` expr to `Some` arm when nonlexical borrow scopes land.
        let boundary = match req.multipart_boundary().map(String::from) {
            Some(boundary) => boundary,
            None => return Err(req),
        };

        Ok(Multipart::with_body(req.body(), boundary))
    }
}

impl<R: Read> Multipart<R> {
    /// Construct a new `Multipart` with the given body reader and boundary.
    ///
    /// ## Note: `boundary`
    /// This will prepend the requisite `--` to the boundary string as documented in
    /// [IETF RFC 1341, Section 7.2.1: "Multipart: the common syntax"][rfc1341-7.2.1].
    /// Simply pass the value of the `boundary` key from the `Content-Type` header in the
    /// request (or use `Multipart::from_request()`, if supported).
    ///
    /// [rfc1341-7.2.1]: https://tools.ietf.org/html/rfc1341#page-30
    pub fn with_body<Bnd: Into<String>>(body: R, boundary: Bnd) -> Self {
        let boundary = boundary.into();

        info!("Multipart::with_boundary(_, {:?}", boundary);

        Multipart {
            reader: BoundaryReader::from_reader(body, boundary),
        }
    }

    /// Read the next entry from this multipart request, returning a struct with the field's name and
    /// data. See `MultipartField` for more info.
    ///
    /// ## Warning: Risk of Data Loss
    /// If the previously returned entry had contents of type `MultipartField::File`,
    /// calling this again will discard any unread contents of that entry.
    pub fn read_entry(&mut self) -> io::Result<Option<MultipartField<&mut Self>>> {
        self.read_entry_mut().into_result()
    }

    /// Read the next entry from this multipart request, returning a struct with the field's name and
    /// data. See `MultipartField` for more info.
    pub fn into_entry(self) -> ReadEntryResult<Self> {
        self.read_entry()
    }

    /// Call `f` for each entry in the multipart request.
    ///
    /// This is a substitute for Rust not supporting streaming iterators (where the return value
    /// from `next()` borrows the iterator for a bound lifetime).
    ///
    /// Returns `Ok(())` when all fields have been read, or the first error.
    pub fn foreach_entry<F>(&mut self, mut foreach: F) -> io::Result<()> where F: FnMut(MultipartField<&mut Self>) {
        loop {
            match self.read_entry() {
                Ok(Some(field)) => foreach(field),
                Ok(None) => return Ok(()),
                Err(err) => return Err(err),
            }
        }
    }

    /// Get a builder type for saving the files in this request to the filesystem.
    ///
    /// See [`SaveBuilder`](save/struct.SaveBuilder.html) for more information.
    pub fn save(&mut self) -> SaveBuilder<&mut Self> {
        SaveBuilder::new(self)
    }

    /// Read the request fully, parsing all fields and saving all files in a new temporary
    /// directory under the OS temporary directory.
    ///
    /// If there is an error in reading the request, returns the partial result along with the
    /// error. See [`SaveResult`](save/enum.SaveResult.html) for more information.
    #[deprecated(since = "0.10.0", note = "use `.save().temp()` instead")]
    pub fn save_all(&mut self) -> EntriesSaveResult<&mut Self> {
        self.save().temp()
    }

    /// Read the request fully, parsing all fields and saving all files in a new temporary
    /// directory under `dir`.
    ///
    /// If there is an error in reading the request, returns the partial result along with the
    /// error. See [`SaveResult`](save/enum.SaveResult.html) for more information.
    #[deprecated(since = "0.10.0", note = "use `.save().with_temp_dir()` instead")]
    pub fn save_all_under<P: AsRef<Path>>(&mut self, dir: P) -> EntriesSaveResult<&mut Self> {
        match TempDir::new_in(dir, "multipart") {
            Ok(temp_dir) => self.save().with_temp_dir(temp_dir),
            Err(err) => SaveResult::Error(err),
        }
    }

    /// Read the request fully, parsing all fields and saving all fields in a new temporary
    /// directory under the OS temporary directory.
    ///
    /// Files larger than `limit` will be truncated to `limit`.
    ///
    /// If there is an error in reading the request, returns the partial result along with the
    /// error. See [`SaveResult`](save/enum.SaveResult.html) for more information.
    #[deprecated(since = "0.10.0", note = "use `.save().size_limit(limit)` instead")]
    pub fn save_all_limited(&mut self, limit: u64) -> EntriesSaveResult<&mut Self> {
        self.save().size_limit(limit).temp()
    }

    /// Read the request fully, parsing all fields and saving all files in a new temporary
    /// directory under `dir`.
    ///
    /// Files larger than `limit` will be truncated to `limit`.
    ///
    /// If there is an error in reading the request, returns the partial result along with the
    /// error. See [`SaveResult`](save/enum.SaveResult.html) for more information.
    #[deprecated(since = "0.10.0", note = "use `.save().size_limit(limit).with_temp_dir()` instead")]
    pub fn save_all_under_limited<P: AsRef<Path>>(&mut self, dir: P, limit: u64) -> EntriesSaveResult<&mut Self> {
        match TempDir::new_in(dir, "multipart") {
            Ok(temp_dir) => self.save().size_limit(limit).with_temp_dir(temp_dir),
            Err(err) => SaveResult::Error(err),
        }
    }
}

impl<R> Borrow<R> for Multipart<R> {
    fn borrow(&self) -> &R {
        self.reader.borrow()
    }
}

impl<R: Read> PrivReadEntry for Multipart<R> {
    type Source = BoundaryReader<R>;

    fn source(&mut self) -> &mut BoundaryReader<R> {
        &mut self.reader
    }

    /// Consume the next boundary.
    /// Returns `true` if the last boundary was read, `false` otherwise.
    fn consume_boundary(&mut self) -> io::Result<bool> {
        debug!("Consume boundary!");
        self.reader.consume_boundary()
    }
}

/// A server-side HTTP request that may or may not be multipart.
///
/// May be implemented by mutable references if providing the request or body by-value is
/// undesirable.
pub trait HttpRequest {
    /// The body of this request.
    type Body: Read;
    /// Get the boundary string of this request if it is a POST request
    /// with the `Content-Type` header set to `multipart/form-data`.
    ///
    /// The boundary string should be supplied as an extra value of the `Content-Type` header, e.g.
    /// `Content-Type: multipart/form-data; boundary={boundary}`.
    fn multipart_boundary(&self) -> Option<&str>;

    /// Return the request body for reading.
    fn body(self) -> Self::Body;
}
<commit_msg>server::Multipart: remove deprecated methods<commit_after>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
//! The server-side abstraction for multipart requests. Enabled with the `server` feature.
//!
//! Use this when you are implementing an HTTP server and want to
//! to accept, parse, and serve HTTP `multipart/form-data` requests (file uploads).
//!
//! See the `Multipart` struct for more info.

extern crate buf_redux;
extern crate httparse;
extern crate twoway;

use std::borrow::Borrow;
use std::io::prelude::*;
use std::path::Path;
use std::io;

use tempdir::TempDir;

use self::boundary::BoundaryReader;

use self::field::PrivReadEntry;

pub use self::field::{MultipartField, MultipartFile, MultipartData, ReadEntry, ReadEntryResult};

use self::save::SaveBuilder;

pub use self::save::{Entries, SaveResult, SavedFile};

use self::save::EntriesSaveResult;

macro_rules! try_opt (
    ($expr:expr) => (
        match $expr {
            Some(val) => val,
            None => return None,
        }
    );
    ($expr:expr, $before_ret:expr) => (
        match $expr {
            Some(val) => val,
            None => {
                $before_ret;
                return None;
            }
        }
    )
);

macro_rules! try_read_entry {
    ($self_:expr; $try:expr) => (
        match $try {
            Ok(res) => res,
            Err(err) => return ::server::ReadEntryResult::Error($self_, err),
        }
    )
}

mod boundary;
mod field;

#[cfg(feature = "hyper")]
pub mod hyper;

#[cfg(feature = "iron")]
pub mod iron;

#[cfg(feature = "tiny_http")]
pub mod tiny_http;

pub mod save;

/// The server-side implementation of `multipart/form-data` requests.
///
/// Implements `Borrow<R>` to allow access to the request body, if desired.
pub struct Multipart<R> {
    reader: BoundaryReader<R>,
}

impl Multipart<()> {
    /// If the given `HttpRequest` is a multipart/form-data POST request,
    /// return the request body wrapped in the multipart reader. Otherwise,
    /// returns the original request.
    pub fn from_request<R: HttpRequest>(req: R) -> Result<Multipart<R::Body>, R> {
        //FIXME: move `map` expr to `Some` arm when nonlexical borrow scopes land.
        let boundary = match req.multipart_boundary().map(String::from) {
            Some(boundary) => boundary,
            None => return Err(req),
        };

        Ok(Multipart::with_body(req.body(), boundary))
    }
}

impl<R: Read> Multipart<R> {
    /// Construct a new `Multipart` with the given body reader and boundary.
    ///
    /// ## Note: `boundary`
    /// This will prepend the requisite `--` to the boundary string as documented in
    /// [IETF RFC 1341, Section 7.2.1: "Multipart: the common syntax"][rfc1341-7.2.1].
    /// Simply pass the value of the `boundary` key from the `Content-Type` header in the
    /// request (or use `Multipart::from_request()`, if supported).
    ///
    /// [rfc1341-7.2.1]: https://tools.ietf.org/html/rfc1341#page-30
    pub fn with_body<Bnd: Into<String>>(body: R, boundary: Bnd) -> Self {
        let boundary = boundary.into();

        info!("Multipart::with_boundary(_, {:?}", boundary);

        Multipart {
            reader: BoundaryReader::from_reader(body, boundary),
        }
    }

    /// Read the next entry from this multipart request, returning a struct with the field's name and
    /// data. See `MultipartField` for more info.
    ///
    /// ## Warning: Risk of Data Loss
    /// If the previously returned entry had contents of type `MultipartField::File`,
    /// calling this again will discard any unread contents of that entry.
    pub fn read_entry(&mut self) -> io::Result<Option<MultipartField<&mut Self>>> {
        self.read_entry_mut().into_result()
    }

    /// Read the next entry from this multipart request, returning a struct with the field's name and
    /// data. See `MultipartField` for more info.
    pub fn into_entry(self) -> ReadEntryResult<Self> {
        self.read_entry()
    }

    /// Call `f` for each entry in the multipart request.
    ///
    /// This is a substitute for Rust not supporting streaming iterators (where the return value
    /// from `next()` borrows the iterator for a bound lifetime).
    ///
    /// Returns `Ok(())` when all fields have been read, or the first error.
    pub fn foreach_entry<F>(&mut self, mut foreach: F) -> io::Result<()> where F: FnMut(MultipartField<&mut Self>) {
        loop {
            match self.read_entry() {
                Ok(Some(field)) => foreach(field),
                Ok(None) => return Ok(()),
                Err(err) => return Err(err),
            }
        }
    }

    /// Get a builder type for saving the files in this request to the filesystem.
    ///
    /// See [`SaveBuilder`](save/struct.SaveBuilder.html) for more information.
    pub fn save(&mut self) -> SaveBuilder<&mut Self> {
        SaveBuilder::new(self)
    }
}

impl<R> Borrow<R> for Multipart<R> {
    fn borrow(&self) -> &R {
        self.reader.borrow()
    }
}

impl<R: Read> PrivReadEntry for Multipart<R> {
    type Source = BoundaryReader<R>;

    fn source(&mut self) -> &mut BoundaryReader<R> {
        &mut self.reader
    }

    /// Consume the next boundary.
    /// Returns `true` if the last boundary was read, `false` otherwise.
    fn consume_boundary(&mut self) -> io::Result<bool> {
        debug!("Consume boundary!");
        self.reader.consume_boundary()
    }
}

/// A server-side HTTP request that may or may not be multipart.
///
/// May be implemented by mutable references if providing the request or body by-value is
/// undesirable.
pub trait HttpRequest {
    /// The body of this request.
    type Body: Read;
    /// Get the boundary string of this request if it is a POST request
    /// with the `Content-Type` header set to `multipart/form-data`.
    ///
    /// The boundary string should be supplied as an extra value of the `Content-Type` header, e.g.
    /// `Content-Type: multipart/form-data; boundary={boundary}`.
    fn multipart_boundary(&self) -> Option<&str>;

    /// Return the request body for reading.
    fn body(self) -> Self::Body;
}
<|endoftext|>


<commit_before>use std::io::{Open, Read, Truncate, ReadWrite, SeekEnd, SeekSet};
use std::io::fs::File;
use std::mem::size_of;
use std::io::Decorator;
use std::vec;
use std::io::mem::{BufReader, MemWriter};

static VERSION: u8 = 1;

// some definitions from kissdb.h

struct Kissdb {
    hash_table_size : u64,
    key_size : u64,
    value_size : u64,
    num_hash_tables : u64,
    hash_tables : ~[u64],
    f : File
}

enum OpenMode {
    ReadOnly,
    RW,
    RWCreate,
    RWReplace
}

fn kissdb_hash(b : &[u8]) -> u64 {
    let mut hash = 5381;
    for &bx in b.iter() {
        hash = ((hash << 5) + hash) + (bx as u64);
    }
    return hash
}

fn kissdb_open(
    path : &Path,
    orig_mode : OpenMode,
    mut hash_table_size : u64,
    mut key_size : u64,
    mut value_size : u64
        ) -> Option<~Kissdb>
{
    let (mode, access) = match orig_mode {
        ReadOnly =>  (Open, Read), // rb
        RW => (Open, ReadWrite), // r+b
        RWCreate =>  (Open, ReadWrite), // r+b
        RWReplace => (Truncate, ReadWrite) // w+b
    };
    let f_ = File::open_mode(path, mode, access).or_else(|| {
            match orig_mode {
                RWCreate => File::open_mode(path, Truncate, ReadWrite),
                _ => None
            }
        });

    let mut f = match f_ {
        Some(f) => f,
        None => return None
    };
    let kissdb_header_size = ((size_of::<u64>() * 3) + 4) as u64;

    f.seek(0, SeekEnd);
    if (f.tell() < kissdb_header_size) {
        if hash_table_size > 0 && key_size > 0
            && value_size >0
            {
            f.seek(0, SeekSet);
            let tmp2 = ['K' as u8, 'd' as u8, 'R' as u8, VERSION];
            f.write(tmp2);
            f.write_le_u64(hash_table_size);
            f.write_le_u64(key_size);
            f.write_le_u64(value_size);
            f.flush();
        }
        else {
            fail!()
        }
    }
    else {
        f.seek(0, SeekSet);
        let mut tmp2 = [0, ..4];
        if f.read(tmp2) != Some(4) { fail!() }
        if tmp2 != ['K' as u8, 'd' as u8, 'R' as u8, VERSION] { fail!() }
        hash_table_size = f.read_le_u64();
        key_size = f.read_le_u64();
        value_size = f.read_le_u64();
    }

    let mut num_hash_tables = 0;

    let mut hash_tables = ~[];
    let mut h;

    while ({h = f.read_one_hash_table(hash_table_size); h.is_some()})
    {
        let httmp = h.unwrap();
        hash_tables.push_all(httmp);
        num_hash_tables = num_hash_tables + 1;
        if (httmp[hash_table_size] > 0) {
            f.seek(httmp[hash_table_size] as i64, SeekSet)
        }
        else {
            break;
        }
    }

    debug!("key_size = {:s}", key_size.to_str());

    Some(~Kissdb {hash_table_size : hash_table_size,
                  key_size : key_size,
                  value_size : value_size,
                  num_hash_tables : num_hash_tables,
                  hash_tables : hash_tables,
                  f : f})
}

trait File2 {
    fn read_one_hash_table(&mut self, u64) -> Option<~[u64]>;
    fn write_one_hash_table(&mut self, &[u64]);
}

impl File2 for File {
    fn read_one_hash_table(&mut self,
                           hash_table_size : u64) -> Option<~[u64]> {
        let bs = (hash_table_size + 1) as uint * size_of::<u64>();
        let mut buf = vec::from_elem(bs, 0 as u8);

        match self.read(buf) {
            Some(buf_size) if buf_size == bs => {
                let mut br = BufReader::new(buf);
                Some(vec::from_fn((hash_table_size + 1) as uint,
                                  |_| br.read_le_u64()))
            },
            _ => None
        }
    }
    fn write_one_hash_table(&mut self, ht : &[u64]) {
        for &x in ht.iter() {
            self.write_le_u64(x);
        }
    }
}

trait Kdb {
    fn kissdb_get(&mut self, key : &[u8]) -> Option<~[u8]>;
    fn kissdb_put(&mut self, key : &[u8], value : &[u8]) -> bool;
}

impl Kdb for Kissdb {
    fn kissdb_get(&mut self, key : &[u8]) -> Option<~[u8]> {
        if key.len() != self.key_size as uint { return None }
        let hash = kissdb_hash(key) % self.hash_table_size;
        let hash_tables = &self.hash_tables;
        for i in range(0, self.num_hash_tables) {
            let offset = hash_tables[i * (self.hash_table_size + 1) + hash] as i64;
            if (offset == 0) { return None }; // yeah, 0 is being special. never used normally.
            self.f.seek(offset as i64, SeekSet);

            let klen = self.key_size as uint;
            let tmp = self.f.read_bytes(klen);

            if key == tmp {
                return Some(self.f.read_bytes(self.value_size as uint))
            }
        }
        None
    }

    fn kissdb_put(&mut self, key : &[u8], value : &[u8]) -> bool {
        if key.len() != self.key_size as uint { fail!() }
        if value.len() != self.value_size as uint { fail!() }
        let hash = kissdb_hash(key) % self.hash_table_size;
        let mut last_ht_offset = ((size_of::<u64>() * 3) + 4) as u64;
        let mut ht_offset = last_ht_offset;

        for i in range(0, self.num_hash_tables) {
            let offset = self.hash_tables[(self.hash_table_size + 1) * i + hash] as i64;
            if (offset != 0) { // yes, 0 is treated special. 0 will never used normally
                /* rewrite if already exists */
                self.f.seek(offset, SeekSet);

                let klen = self.key_size as uint;
                let tmp = self.f.read_bytes(klen);
                if key == tmp {
                    self.f.write(value);
                    self.f.flush();
                    return true; /* success */
                }
                // put_no_match_next_hash_table:
                last_ht_offset = ht_offset;
                ht_offset = self.hash_tables[(self.hash_table_size + 1) * i + self.hash_table_size];
                //cmp != , should be put_no_match_next_hash_table
            } else {
                /* add if an empty hash table slot is discovered */
                self.f.seek(0, SeekEnd);
                let end_offset = self.f.tell();

                // debug!("endoffset = {:s}",endoffset.to_str());
                self.f.write(key);
                self.f.write(value);

                self.f.seek(ht_offset as i64 + (size_of::<u64>() as i64 * hash as i64), SeekSet);
                self.f.write_le_u64(end_offset);
                self.hash_tables[(self.hash_table_size + 1) * i + hash] = end_offset;

                self.f.flush();

                return true; /* success */
            }
        }

        /* if no existing slots, add a new page of hash table entries */
        debug!("add new page");
        self.f.seek(0, SeekEnd);
        let endoffset = self.f.tell();

        let mut new_table = vec::from_elem(self.hash_table_size as uint + 1, 0 as u64);
        let hash_table_size_bytes = size_of::<u64>() as u64 * (self.hash_table_size + 1);
        new_table[hash] = endoffset + hash_table_size_bytes; // where key, value are to be written
        self.f.write_one_hash_table(new_table);
        self.hash_tables.push_all_move(new_table);

        debug!("writing at {:s}", self.f.tell().to_str());
        self.f.write(key);
        self.f.write(value);

        if self.num_hash_tables > 0 {
            self.f.seek(last_ht_offset as i64 + (size_of::<u64>() as i64 * self.hash_table_size as i64), SeekSet);
            self.f.write_le_u64(endoffset);
            // mimick rereading
            self.hash_tables[((self.hash_table_size + 1) * (self.num_hash_tables - 1)) + self.hash_table_size] = endoffset;
        }

        self.num_hash_tables = self.num_hash_tables + 1;
        self.f.flush();
        return true; /* success */
    }

}

fn main()
{
    println("Opening new empty database test.db...");
    {
        let mut db = kissdb_open(&Path::new("test.db"), RWReplace, 1024, 8, size_of::<u64>() as u64).unwrap();

        println("Adding and then re-getting 10000 64-byte values...");

        let mut v = [0,0,0,0,0,0,0,0];

        for i in range(0, 10000) {
            for j in range(0, 8) {
                v[j] = i as u8;
            }
            let mut key = MemWriter::new();
            key.write_le_u64(i as u64);
            let key_buf = key.inner();
            db.kissdb_put(key_buf, v);
            let gotten = db.kissdb_get(key_buf).unwrap();
            for j in range(0, 8) {
                if gotten[j] != i as u8 { fail!() }
            }
        }
        println("Getting 10000 64-byte values...");

        for i in range(0, 10000) {
            let mut key = MemWriter::new();
            key.write_le_u64(i as u64);
            let gotten = db.kissdb_get(key.inner()).unwrap();
            for j in range(0,8) {
                if gotten[j] != i as u8 { fail!() }
            }
        }

        println("closing and re-opening database in read-only mode...");
    }

    {
        let mut db = kissdb_open(&Path::new("test.db"), ReadOnly, 1024, 8, size_of::<u64>() as u64).unwrap();

        println("Getting 10000 64-byte values...");

        for i in range(0, 10000) {
            let mut key = MemWriter::new();
            key.write_le_u64(i as u64);
            let gotten = db.kissdb_get(key.inner()).unwrap();
            for j in range(0,8) {
                if gotten[j] != i as u8 { fail!() }
            }
        }
    }

    println("Iterator not implemented ...");

    println("All tests OK!");
}
<commit_msg>misc changes<commit_after>use std::io::{Open, Read, Truncate, ReadWrite, SeekEnd, SeekSet};
use std::io::fs::File;
use std::mem::size_of;
use std::io::Decorator;
use std::vec;
use std::io::mem::{BufReader, MemWriter};
use std::io::io_error;

static VERSION: u8 = 1;

// some definitions from kissdb.h

struct Kissdb {
    hash_table_size : u64,
    key_size : u64,
    value_size : u64,
    num_hash_tables : u64,
    hash_tables : ~[u64],
    f : File
}

enum OpenMode {
    ReadOnly,
    RW,
    RWCreate,
    RWReplace
}

fn kissdb_hash(b : &[u8]) -> u64 {
    let mut hash = 5381;
    for &bx in b.iter() {
        hash = ((hash << 5) + hash) + (bx as u64);
    }
    hash
}

fn kissdb_open(
    path : &Path,
    orig_mode : OpenMode,
    mut hash_table_size : u64,
    mut key_size : u64,
    mut value_size : u64
        ) -> Option<~Kissdb>
{
    let (mode, access) = match orig_mode {
        ReadOnly =>  (Open, Read), // rb
        RW => (Open, ReadWrite), // r+b
        RWCreate =>  (Open, ReadWrite), // r+b
        RWReplace => (Truncate, ReadWrite) // w+b
    };
    let f_ = File::open_mode(path, mode, access).or_else(|| {
            match orig_mode {
                RWCreate => File::open_mode(path, Truncate, ReadWrite),
                _ => None
            }
        });

    let mut f = match f_ {
        Some(f) => f,
        None => return None
    };
    let kissdb_header_size = ((size_of::<u64>() * 3) + 4) as u64;

    f.seek(0, SeekEnd);
    if (f.tell() < kissdb_header_size) {
        if hash_table_size > 0 && key_size > 0
            && value_size >0
            {
            f.seek(0, SeekSet);
            let tmp2 = ['K' as u8, 'd' as u8, 'R' as u8, VERSION];
            f.write(tmp2);
            f.write_le_u64(hash_table_size);
            f.write_le_u64(key_size);
            f.write_le_u64(value_size);
            f.flush();
        }
        else {
            fail!()
        }
    }
    else {
        f.seek(0, SeekSet);
        let mut tmp2 = [0, ..4];
        if f.read(tmp2) != Some(4) { fail!() }
        if tmp2 != ['K' as u8, 'd' as u8, 'R' as u8, VERSION] { fail!() }
        hash_table_size = f.read_le_u64();
        key_size = f.read_le_u64();
        value_size = f.read_le_u64();
    }

    let mut num_hash_tables = 0;

    let mut hash_tables = ~[];
    let mut h;

    while ({h = f.read_one_hash_table(hash_table_size); h.is_some()})
    {
        let httmp = h.unwrap();
        hash_tables.push_all(httmp);
        num_hash_tables = num_hash_tables + 1;
        if (httmp[hash_table_size] > 0) {
            f.seek(httmp[hash_table_size] as i64, SeekSet)
        }
        else {
            break;
        }
    }

    debug!("key_size = {:s}", key_size.to_str());

    Some(~Kissdb {hash_table_size : hash_table_size,
                  key_size : key_size,
                  value_size : value_size,
                  num_hash_tables : num_hash_tables,
                  hash_tables : hash_tables,
                  f : f})
}

trait File2 {
    fn read_one_hash_table(&mut self, u64) -> Option<~[u64]>;
    fn write_one_hash_table(&mut self, &[u64]);
}

impl File2 for File {
    fn read_one_hash_table(&mut self,
                           hash_table_size : u64) -> Option<~[u64]> {
        let bs = (hash_table_size + 1) as uint * size_of::<u64>();
        let mut err = false;

        io_error::cond.trap(|_| err = true ).inside(|| {
            let buf = self.read_bytes(bs);
            let mut br = BufReader::new(buf);
            if err { None }
            else {
                Some(vec::from_fn((hash_table_size + 1) as uint,
                                  |_| br.read_le_u64()))
            }
        })
    }
    fn write_one_hash_table(&mut self, ht : &[u64]) {
        for &x in ht.iter() {
            self.write_le_u64(x);
        }
    }
}

trait Kdb {
    fn kissdb_get(&mut self, key : &[u8]) -> Option<~[u8]>;
    fn kissdb_put(&mut self, key : &[u8], value : &[u8]) -> bool;
}

impl Kdb for Kissdb {
    fn kissdb_get(&mut self, key : &[u8]) -> Option<~[u8]> {
        if key.len() != self.key_size as uint { return None }
        let hash = kissdb_hash(key) % self.hash_table_size;
        let hash_tables = &self.hash_tables;
        for i in range(0, self.num_hash_tables) {
            let offset = hash_tables[i * (self.hash_table_size + 1) + hash] as i64;
            if (offset == 0) { return None }; // yeah, 0 is being special. never used normally.
            self.f.seek(offset as i64, SeekSet);

            let klen = self.key_size as uint;
            let tmp = self.f.read_bytes(klen);

            if key == tmp {
                return Some(self.f.read_bytes(self.value_size as uint))
            }
        }
        None
    }

    fn kissdb_put(&mut self, key : &[u8], value : &[u8]) -> bool {
        if key.len() != self.key_size as uint { fail!() }
        if value.len() != self.value_size as uint { fail!() }
        let hash = kissdb_hash(key) % self.hash_table_size;
        let mut last_ht_offset = ((size_of::<u64>() * 3) + 4) as u64;
        let mut ht_offset = last_ht_offset;

        for i in range(0, self.num_hash_tables) {
            let offset = self.hash_tables[(self.hash_table_size + 1) * i + hash] as i64;
            if (offset != 0) { // yes, 0 is treated special. 0 will never used normally
                /* rewrite if already exists */
                self.f.seek(offset, SeekSet);

                let klen = self.key_size as uint;
                let tmp = self.f.read_bytes(klen);
                if key == tmp {
                    self.f.write(value);
                    self.f.flush();
                    return true; /* success */
                }
                // put_no_match_next_hash_table:
                last_ht_offset = ht_offset;
                ht_offset = self.hash_tables[(self.hash_table_size + 1) * i + self.hash_table_size];
                //cmp != , should be put_no_match_next_hash_table
            } else {
                /* add if an empty hash table slot is discovered */
                self.f.seek(0, SeekEnd);
                let end_offset = self.f.tell();

                // debug!("endoffset = {:s}",endoffset.to_str());
                self.f.write(key);
                self.f.write(value);

                self.f.seek(ht_offset as i64 + (size_of::<u64>() as i64 * hash as i64), SeekSet);
                self.f.write_le_u64(end_offset);
                self.hash_tables[(self.hash_table_size + 1) * i + hash] = end_offset;

                self.f.flush();

                return true; /* success */
            }
        }

        /* if no existing slots, add a new page of hash table entries */
        debug!("add new page");
        self.f.seek(0, SeekEnd);
        let endoffset = self.f.tell();

        let mut new_table = vec::from_elem(self.hash_table_size as uint + 1, 0 as u64);
        let hash_table_size_bytes = size_of::<u64>() as u64 * (self.hash_table_size + 1);
        new_table[hash] = endoffset + hash_table_size_bytes; // where key, value are to be written
        self.f.write_one_hash_table(new_table);
        self.hash_tables.push_all_move(new_table);

        debug!("writing at {:s}", self.f.tell().to_str());
        self.f.write(key);
        self.f.write(value);

        if self.num_hash_tables > 0 {
            self.f.seek(last_ht_offset as i64 + (size_of::<u64>() as i64 * self.hash_table_size as i64), SeekSet);
            self.f.write_le_u64(endoffset);
            // mimick rereading
            self.hash_tables[((self.hash_table_size + 1) * (self.num_hash_tables - 1)) + self.hash_table_size] = endoffset;
        }

        self.num_hash_tables = self.num_hash_tables + 1;
        self.f.flush();
        true /* success */
    }

}

fn main()
{
    println("Opening new empty database test.db...");
    {
        let mut db = kissdb_open(&Path::new("test.db"), RWReplace, 1024, 8, size_of::<u64>() as u64).unwrap();

        println("Adding and then re-getting 10000 64-byte values...");

        let mut v = [0,0,0,0,0,0,0,0];

        for i in range(0, 10000) {
            for j in range(0, 8) {
                v[j] = i as u8;
            }
            let mut key = MemWriter::new();
            key.write_le_u64(i as u64);
            let key_buf = key.inner();
            db.kissdb_put(key_buf, v);
            let gotten = db.kissdb_get(key_buf).unwrap();
            for j in range(0, 8) {
                if gotten[j] != i as u8 { fail!() }
            }
        }
        println("Getting 10000 64-byte values...");

        for i in range(0, 10000) {
            let mut key = MemWriter::new();
            key.write_le_u64(i as u64);
            let gotten = db.kissdb_get(key.inner()).unwrap();
            for j in range(0,8) {
                if gotten[j] != i as u8 { fail!() }
            }
        }

        println("closing and re-opening database in read-only mode...");
    }

    {
        let mut db = kissdb_open(&Path::new("test.db"), ReadOnly, 1024, 8, size_of::<u64>() as u64).unwrap();

        println("Getting 10000 64-byte values...");

        for i in range(0, 10000) {
            let mut key = MemWriter::new();
            key.write_le_u64(i as u64);
            let gotten = db.kissdb_get(key.inner()).unwrap();
            for j in range(0,8) {
                if gotten[j] != i as u8 { fail!() }
            }
        }
    }

    println("Iterator not implemented ...");

    println("All tests OK!");
}
<|endoftext|>


<commit_before>use diesel;
use diesel::prelude::*;

use data::types::*;
use helpers::db::DB;

use models::resource::{Resource, UpdatedResource};

use schema::resources::dsl as resources_dsl;

/// This function checks if there are enough resources for a given set
/// of costs from a research or model entry.
/// It also subtracts and updates the resources the specified value from the database.
///
/// The first parameter is a vector of resources which represent the costs.
/// The second parameter is a vector of all `Resource` database models from a pod or a base.
pub fn check_resources(costs: &Option<Vec<(ResourceTypes, i64)>>,
                       resources: Vec<Resource>,
                       db: &DB)
                       -> bool {
    match costs.as_ref() {
        // There are no costs for this module/research
        None => return true,
        // There are some costs
        Some(costs) => {
            for &(ref resource_type, amount) in costs {
                // Try to get the correct entry from existing resources.
                let existing = resources
                    .iter()
                    .filter(|x| x.name == resource_type.to_string())
                    .next();
                match existing {
                    // There is no resource for this resource_type,
                    // thereby it's not enough.
                    None => return false,
                    // There is a resource for this resource type
                    // We need to check if we got enough of it.
                    Some(existing_resource) => {
                        if existing_resource.amount < amount {
                            return false;
                        }
                    }
                }
            }
            update_resources(resources, costs, true, db);
            return true;
        }
    }
}

pub fn update_resources(resources: Vec<Resource>,
                        costs: &Vec<(ResourceTypes, i64)>,
                        subtract: bool,
                        db: &DB) {

    for &(ref resource_type, amount) in costs.iter() {
        // Try to get the correct entry from existing resources.
        let resource = resources
            .iter()
            .filter(|x| x.name == resource_type.to_string())
            .next();
        match resource {
            // There is no resource for this resource_type,
            // thereby it's not enough.
            // There is a resource for this resource type
            Some(resource) => {
                update_resource(resource, amount, subtract, db);
            }
            None => (),
        }
    }
}

pub fn update_resource(resource: &Resource, amount: i64, subtract: bool, db: &DB) {
    let mut new_amount: i64;
    if subtract {
        new_amount = resource.amount - amount;
    } else {
        new_amount = resource.amount + amount;
        if new_amount > resource.max_amount {
            new_amount = resource.max_amount;
        }
    }

    let updated_resource = UpdatedResource {
        amount: Some(new_amount),
        max_amount: None,
    };

    diesel::update(resources_dsl::resources.filter(resources_dsl::id.eq(resource.id)))
        .set(&updated_resource)
        .get_result::<Resource>(&**db)
        .expect("Failed to update resource.");
}
<commit_msg>More documentation in resource helper<commit_after>use diesel;
use diesel::prelude::*;

use data::types::*;
use helpers::db::DB;

use models::resource::{Resource, UpdatedResource};

use schema::resources::dsl as resources_dsl;

/// This function checks if there are enough resources for a given set
/// of costs from a research or model entry.
/// It also subtracts and updates the resources the specified value from the database.
///
/// The first parameter is a vector of resources which represent the costs.
/// The second parameter is a vector of all `Resource` database models from a pod or a base.
pub fn check_resources(costs: &Option<Vec<(ResourceTypes, i64)>>,
                       resources: Vec<Resource>,
                       db: &DB)
                       -> bool {
    match costs.as_ref() {
        // There are no costs for this module/research
        None => return true,
        // There are some costs
        Some(costs) => {
            for &(ref resource_type, amount) in costs {
                // Try to get the correct entry from existing resources.
                let existing = resources
                    .iter()
                    .filter(|x| x.name == resource_type.to_string())
                    .next();
                match existing {
                    // There is no resource for this resource_type,
                    // thereby it's not enough.
                    None => return false,
                    // There is a resource for this resource type
                    // We need to check if we got enough of it.
                    Some(existing_resource) => {
                        if existing_resource.amount < amount {
                            return false;
                        }
                    }
                }
            }
            update_resources(costs, resources, true, db);
            return true;
        }
    }
}

/// This function updates the resources the specified value from the database.
/// Depending on the third parameter the costs will either be added or subtracted.
///
/// The first parameter is a vector of resources which represent the costs.
/// The second parameter is a vector of all `Resource` database models from a pod or a base.
pub fn update_resources(costs: &Vec<(ResourceTypes, i64)>,
                        resources: Vec<Resource>,
                        subtract: bool,
                        db: &DB) {

    for &(ref resource_type, amount) in costs.iter() {
        // Try to get the correct entry from existing resources.
        let resource = resources
            .iter()
            .filter(|x| x.name == resource_type.to_string())
            .next();
        match resource {
            // There is no resource for this resource_type,
            // thereby it's not enough.
            // There is a resource for this resource type
            Some(resource) => {
                update_resource(resource, amount, subtract, db);
            }
            None => (),
        }
    }
}

/// This function updates a resource in the database.
/// Depending on the third parameter the value will either be added or subtracted.
///
/// The first parameter is the queried database model.
/// The second parameter is the amount to be added or subtracted.
pub fn update_resource(resource: &Resource, amount: i64, subtract: bool, db: &DB) {
    let mut new_amount: i64;
    if subtract {
        new_amount = resource.amount - amount;
    } else {
        new_amount = resource.amount + amount;
        if new_amount > resource.max_amount {
            new_amount = resource.max_amount;
        }
    }

    let updated_resource = UpdatedResource {
        amount: Some(new_amount),
        max_amount: None,
    };

    diesel::update(resources_dsl::resources.filter(resources_dsl::id.eq(resource.id)))
        .set(&updated_resource)
        .get_result::<Resource>(&**db)
        .expect("Failed to update resource.");
}
<|endoftext|>


<commit_before>use std::{
    future::Future,
    pin::Pin,
    sync::{
        atomic::{AtomicBool, Ordering::Relaxed},
        mpsc::{sync_channel, Receiver, SyncSender, TryRecvError},
    },
    task::{Context, Poll, Waker},
    time::{Duration, Instant},
};

#[cfg(not(feature = "testing"))]
use std::collections::HashMap as Map;

// we avoid HashMap while testing because
// it makes tests non-deterministic
#[cfg(feature = "testing")]
use std::collections::BTreeMap as Map;

use crate::*;

static ID_GEN: AtomicUsize = AtomicUsize::new(0);

/// An event that happened to a key that a subscriber is interested in.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Event {
    /// A new complete (key, value) pair
    Insert {
        /// The key that has been set
        key: IVec,
        /// The value that has been set
        value: IVec,
    },
    /// A deleted key
    Remove {
        /// The key that has been removed
        key: IVec,
    },
}

impl Event {
    /// Return the key associated with the `Event`
    pub fn key(&self) -> &IVec {
        match self {
            Event::Insert { key, .. } | Event::Remove { key } => key,
        }
    }
}

type Senders = Map<usize, (Option<Waker>, SyncSender<OneShot<Option<Event>>>)>;

/// A subscriber listening on a specified prefix
///
/// `Subscriber` implements both `Iterator<Item = Event>`
/// and `Future<Output=Option<Event>>`
///
/// # Examples
///
/// Synchronous, blocking subscriber:
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use sled::{Config, Event};
/// let config = Config::new().temporary(true);
///
/// let tree = config.open()?;
///
/// // watch all events by subscribing to the empty prefix
/// let mut subscriber = tree.watch_prefix(vec![]);
///
/// let tree_2 = tree.clone();
/// let thread = std::thread::spawn(move || {
///     tree.insert(vec![0], vec![1])
/// });
///
/// // `Subscription` implements `Iterator<Item=Event>`
/// for event in subscriber.take(1) {
///     match event {
///         Event::Insert{ key, value } => assert_eq!(key.as_ref(), &[0]),
///         Event::Remove {key } => {}
///     }
/// }
///
/// # thread.join().unwrap();
/// # Ok(())
/// # }
/// ```
/// Aynchronous, non-blocking subscriber:
///
/// `Subscription` implements `Future<Output=Option<Event>>`.
///
/// `while let Some(event) = (&mut subscriber).await { /* use it */ }`
pub struct Subscriber {
    id: usize,
    rx: Receiver<OneShot<Option<Event>>>,
    existing: Option<OneShot<Option<Event>>>,
    home: Arc<RwLock<Senders>>,
}

impl Drop for Subscriber {
    fn drop(&mut self) {
        let mut w_senders = self.home.write();
        w_senders.remove(&self.id);
    }
}

impl Subscriber {
    /// Attempts to wait for a value on this `Subscriber`, returning
    /// an error if no event arrives within the provided `Duration`
    /// or if the backing `Db` shuts down.
    pub fn next_timeout(
        &self,
        mut timeout: Duration,
    ) -> std::result::Result<Event, std::sync::mpsc::RecvTimeoutError> {
        loop {
            let start = Instant::now();
            let future_rx = self.rx.recv_timeout(timeout)?;
            timeout =
                if let Some(timeout) = timeout.checked_sub(start.elapsed()) {
                    timeout
                } else {
                    Duration::from_nanos(0)
                };

            let start = Instant::now();
            if let Some(event) = future_rx.wait_timeout(timeout)? {
                return Ok(event);
            }
            timeout =
                if let Some(timeout) = timeout.checked_sub(start.elapsed()) {
                    timeout
                } else {
                    Duration::from_nanos(0)
                };
        }
    }

    fn poll_oneshot(
        self: &mut Pin<&mut Self>,
        mut oneshot: OneShot<Option<Event>>,
        cx: &mut Context<'_>,
    ) -> Option<Poll<Option<Event>>> {
        match Future::poll(Pin::new(&mut oneshot), cx) {
            Poll::Ready(Some(event)) => Some(Poll::Ready(event)),
            Poll::Ready(None) => None,
            Poll::Pending => {
                self.existing = Some(oneshot);
                Some(Poll::Pending)
            }
        }
    }
}

impl Future for Subscriber {
    type Output = Option<Event>;

    fn poll(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Self::Output> {
        loop {
            if let Some(future_rx) = self.existing.take() {
                if let Some(poll) = self.poll_oneshot(future_rx, cx) {
                    return poll;
                }
            }

            match self.rx.try_recv() {
                Ok(future_rx) => {
                    if let Some(poll) = self.poll_oneshot(future_rx, cx) {
                        return poll;
                    }
                }
                Err(TryRecvError::Empty) => break,
                Err(TryRecvError::Disconnected) => return Poll::Ready(None),
            }
        }
        let mut home = self.home.write();
        let entry = home.get_mut(&self.id).unwrap();
        entry.0 = Some(cx.waker().clone());
        Poll::Pending
    }
}

impl Iterator for Subscriber {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        loop {
            let future_rx = self.rx.recv().ok()?;
            match future_rx.wait() {
                Some(Some(event)) => return Some(event),
                Some(None) => return None,
                None => continue,
            }
        }
    }
}

#[derive(Debug, Default)]
pub(crate) struct Subscribers {
    watched: RwLock<BTreeMap<Vec<u8>, Arc<RwLock<Senders>>>>,
    ever_used: AtomicBool,
}

impl Drop for Subscribers {
    fn drop(&mut self) {
        let watched = self.watched.read();

        for senders in watched.values() {
            let senders =
                std::mem::replace(&mut *senders.write(), Map::default());
            for (_, (waker, sender)) in senders {
                drop(sender);
                if let Some(waker) = waker {
                    waker.wake();
                }
            }
        }
    }
}

impl Subscribers {
    pub(crate) fn register(&self, prefix: &[u8]) -> Subscriber {
        self.ever_used.store(true, Relaxed);
        let r_mu = {
            let r_mu = self.watched.read();
            if r_mu.contains_key(prefix) {
                r_mu
            } else {
                drop(r_mu);
                let mut w_mu = self.watched.write();
                if !w_mu.contains_key(prefix) {
                    let old = w_mu.insert(
                        prefix.to_vec(),
                        Arc::new(RwLock::new(Map::default())),
                    );
                    assert!(old.is_none());
                }
                drop(w_mu);
                self.watched.read()
            }
        };

        let (tx, rx) = sync_channel(1024);

        let arc_senders = &r_mu[prefix];
        let mut w_senders = arc_senders.write();

        let id = ID_GEN.fetch_add(1, Relaxed);

        w_senders.insert(id, (None, tx));

        Subscriber { id, rx, existing: None, home: arc_senders.clone() }
    }

    pub(crate) fn reserve<R: AsRef<[u8]>>(
        &self,
        key: R,
    ) -> Option<ReservedBroadcast> {
        if !self.ever_used.load(Relaxed) {
            return None;
        }

        let r_mu = self.watched.read();
        let prefixes = r_mu.iter().filter(|(k, _)| key.as_ref().starts_with(k));

        let mut subscribers = vec![];

        for (_, subs_rwl) in prefixes {
            let subs = subs_rwl.read();

            for (_id, (waker, sender)) in subs.iter() {
                let (tx, rx) = OneShot::pair();
                if sender.send(rx).is_err() {
                    continue;
                }
                subscribers.push((waker.clone(), tx));
            }
        }

        if subscribers.is_empty() {
            None
        } else {
            Some(ReservedBroadcast { subscribers })
        }
    }
}

pub(crate) struct ReservedBroadcast {
    subscribers: Vec<(Option<Waker>, OneShotFiller<Option<Event>>)>,
}

impl ReservedBroadcast {
    pub fn complete(self, event: &Event) {
        let iter = self.subscribers.into_iter();

        for (waker, tx) in iter {
            tx.fill(Some(event.clone()));
            if let Some(waker) = waker {
                waker.wake();
            }
        }
    }
}

#[test]
fn basic_subscriber() {
    let subs = Subscribers::default();

    let mut s2 = subs.register(&[0]);
    let mut s3 = subs.register(&[0, 1]);
    let mut s4 = subs.register(&[1, 2]);

    let r1 = subs.reserve(b"awft");
    assert!(r1.is_none());

    let mut s1 = subs.register(&[]);

    let k2: IVec = vec![].into();
    let r2 = subs.reserve(&k2).unwrap();
    r2.complete(&Event::Insert { key: k2.clone(), value: k2.clone() });

    let k3: IVec = vec![0].into();
    let r3 = subs.reserve(&k3).unwrap();
    r3.complete(&Event::Insert { key: k3.clone(), value: k3.clone() });

    let k4: IVec = vec![0, 1].into();
    let r4 = subs.reserve(&k4).unwrap();
    r4.complete(&Event::Remove { key: k4.clone() });

    let k5: IVec = vec![0, 1, 2].into();
    let r5 = subs.reserve(&k5).unwrap();
    r5.complete(&Event::Insert { key: k5.clone(), value: k5.clone() });

    let k6: IVec = vec![1, 1, 2].into();
    let r6 = subs.reserve(&k6).unwrap();
    r6.complete(&Event::Remove { key: k6.clone() });

    let k7: IVec = vec![1, 1, 2].into();
    let r7 = subs.reserve(&k7).unwrap();
    drop(r7);

    let k8: IVec = vec![1, 2, 2].into();
    let r8 = subs.reserve(&k8).unwrap();
    r8.complete(&Event::Insert { key: k8.clone(), value: k8.clone() });

    assert_eq!(s1.next().unwrap().key(), &*k2);
    assert_eq!(s1.next().unwrap().key(), &*k3);
    assert_eq!(s1.next().unwrap().key(), &*k4);
    assert_eq!(s1.next().unwrap().key(), &*k5);
    assert_eq!(s1.next().unwrap().key(), &*k6);
    assert_eq!(s1.next().unwrap().key(), &*k8);

    assert_eq!(s2.next().unwrap().key(), &*k3);
    assert_eq!(s2.next().unwrap().key(), &*k4);
    assert_eq!(s2.next().unwrap().key(), &*k5);

    assert_eq!(s3.next().unwrap().key(), &*k4);
    assert_eq!(s3.next().unwrap().key(), &*k5);

    assert_eq!(s4.next().unwrap().key(), &*k8);
}
<commit_msg>Follow @rrichardson's lead and only poll oneshots in one place<commit_after>use std::{
    future::Future,
    pin::Pin,
    sync::{
        atomic::{AtomicBool, Ordering::Relaxed},
        mpsc::{sync_channel, Receiver, SyncSender, TryRecvError},
    },
    task::{Context, Poll, Waker},
    time::{Duration, Instant},
};

#[cfg(not(feature = "testing"))]
use std::collections::HashMap as Map;

// we avoid HashMap while testing because
// it makes tests non-deterministic
#[cfg(feature = "testing")]
use std::collections::BTreeMap as Map;

use crate::*;

static ID_GEN: AtomicUsize = AtomicUsize::new(0);

/// An event that happened to a key that a subscriber is interested in.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Event {
    /// A new complete (key, value) pair
    Insert {
        /// The key that has been set
        key: IVec,
        /// The value that has been set
        value: IVec,
    },
    /// A deleted key
    Remove {
        /// The key that has been removed
        key: IVec,
    },
}

impl Event {
    /// Return the key associated with the `Event`
    pub fn key(&self) -> &IVec {
        match self {
            Event::Insert { key, .. } | Event::Remove { key } => key,
        }
    }
}

type Senders = Map<usize, (Option<Waker>, SyncSender<OneShot<Option<Event>>>)>;

/// A subscriber listening on a specified prefix
///
/// `Subscriber` implements both `Iterator<Item = Event>`
/// and `Future<Output=Option<Event>>`
///
/// # Examples
///
/// Synchronous, blocking subscriber:
/// ```
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use sled::{Config, Event};
/// let config = Config::new().temporary(true);
///
/// let tree = config.open()?;
///
/// // watch all events by subscribing to the empty prefix
/// let mut subscriber = tree.watch_prefix(vec![]);
///
/// let tree_2 = tree.clone();
/// let thread = std::thread::spawn(move || {
///     tree.insert(vec![0], vec![1])
/// });
///
/// // `Subscription` implements `Iterator<Item=Event>`
/// for event in subscriber.take(1) {
///     match event {
///         Event::Insert{ key, value } => assert_eq!(key.as_ref(), &[0]),
///         Event::Remove {key } => {}
///     }
/// }
///
/// # thread.join().unwrap();
/// # Ok(())
/// # }
/// ```
/// Aynchronous, non-blocking subscriber:
///
/// `Subscription` implements `Future<Output=Option<Event>>`.
///
/// `while let Some(event) = (&mut subscriber).await { /* use it */ }`
pub struct Subscriber {
    id: usize,
    rx: Receiver<OneShot<Option<Event>>>,
    existing: Option<OneShot<Option<Event>>>,
    home: Arc<RwLock<Senders>>,
}

impl Drop for Subscriber {
    fn drop(&mut self) {
        let mut w_senders = self.home.write();
        w_senders.remove(&self.id);
    }
}

impl Subscriber {
    /// Attempts to wait for a value on this `Subscriber`, returning
    /// an error if no event arrives within the provided `Duration`
    /// or if the backing `Db` shuts down.
    pub fn next_timeout(
        &self,
        mut timeout: Duration,
    ) -> std::result::Result<Event, std::sync::mpsc::RecvTimeoutError> {
        loop {
            let start = Instant::now();
            let future_rx = self.rx.recv_timeout(timeout)?;
            timeout =
                if let Some(timeout) = timeout.checked_sub(start.elapsed()) {
                    timeout
                } else {
                    Duration::from_nanos(0)
                };

            let start = Instant::now();
            if let Some(event) = future_rx.wait_timeout(timeout)? {
                return Ok(event);
            }
            timeout =
                if let Some(timeout) = timeout.checked_sub(start.elapsed()) {
                    timeout
                } else {
                    Duration::from_nanos(0)
                };
        }
    }
}

impl Future for Subscriber {
    type Output = Option<Event>;

    fn poll(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Self::Output> {
        loop {
            let mut future_rx = if let Some(future_rx) = self.existing.take() {
                future_rx
            } else {
                match self.rx.try_recv() {
                    Ok(future_rx) => future_rx,
                    Err(TryRecvError::Empty) => break,
                    Err(TryRecvError::Disconnected) => {
                        return Poll::Ready(None)
                    }
                }
            };

            match Future::poll(Pin::new(&mut future_rx), cx) {
                Poll::Ready(Some(event)) => return Poll::Ready(event),
                Poll::Ready(None) => continue,
                Poll::Pending => {
                    self.existing = Some(future_rx);
                    return Poll::Pending;
                }
            }
        }
        let mut home = self.home.write();
        let entry = home.get_mut(&self.id).unwrap();
        entry.0 = Some(cx.waker().clone());
        Poll::Pending
    }
}

impl Iterator for Subscriber {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        loop {
            let future_rx = self.rx.recv().ok()?;
            match future_rx.wait() {
                Some(Some(event)) => return Some(event),
                Some(None) => return None,
                None => continue,
            }
        }
    }
}

#[derive(Debug, Default)]
pub(crate) struct Subscribers {
    watched: RwLock<BTreeMap<Vec<u8>, Arc<RwLock<Senders>>>>,
    ever_used: AtomicBool,
}

impl Drop for Subscribers {
    fn drop(&mut self) {
        let watched = self.watched.read();

        for senders in watched.values() {
            let senders =
                std::mem::replace(&mut *senders.write(), Map::default());
            for (_, (waker, sender)) in senders {
                drop(sender);
                if let Some(waker) = waker {
                    waker.wake();
                }
            }
        }
    }
}

impl Subscribers {
    pub(crate) fn register(&self, prefix: &[u8]) -> Subscriber {
        self.ever_used.store(true, Relaxed);
        let r_mu = {
            let r_mu = self.watched.read();
            if r_mu.contains_key(prefix) {
                r_mu
            } else {
                drop(r_mu);
                let mut w_mu = self.watched.write();
                if !w_mu.contains_key(prefix) {
                    let old = w_mu.insert(
                        prefix.to_vec(),
                        Arc::new(RwLock::new(Map::default())),
                    );
                    assert!(old.is_none());
                }
                drop(w_mu);
                self.watched.read()
            }
        };

        let (tx, rx) = sync_channel(1024);

        let arc_senders = &r_mu[prefix];
        let mut w_senders = arc_senders.write();

        let id = ID_GEN.fetch_add(1, Relaxed);

        w_senders.insert(id, (None, tx));

        Subscriber { id, rx, existing: None, home: arc_senders.clone() }
    }

    pub(crate) fn reserve<R: AsRef<[u8]>>(
        &self,
        key: R,
    ) -> Option<ReservedBroadcast> {
        if !self.ever_used.load(Relaxed) {
            return None;
        }

        let r_mu = self.watched.read();
        let prefixes = r_mu.iter().filter(|(k, _)| key.as_ref().starts_with(k));

        let mut subscribers = vec![];

        for (_, subs_rwl) in prefixes {
            let subs = subs_rwl.read();

            for (_id, (waker, sender)) in subs.iter() {
                let (tx, rx) = OneShot::pair();
                if sender.send(rx).is_err() {
                    continue;
                }
                subscribers.push((waker.clone(), tx));
            }
        }

        if subscribers.is_empty() {
            None
        } else {
            Some(ReservedBroadcast { subscribers })
        }
    }
}

pub(crate) struct ReservedBroadcast {
    subscribers: Vec<(Option<Waker>, OneShotFiller<Option<Event>>)>,
}

impl ReservedBroadcast {
    pub fn complete(self, event: &Event) {
        let iter = self.subscribers.into_iter();

        for (waker, tx) in iter {
            tx.fill(Some(event.clone()));
            if let Some(waker) = waker {
                waker.wake();
            }
        }
    }
}

#[test]
fn basic_subscriber() {
    let subs = Subscribers::default();

    let mut s2 = subs.register(&[0]);
    let mut s3 = subs.register(&[0, 1]);
    let mut s4 = subs.register(&[1, 2]);

    let r1 = subs.reserve(b"awft");
    assert!(r1.is_none());

    let mut s1 = subs.register(&[]);

    let k2: IVec = vec![].into();
    let r2 = subs.reserve(&k2).unwrap();
    r2.complete(&Event::Insert { key: k2.clone(), value: k2.clone() });

    let k3: IVec = vec![0].into();
    let r3 = subs.reserve(&k3).unwrap();
    r3.complete(&Event::Insert { key: k3.clone(), value: k3.clone() });

    let k4: IVec = vec![0, 1].into();
    let r4 = subs.reserve(&k4).unwrap();
    r4.complete(&Event::Remove { key: k4.clone() });

    let k5: IVec = vec![0, 1, 2].into();
    let r5 = subs.reserve(&k5).unwrap();
    r5.complete(&Event::Insert { key: k5.clone(), value: k5.clone() });

    let k6: IVec = vec![1, 1, 2].into();
    let r6 = subs.reserve(&k6).unwrap();
    r6.complete(&Event::Remove { key: k6.clone() });

    let k7: IVec = vec![1, 1, 2].into();
    let r7 = subs.reserve(&k7).unwrap();
    drop(r7);

    let k8: IVec = vec![1, 2, 2].into();
    let r8 = subs.reserve(&k8).unwrap();
    r8.complete(&Event::Insert { key: k8.clone(), value: k8.clone() });

    assert_eq!(s1.next().unwrap().key(), &*k2);
    assert_eq!(s1.next().unwrap().key(), &*k3);
    assert_eq!(s1.next().unwrap().key(), &*k4);
    assert_eq!(s1.next().unwrap().key(), &*k5);
    assert_eq!(s1.next().unwrap().key(), &*k6);
    assert_eq!(s1.next().unwrap().key(), &*k8);

    assert_eq!(s2.next().unwrap().key(), &*k3);
    assert_eq!(s2.next().unwrap().key(), &*k4);
    assert_eq!(s2.next().unwrap().key(), &*k5);

    assert_eq!(s3.next().unwrap().key(), &*k4);
    assert_eq!(s3.next().unwrap().key(), &*k5);

    assert_eq!(s4.next().unwrap().key(), &*k8);
}
<|endoftext|>


<commit_before>// Portions of this file are Copyright 2014 The Rust Project Developers.
// See http://rust-lang.org/COPYRIGHT.

use libc;
use core::mem;
use errno::{SysError, SysResult};

pub use libc::consts::os::posix88::{
    SIGHUP,   // 1
    SIGINT,   // 2
    SIGQUIT,  // 3
    SIGILL,   // 4
    SIGABRT,  // 6
    SIGFPE,   // 8
    SIGKILL,  // 9
    SIGSEGV,  // 11
    SIGPIPE,  // 13
    SIGALRM,  // 14
    SIGTERM,  // 15
};

pub use self::signal::{
    SIGTRAP,
    SIGIOT,
    SIGBUS,
    SIGSYS,
    SIGURG,
    SIGSTOP,
    SIGTSTP,
    SIGCONT,
    SIGCHLD,
    SIGTTIN,
    SIGTTOU,
    SIGIO,
    SIGXCPU,
    SIGXFSZ,
    SIGVTALRM,
    SIGPROF,
    SIGWINCH,
    SIGUSR1,
    SIGUSR2,
};

pub use self::signal::SockFlag;
pub use self::signal::sigset_t;

// This doesn't always exist, but when it does, it's 7
pub const SIGEMT: libc::c_int = 7;

#[cfg(any(all(target_os = "linux",
              any(target_arch = "x86",
                  target_arch = "x86_64",
                  target_arch = "arm")),
          target_os = "android"))]
pub mod signal {
    use libc;

    bitflags!(
        flags SockFlag: libc::c_ulong {
            const SA_NOCLDSTOP = 0x00000001,
            const SA_NOCLDWAIT = 0x00000002,
            const SA_NODEFER   = 0x40000000,
            const SA_ONSTACK   = 0x08000000,
            const SA_RESETHAND = 0x80000000,
            const SA_RESTART   = 0x10000000,
            const SA_SIGINFO   = 0x00000004,
        }
    )

    pub const SIGTRAP:      libc::c_int = 5;
    pub const SIGIOT:       libc::c_int = 6;
    pub const SIGBUS:       libc::c_int = 7;
    pub const SIGUSR1:      libc::c_int = 10;
    pub const SIGUSR2:      libc::c_int = 12;
    pub const SIGSTKFLT:    libc::c_int = 16;
    pub const SIGCHLD:      libc::c_int = 17;
    pub const SIGCONT:      libc::c_int = 18;
    pub const SIGSTOP:      libc::c_int = 19;
    pub const SIGTSTP:      libc::c_int = 20;
    pub const SIGTTIN:      libc::c_int = 21;
    pub const SIGTTOU:      libc::c_int = 22;
    pub const SIGURG:       libc::c_int = 23;
    pub const SIGXCPU:      libc::c_int = 24;
    pub const SIGXFSZ:      libc::c_int = 25;
    pub const SIGVTALRM:    libc::c_int = 26;
    pub const SIGPROF:      libc::c_int = 27;
    pub const SIGWINCH:     libc::c_int = 28;
    pub const SIGIO:        libc::c_int = 29;
    pub const SIGPOLL:      libc::c_int = 29;
    pub const SIGPWR:       libc::c_int = 30;
    pub const SIGSYS:       libc::c_int = 31;
    pub const SIGUNUSED:    libc::c_int = 31;

    // This definition is not as accurate as it could be, {pid, uid, status} is
    // actually a giant union. Currently we're only interested in these fields,
    // however.
    #[repr(C)]
    pub struct siginfo {
        si_signo: libc::c_int,
        si_errno: libc::c_int,
        si_code: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[repr(C)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        pub sa_flags: SockFlag,
        sa_restorer: *mut libc::c_void,
    }

    #[repr(C)]
    #[cfg(target_word_size = "32")]
    pub struct sigset_t {
        __val: [libc::c_ulong, ..32],
    }

    #[repr(C)]
    #[cfg(target_word_size = "64")]
    pub struct sigset_t {
        __val: [libc::c_ulong, ..16],
    }
}

#[cfg(all(target_os = "linux",
          any(target_arch = "mips", target_arch = "mipsel")))]
pub mod signal {
    use libc;

    bitflags!(
        flags SockFlag: libc::c_uint {
            const SA_NOCLDSTOP = 0x00000001,
            const SA_NOCLDWAIT = 0x00001000,
            const SA_NODEFER   = 0x40000000,
            const SA_ONSTACK   = 0x08000000,
            const SA_RESETHAND = 0x80000000,
            const SA_RESTART   = 0x10000000,
            const SA_SIGINFO   = 0x00000008,
        }
    )

    pub const SIGTRAP:      libc::c_int = 5;
    pub const SIGIOT:       libc::c_int = 6;
    pub const SIGBUS:       libc::c_int = 10;
    pub const SIGSYS:       libc::c_int = 12;
    pub const SIGUSR1:      libc::c_int = 16;
    pub const SIGUSR2:      libc::c_int = 17;
    pub const SIGCHLD:      libc::c_int = 18;
    pub const SIGCLD:       libc::c_int = 18;
    pub const SIGPWR:       libc::c_int = 19;
    pub const SIGWINCH:     libc::c_int = 20;
    pub const SIGURG:       libc::c_int = 21;
    pub const SIGIO:        libc::c_int = 22;
    pub const SIGPOLL:      libc::c_int = 22;
    pub const SIGSTOP:      libc::c_int = 23;
    pub const SIGTSTP:      libc::c_int = 24;
    pub const SIGCONT:      libc::c_int = 25;
    pub const SIGTTIN:      libc::c_int = 26;
    pub const SIGTTOU:      libc::c_int = 27;
    pub const SIGVTALRM:    libc::c_int = 28;
    pub const SIGPROF:      libc::c_int = 29;
    pub const SIGXCPU:      libc::c_int = 30;
    pub const SIGFSZ:       libc::c_int = 31;

    // This definition is not as accurate as it could be, {pid, uid, status} is
    // actually a giant union. Currently we're only interested in these fields,
    // however.
    #[repr(C)]
    pub struct siginfo {
        si_signo: libc::c_int,
        si_code: libc::c_int,
        si_errno: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[repr(C)]
    pub struct sigaction {
        pub sa_flags: SockFlag,
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        sa_restorer: *mut libc::c_void,
        sa_resv: [libc::c_int, ..1],
    }

    #[repr(C)]
    pub struct sigset_t {
        __val: [libc::c_ulong, ..32],
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly"))]
pub mod signal {
    use libc;

    bitflags!(
        flags SockFlag: libc::c_int {
            const SA_NOCLDSTOP = 0x0008,
            const SA_NOCLDWAIT = 0x0020,
            const SA_NODEFER   = 0x0010,
            const SA_ONSTACK   = 0x0001,
            const SA_RESETHAND = 0x0004,
            const SA_RESTART   = 0x0002,
            const SA_SIGINFO   = 0x0040,
        }
    )

    pub const SIGTRAP:      libc::c_int = 5;
    pub const SIGIOT:       libc::c_int = 6;
    pub const SIGBUS:       libc::c_int = 10;
    pub const SIGSYS:       libc::c_int = 12;
    pub const SIGURG:       libc::c_int = 16;
    pub const SIGSTOP:      libc::c_int = 17;
    pub const SIGTSTP:      libc::c_int = 18;
    pub const SIGCONT:      libc::c_int = 19;
    pub const SIGCHLD:      libc::c_int = 20;
    pub const SIGTTIN:      libc::c_int = 21;
    pub const SIGTTOU:      libc::c_int = 22;
    pub const SIGIO:        libc::c_int = 23;
    pub const SIGXCPU:      libc::c_int = 24;
    pub const SIGXFSZ:      libc::c_int = 25;
    pub const SIGVTALRM:    libc::c_int = 26;
    pub const SIGPROF:      libc::c_int = 27;
    pub const SIGWINCH:     libc::c_int = 28;
    pub const SIGINFO:      libc::c_int = 29;
    pub const SIGUSR1:      libc::c_int = 30;
    pub const SIGUSR2:      libc::c_int = 31;

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub type sigset_t = u32;
    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
    #[repr(C)]
    pub struct sigset_t {
        bits: [u32, ..4],
    }

    // This structure has more fields, but we're not all that interested in
    // them.
    #[repr(C)]
    pub struct siginfo {
        pub si_signo: libc::c_int,
        pub si_errno: libc::c_int,
        pub si_code: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    #[repr(C)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        sa_tramp: *mut libc::c_void,
        pub sa_mask: sigset_t,
        pub sa_flags: SockFlag,
    }

    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
    #[repr(C)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_flags: SockFlag,
        pub sa_mask: sigset_t,
    }

}

mod ffi {
    use libc;
    use super::signal::{sigaction, sigset_t};

    extern {
        pub fn sigaction(signum: libc::c_int,
                         act: *const sigaction,
                         oldact: *mut sigaction) -> libc::c_int;

        pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
        pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
        pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;
    }
}

pub struct SigSet {
    sigset: sigset_t
}

pub type SigNum = libc::c_int;

impl SigSet {
    pub fn empty() -> SigSet {
        let mut sigset = unsafe { mem::uninitialized::<sigset_t>() };
        let _ = unsafe { ffi::sigemptyset(&mut sigset as *mut sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn add(&mut self, signum: SigNum) -> SysResult<()> {
        let res = unsafe { ffi::sigaddset(&mut self.sigset as *mut sigset_t, signum) };

        if res < 0 {
            return Err(SysError::last());
        }

        Ok(())
    }

    pub fn remove(&mut self, signum: SigNum) -> SysResult<()> {
        let res = unsafe { ffi::sigdelset(&mut self.sigset as *mut sigset_t, signum) };

        if res < 0 {
            return Err(SysError::last());
        }

        Ok(())
    }
}

type sigaction_t = self::signal::sigaction;

pub struct SigAction {
    sigaction: sigaction_t
}

impl SigAction {
    pub fn new(handler: extern fn(libc::c_int), flags: SockFlag, mask: SigSet) -> SigAction {
        let mut s = unsafe { mem::uninitialized::<sigaction_t>() };
        s.sa_handler = handler;
        s.sa_flags = flags;
        s.sa_mask = mask.sigset;

        SigAction { sigaction: s }
    }
}

pub fn sigaction(signum: SigNum, sigaction: &SigAction) -> SysResult<SigAction> {
    let mut oldact = unsafe { mem::uninitialized::<sigaction_t>() };

    let res = unsafe {
        ffi::sigaction(signum, &sigaction.sigaction as *const sigaction_t, &mut oldact as *mut sigaction_t)
    };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(SigAction { sigaction: oldact })
}
<commit_msg>Bind kill<commit_after>// Portions of this file are Copyright 2014 The Rust Project Developers.
// See http://rust-lang.org/COPYRIGHT.

use libc;
use core::mem;
use errno::{SysError, SysResult};

pub use libc::consts::os::posix88::{
    SIGHUP,   // 1
    SIGINT,   // 2
    SIGQUIT,  // 3
    SIGILL,   // 4
    SIGABRT,  // 6
    SIGFPE,   // 8
    SIGKILL,  // 9
    SIGSEGV,  // 11
    SIGPIPE,  // 13
    SIGALRM,  // 14
    SIGTERM,  // 15
};

pub use self::signal::{
    SIGTRAP,
    SIGIOT,
    SIGBUS,
    SIGSYS,
    SIGURG,
    SIGSTOP,
    SIGTSTP,
    SIGCONT,
    SIGCHLD,
    SIGTTIN,
    SIGTTOU,
    SIGIO,
    SIGXCPU,
    SIGXFSZ,
    SIGVTALRM,
    SIGPROF,
    SIGWINCH,
    SIGUSR1,
    SIGUSR2,
};

pub use self::signal::SockFlag;
pub use self::signal::sigset_t;

// This doesn't always exist, but when it does, it's 7
pub const SIGEMT: libc::c_int = 7;

#[cfg(any(all(target_os = "linux",
              any(target_arch = "x86",
                  target_arch = "x86_64",
                  target_arch = "arm")),
          target_os = "android"))]
pub mod signal {
    use libc;

    bitflags!(
        flags SockFlag: libc::c_ulong {
            const SA_NOCLDSTOP = 0x00000001,
            const SA_NOCLDWAIT = 0x00000002,
            const SA_NODEFER   = 0x40000000,
            const SA_ONSTACK   = 0x08000000,
            const SA_RESETHAND = 0x80000000,
            const SA_RESTART   = 0x10000000,
            const SA_SIGINFO   = 0x00000004,
        }
    )

    pub const SIGTRAP:      libc::c_int = 5;
    pub const SIGIOT:       libc::c_int = 6;
    pub const SIGBUS:       libc::c_int = 7;
    pub const SIGUSR1:      libc::c_int = 10;
    pub const SIGUSR2:      libc::c_int = 12;
    pub const SIGSTKFLT:    libc::c_int = 16;
    pub const SIGCHLD:      libc::c_int = 17;
    pub const SIGCONT:      libc::c_int = 18;
    pub const SIGSTOP:      libc::c_int = 19;
    pub const SIGTSTP:      libc::c_int = 20;
    pub const SIGTTIN:      libc::c_int = 21;
    pub const SIGTTOU:      libc::c_int = 22;
    pub const SIGURG:       libc::c_int = 23;
    pub const SIGXCPU:      libc::c_int = 24;
    pub const SIGXFSZ:      libc::c_int = 25;
    pub const SIGVTALRM:    libc::c_int = 26;
    pub const SIGPROF:      libc::c_int = 27;
    pub const SIGWINCH:     libc::c_int = 28;
    pub const SIGIO:        libc::c_int = 29;
    pub const SIGPOLL:      libc::c_int = 29;
    pub const SIGPWR:       libc::c_int = 30;
    pub const SIGSYS:       libc::c_int = 31;
    pub const SIGUNUSED:    libc::c_int = 31;

    // This definition is not as accurate as it could be, {pid, uid, status} is
    // actually a giant union. Currently we're only interested in these fields,
    // however.
    #[repr(C)]
    pub struct siginfo {
        si_signo: libc::c_int,
        si_errno: libc::c_int,
        si_code: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[repr(C)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        pub sa_flags: SockFlag,
        sa_restorer: *mut libc::c_void,
    }

    #[repr(C)]
    #[cfg(target_word_size = "32")]
    pub struct sigset_t {
        __val: [libc::c_ulong, ..32],
    }

    #[repr(C)]
    #[cfg(target_word_size = "64")]
    pub struct sigset_t {
        __val: [libc::c_ulong, ..16],
    }
}

#[cfg(all(target_os = "linux",
          any(target_arch = "mips", target_arch = "mipsel")))]
pub mod signal {
    use libc;

    bitflags!(
        flags SockFlag: libc::c_uint {
            const SA_NOCLDSTOP = 0x00000001,
            const SA_NOCLDWAIT = 0x00001000,
            const SA_NODEFER   = 0x40000000,
            const SA_ONSTACK   = 0x08000000,
            const SA_RESETHAND = 0x80000000,
            const SA_RESTART   = 0x10000000,
            const SA_SIGINFO   = 0x00000008,
        }
    )

    pub const SIGTRAP:      libc::c_int = 5;
    pub const SIGIOT:       libc::c_int = 6;
    pub const SIGBUS:       libc::c_int = 10;
    pub const SIGSYS:       libc::c_int = 12;
    pub const SIGUSR1:      libc::c_int = 16;
    pub const SIGUSR2:      libc::c_int = 17;
    pub const SIGCHLD:      libc::c_int = 18;
    pub const SIGCLD:       libc::c_int = 18;
    pub const SIGPWR:       libc::c_int = 19;
    pub const SIGWINCH:     libc::c_int = 20;
    pub const SIGURG:       libc::c_int = 21;
    pub const SIGIO:        libc::c_int = 22;
    pub const SIGPOLL:      libc::c_int = 22;
    pub const SIGSTOP:      libc::c_int = 23;
    pub const SIGTSTP:      libc::c_int = 24;
    pub const SIGCONT:      libc::c_int = 25;
    pub const SIGTTIN:      libc::c_int = 26;
    pub const SIGTTOU:      libc::c_int = 27;
    pub const SIGVTALRM:    libc::c_int = 28;
    pub const SIGPROF:      libc::c_int = 29;
    pub const SIGXCPU:      libc::c_int = 30;
    pub const SIGFSZ:       libc::c_int = 31;

    // This definition is not as accurate as it could be, {pid, uid, status} is
    // actually a giant union. Currently we're only interested in these fields,
    // however.
    #[repr(C)]
    pub struct siginfo {
        si_signo: libc::c_int,
        si_code: libc::c_int,
        si_errno: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[repr(C)]
    pub struct sigaction {
        pub sa_flags: SockFlag,
        pub sa_handler: extern fn(libc::c_int),
        pub sa_mask: sigset_t,
        sa_restorer: *mut libc::c_void,
        sa_resv: [libc::c_int, ..1],
    }

    #[repr(C)]
    pub struct sigset_t {
        __val: [libc::c_ulong, ..32],
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly"))]
pub mod signal {
    use libc;

    bitflags!(
        flags SockFlag: libc::c_int {
            const SA_NOCLDSTOP = 0x0008,
            const SA_NOCLDWAIT = 0x0020,
            const SA_NODEFER   = 0x0010,
            const SA_ONSTACK   = 0x0001,
            const SA_RESETHAND = 0x0004,
            const SA_RESTART   = 0x0002,
            const SA_SIGINFO   = 0x0040,
        }
    )

    pub const SIGTRAP:      libc::c_int = 5;
    pub const SIGIOT:       libc::c_int = 6;
    pub const SIGBUS:       libc::c_int = 10;
    pub const SIGSYS:       libc::c_int = 12;
    pub const SIGURG:       libc::c_int = 16;
    pub const SIGSTOP:      libc::c_int = 17;
    pub const SIGTSTP:      libc::c_int = 18;
    pub const SIGCONT:      libc::c_int = 19;
    pub const SIGCHLD:      libc::c_int = 20;
    pub const SIGTTIN:      libc::c_int = 21;
    pub const SIGTTOU:      libc::c_int = 22;
    pub const SIGIO:        libc::c_int = 23;
    pub const SIGXCPU:      libc::c_int = 24;
    pub const SIGXFSZ:      libc::c_int = 25;
    pub const SIGVTALRM:    libc::c_int = 26;
    pub const SIGPROF:      libc::c_int = 27;
    pub const SIGWINCH:     libc::c_int = 28;
    pub const SIGINFO:      libc::c_int = 29;
    pub const SIGUSR1:      libc::c_int = 30;
    pub const SIGUSR2:      libc::c_int = 31;

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub type sigset_t = u32;
    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
    #[repr(C)]
    pub struct sigset_t {
        bits: [u32, ..4],
    }

    // This structure has more fields, but we're not all that interested in
    // them.
    #[repr(C)]
    pub struct siginfo {
        pub si_signo: libc::c_int,
        pub si_errno: libc::c_int,
        pub si_code: libc::c_int,
        pub pid: libc::pid_t,
        pub uid: libc::uid_t,
        pub status: libc::c_int,
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    #[repr(C)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        sa_tramp: *mut libc::c_void,
        pub sa_mask: sigset_t,
        pub sa_flags: SockFlag,
    }

    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
    #[repr(C)]
    pub struct sigaction {
        pub sa_handler: extern fn(libc::c_int),
        pub sa_flags: SockFlag,
        pub sa_mask: sigset_t,
    }

}

mod ffi {
    use libc;
    use super::signal::{sigaction, sigset_t};

    extern {
        pub fn sigaction(signum: libc::c_int,
                         act: *const sigaction,
                         oldact: *mut sigaction) -> libc::c_int;

        pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
        pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
        pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;

        pub fn kill(pid: libc::pid_t, signum: libc::c_int) -> libc::c_int;
    }
}

pub struct SigSet {
    sigset: sigset_t
}

pub type SigNum = libc::c_int;

impl SigSet {
    pub fn empty() -> SigSet {
        let mut sigset = unsafe { mem::uninitialized::<sigset_t>() };
        let _ = unsafe { ffi::sigemptyset(&mut sigset as *mut sigset_t) };

        SigSet { sigset: sigset }
    }

    pub fn add(&mut self, signum: SigNum) -> SysResult<()> {
        let res = unsafe { ffi::sigaddset(&mut self.sigset as *mut sigset_t, signum) };

        if res < 0 {
            return Err(SysError::last());
        }

        Ok(())
    }

    pub fn remove(&mut self, signum: SigNum) -> SysResult<()> {
        let res = unsafe { ffi::sigdelset(&mut self.sigset as *mut sigset_t, signum) };

        if res < 0 {
            return Err(SysError::last());
        }

        Ok(())
    }
}

type sigaction_t = self::signal::sigaction;

pub struct SigAction {
    sigaction: sigaction_t
}

impl SigAction {
    pub fn new(handler: extern fn(libc::c_int), flags: SockFlag, mask: SigSet) -> SigAction {
        let mut s = unsafe { mem::uninitialized::<sigaction_t>() };
        s.sa_handler = handler;
        s.sa_flags = flags;
        s.sa_mask = mask.sigset;

        SigAction { sigaction: s }
    }
}

pub fn sigaction(signum: SigNum, sigaction: &SigAction) -> SysResult<SigAction> {
    let mut oldact = unsafe { mem::uninitialized::<sigaction_t>() };

    let res = unsafe {
        ffi::sigaction(signum, &sigaction.sigaction as *const sigaction_t, &mut oldact as *mut sigaction_t)
    };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(SigAction { sigaction: oldact })
}

pub fn kill(pid: libc::pid_t, signum: SigNum) -> SysResult<()> {
    let res = unsafe { ffi::kill(pid, signum) };

    if res < 0 {
        return Err(SysError::last());
    }

    Ok(())
}
<|endoftext|>