<commit_before>// Copyright 2013 The SAX-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[comment = "Wrapper for libxml2's SAX parser."];
#[pkgid = "github.com/bjz/sax-rs#sax:0.1"];

#[crate_type = "lib"];

#[feature(globs)];

extern mod extra;

use std::cast;
use std::comm::{Port, stream};
use std::libc::{c_char, c_int};
use std::str;
// use std::task;

use error::ErrorData;

pub mod error;
pub mod ffi;
mod extfn;

/// Events to be sent by the parser.
#[deriving(Eq, Clone)]
pub enum ParseEvent {
    /// The document has begun to be processed.
    StartDocument,
    /// The document processing has finished.
    EndDocument,
    /// An opening tag has was parsed.
    StartElement(~str, Attributes),
    /// A closing tag was parsed.
    EndElement(~str),
    /// Some characters between tags have been recived.
    Characters(~str),
    /// A comment tag was parsed.
    Comment(~str),
    /// A `CDATA` block was parsed.
    CdataBlock(~str),
}

impl ToStr for ParseEvent {
    fn to_str(&self) -> ~str {
        match *self {
            StartDocument => ~"START DOCUMENT",
            EndDocument => ~"END DOCUMENT",
            StartElement(ref name, ref atts) => format!("<{}{}>", *name, atts.to_str()),
            EndElement(ref name) => format!("</{}>", *name),
            Characters(ref ch) => ch.clone(),
            Comment(ref value) => format!("", *value),
            CdataBlock(ref value) => format!("<![CDATA[{}]]>", *value),
        }
    }
}

#[deriving(Eq, Clone)]
pub struct Attribute {
    name: ~str,
    value: ~str,
}

/// A list of attributes
#[deriving(Eq, Clone)]
pub struct Attributes(~[Attribute]);

impl Attributes {
    unsafe fn from_buf(atts: **ffi::xmlChar) -> Attributes {
        let mut ret = Attributes(~[]);
        let mut ptr = atts as **c_char;
        while !ptr.is_null() && !(*ptr).is_null() {
            ret.push(
                Attribute {
                    name: str::raw::from_c_str(*ptr),
                    value: str::raw::from_c_str(*ptr.offset(1)),
                }
            );
            ptr = ptr.offset(2);
        }
        ret
    }

    pub fn find<'a>(&'a self, name: &str) -> Option<&'a str> {
        self.iter()
            .find(|att| name == att.name)
            .map(|att| att.value.as_slice())
    }

    pub fn get<'a>(&'a self, name: &str) -> &'a str {
        self.find(name).expect(format!("Could not find an attribute with the name \"{}\"", name))
    }

    pub fn find_clone(&self, name: &str) -> Option<~str> {
        self.find(name).map(|v| v.to_owned())
    }

    pub fn get_clone(&self, name: &str) -> ~str {
        self.get(name).to_owned()
    }
}

impl ToStr for Attributes {
    fn to_str(&self) -> ~str {
        self.iter().map(|att| {
            format!(" {}=\"{}\"", att.name, att.value)
        }).to_owned_vec().concat()
    }
}

/// Either a parse event wrapped in `Ok` or some Error data wrapped in `Err`.
pub type ParseResult = Result<ParseEvent, ErrorData>;

/// A port to recieve `ParseResult`s from the parser.
pub struct SaxPort {
    priv port: Port<ParseResult>,
}

impl GenericPort<ParseResult> for SaxPort {
    /// Recives a new parse message.
    ///
    /// # Failure
    ///
    /// Fails if the method is called again after the final `Ok(EndDocument)`
    /// parse result has been recived.
    fn recv(&self) -> ParseResult {
        self.port.try_recv().expect(
            "Could not get a new parse result, the parser has already finished!"
        )
    }

    /// Receives a parse result wrapped in `Some`, or `None` if the parser has
    /// finished.
    fn try_recv(&self) -> Option<ParseResult> {
        self.port.try_recv()
    }
}

/// Parses the entire XML string.
///
/// # Returns
///
/// A port that recieves parse results.
///
/// # Example
///
/// ~~~rust
/// let port = parse_xml("<hullo><world /></hullo>");
/// loop {
///     if port.recv() == Ok(EndDocument) { break }
/// }
/// ~~~
#[inline(never)]
pub fn parse_xml(src: &str) -> SaxPort {
    let len = src.len() as c_int;
    src.to_c_str().with_ref(|c_str| {
        let (port, chan) = stream();
        // do task::spawn {
            unsafe {
                ffi::xmlSAXUserParseMemory(&extfn::new_handler(),
                                           cast::transmute(&chan),
                                           c_str, len);
                ffi::xmlCleanupParser();
            }
        // }
        SaxPort { port: port }
    })
}

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

    fn get_mock_atts() -> Attributes {
        Attributes(~[
            Attribute { name: ~"foo", value: ~"0" },
            Attribute { name: ~"bar", value: ~"1" },
            Attribute { name: ~"baz", value: ~"2" }
        ])
    }

    #[test]
    fn test_att_get() {
        let atts = get_mock_atts();
        assert_eq!(atts.get("foo"), "0");
        assert_eq!(atts.get("bar"), "1");
        assert_eq!(atts.get("baz"), "2");
    }

    #[test]
    fn test_att_find() {
        let atts = get_mock_atts();
        assert_eq!(atts.find("foo"), Some("0"));
        assert_eq!(atts.find("bar"), Some("1"));
        assert_eq!(atts.find("baz"), Some("2"));
    }

    #[test]
    fn test() {
        let sax = parse_xml(
            "<hello><this />test</hello>"
        );
        loop {
            match sax.recv() {
                Ok(StartDocument) => (),
                Ok(EndDocument) => break,
                Ok(event) => println(event.to_str()),
                Err(err) => println(err.to_str()),
            }
        }
    }
}
<commit_msg>updated sax to work with new std::comm<commit_after>// Copyright 2013 The SAX-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[comment = "Wrapper for libxml2's SAX parser."];
#[pkgid = "github.com/bjz/sax-rs#sax:0.1"];

#[crate_type = "lib"];

#[feature(globs)];

extern mod extra;

use std::cast;
use std::comm::{Port, Chan};
use std::libc::{c_char, c_int};
use std::str;
// use std::task;

use error::ErrorData;

pub mod error;
pub mod ffi;
mod extfn;

/// Events to be sent by the parser.
#[deriving(Eq, Clone)]
pub enum ParseEvent {
    /// The document has begun to be processed.
    StartDocument,
    /// The document processing has finished.
    EndDocument,
    /// An opening tag has was parsed.
    StartElement(~str, Attributes),
    /// A closing tag was parsed.
    EndElement(~str),
    /// Some characters between tags have been recived.
    Characters(~str),
    /// A comment tag was parsed.
    Comment(~str),
    /// A `CDATA` block was parsed.
    CdataBlock(~str),
}

impl ToStr for ParseEvent {
    fn to_str(&self) -> ~str {
        match *self {
            StartDocument => ~"START DOCUMENT",
            EndDocument => ~"END DOCUMENT",
            StartElement(ref name, ref atts) => format!("<{}{}>", *name, atts.to_str()),
            EndElement(ref name) => format!("</{}>", *name),
            Characters(ref ch) => ch.clone(),
            Comment(ref value) => format!("", *value),
            CdataBlock(ref value) => format!("<![CDATA[{}]]>", *value),
        }
    }
}

#[deriving(Eq, Clone)]
pub struct Attribute {
    name: ~str,
    value: ~str,
}

/// A list of attributes
#[deriving(Eq, Clone)]
pub struct Attributes(~[Attribute]);

impl Attributes {
    unsafe fn from_buf(atts: **ffi::xmlChar) -> Attributes {
        let mut ret = Attributes(~[]);
        let mut ptr = atts as **c_char;
        while !ptr.is_null() && !(*ptr).is_null() {
            ret.push(
                Attribute {
                    name: str::raw::from_c_str(*ptr),
                    value: str::raw::from_c_str(*ptr.offset(1)),
                }
            );
            ptr = ptr.offset(2);
        }
        ret
    }

    pub fn find<'a>(&'a self, name: &str) -> Option<&'a str> {
        self.iter()
            .find(|att| name == att.name)
            .map(|att| att.value.as_slice())
    }

    pub fn get<'a>(&'a self, name: &str) -> &'a str {
        self.find(name).expect(format!("Could not find an attribute with the name \"{}\"", name))
    }

    pub fn find_clone(&self, name: &str) -> Option<~str> {
        self.find(name).map(|v| v.to_owned())
    }

    pub fn get_clone(&self, name: &str) -> ~str {
        self.get(name).to_owned()
    }
}

impl ToStr for Attributes {
    fn to_str(&self) -> ~str {
        self.iter().map(|att| {
            format!(" {}=\"{}\"", att.name, att.value)
        }).to_owned_vec().concat()
    }
}

/// Either a parse event wrapped in `Ok` or some Error data wrapped in `Err`.
pub type ParseResult = Result<ParseEvent, ErrorData>;

/// Parses the entire XML string.
///
/// # Returns
///
/// A port that recieves parse results.
///
/// # Example
///
/// ~~~rust
/// let port = parse_xml("<hullo><world /></hullo>");
/// loop {
///     if port.recv() == Ok(EndDocument) { break }
/// }
/// ~~~
#[inline(never)]
pub fn parse_xml(src: &str) -> Port<ParseResult> {
    let len = src.len() as c_int;
    src.to_c_str().with_ref(|c_str| {
        let (port, chan) = Chan::new();
        // do task::spawn {
            unsafe {
                ffi::xmlSAXUserParseMemory(&extfn::new_handler(),
                                           cast::transmute(&chan),
                                           c_str, len);
                ffi::xmlCleanupParser();
            }
        // }
        port
    })
}

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

    fn get_mock_atts() -> Attributes {
        Attributes(~[
            Attribute { name: ~"foo", value: ~"0" },
            Attribute { name: ~"bar", value: ~"1" },
            Attribute { name: ~"baz", value: ~"2" }
        ])
    }

    #[test]
    fn test_att_get() {
        let atts = get_mock_atts();
        assert_eq!(atts.get("foo"), "0");
        assert_eq!(atts.get("bar"), "1");
        assert_eq!(atts.get("baz"), "2");
    }

    #[test]
    fn test_att_find() {
        let atts = get_mock_atts();
        assert_eq!(atts.find("foo"), Some("0"));
        assert_eq!(atts.find("bar"), Some("1"));
        assert_eq!(atts.find("baz"), Some("2"));
    }

    #[test]
    fn test() {
        let sax = parse_xml(
            "<hello><this />test</hello>"
        );
        loop {
            match sax.recv() {
                Ok(StartDocument) => (),
                Ok(EndDocument) => break,
                Ok(event) => println(event.to_str()),
                Err(err) => println(err.to_str()),
            }
        }
    }
}
<|endoftext|>


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

// Code to handle a single block device.

use std::fs::OpenOptions;
use std::path::PathBuf;

use chrono::{DateTime, Utc};

use devicemapper::{Device, Sectors};

use super::super::engine::{BlockDev, HasUuid};
use super::super::errors::EngineResult;
use super::super::types::{DevUuid, PoolUuid};

use super::metadata::BDA;
use super::range_alloc::RangeAllocator;
use super::serde_structs::{BlockDevSave, Recordable};

#[derive(Debug)]
pub struct StratBlockDev {
    dev: Device,
    pub devnode: PathBuf,
    bda: BDA,
    used: RangeAllocator,
}

impl StratBlockDev {
    pub fn new(dev: Device,
               devnode: PathBuf,
               bda: BDA,
               allocator: RangeAllocator)
               -> StratBlockDev {
        StratBlockDev {
            dev: dev,
            devnode: devnode,
            bda: bda,
            used: allocator,
        }
    }

    /// Returns the blockdev's Device
    pub fn device(&self) -> &Device {
        &self.dev
    }

    pub fn wipe_metadata(&self) -> EngineResult<()> {
        let mut f = OpenOptions::new().write(true).open(&self.devnode)?;
        BDA::wipe(&mut f)
    }

    pub fn save_state(&mut self, time: &DateTime<Utc>, metadata: &[u8]) -> EngineResult<()> {
        let mut f = OpenOptions::new().write(true).open(&self.devnode)?;
        self.bda.save_state(time, metadata, &mut f)
    }

    /// List the available-for-upper-layer-use range in this blockdev.
    pub fn avail_range(&self) -> (Sectors, Sectors) {
        let start = self.metadata_size();
        let size = self.current_capacity();
        // Blockdev size is at least MIN_DEV_SIZE, so this can fail only if
        // size of metadata area exceeds 1 GiB. Initial metadata area size
        // is 4 MiB.
        assert!(start <= size);
        (start, size - start)
    }

    /// The device's UUID.
    pub fn uuid(&self) -> &DevUuid {
        self.bda.dev_uuid()
    }

    /// The device's pool's UUID.
    pub fn pool_uuid(&self) -> &PoolUuid {
        self.bda.pool_uuid()
    }

    /// Last time metadata was written to this device.
    pub fn last_update_time(&self) -> Option<&DateTime<Utc>> {
        self.bda.last_update_time()
    }

    // Find some sector ranges that could be allocated. If more
    // sectors are needed than our capacity, return partial results.
    pub fn request_space(&mut self, size: Sectors) -> (Sectors, Vec<(Sectors, Sectors)>) {
        self.used.request(size)
    }

    // ALL SIZE METHODS

    /// The size of the device as recorded in the metadata.
    pub fn recorded_size(&self) -> Sectors {
        self.bda.dev_size()
    }

    /// The actual size of the device now.
    pub fn current_capacity(&self) -> Sectors {
        self.used.capacity()
    }

    /// The number of Sectors on this device used by Stratis for metadata
    pub fn metadata_size(&self) -> Sectors {
        self.bda.size()
    }

    /// The number of Sectors on this device not allocated for any purpose.
    /// self.current_capacity() - self.metadata_size() >= self.available()
    pub fn available(&self) -> Sectors {
        self.used.available()
    }

    /// The maximum size of variable length metadata that can be accommodated.
    /// self.max_metadata_size() < self.metadata_size()
    pub fn max_metadata_size(&self) -> Sectors {
        self.bda.max_data_size()
    }
}

impl HasUuid for StratBlockDev {
    fn uuid(&self) -> &DevUuid {
        &self.bda.dev_uuid()
    }
}

impl BlockDev for StratBlockDev {
    fn devnode(&self) -> PathBuf {
        self.devnode.clone()
    }
}

impl Recordable<BlockDevSave> for StratBlockDev {
    fn record(&self) -> BlockDevSave {
        BlockDevSave { devnode: self.devnode.clone() }
    }
}
<commit_msg>Fix a needless-borrow clippy error<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Code to handle a single block device.

use std::fs::OpenOptions;
use std::path::PathBuf;

use chrono::{DateTime, Utc};

use devicemapper::{Device, Sectors};

use super::super::engine::{BlockDev, HasUuid};
use super::super::errors::EngineResult;
use super::super::types::{DevUuid, PoolUuid};

use super::metadata::BDA;
use super::range_alloc::RangeAllocator;
use super::serde_structs::{BlockDevSave, Recordable};

#[derive(Debug)]
pub struct StratBlockDev {
    dev: Device,
    pub devnode: PathBuf,
    bda: BDA,
    used: RangeAllocator,
}

impl StratBlockDev {
    pub fn new(dev: Device,
               devnode: PathBuf,
               bda: BDA,
               allocator: RangeAllocator)
               -> StratBlockDev {
        StratBlockDev {
            dev: dev,
            devnode: devnode,
            bda: bda,
            used: allocator,
        }
    }

    /// Returns the blockdev's Device
    pub fn device(&self) -> &Device {
        &self.dev
    }

    pub fn wipe_metadata(&self) -> EngineResult<()> {
        let mut f = OpenOptions::new().write(true).open(&self.devnode)?;
        BDA::wipe(&mut f)
    }

    pub fn save_state(&mut self, time: &DateTime<Utc>, metadata: &[u8]) -> EngineResult<()> {
        let mut f = OpenOptions::new().write(true).open(&self.devnode)?;
        self.bda.save_state(time, metadata, &mut f)
    }

    /// List the available-for-upper-layer-use range in this blockdev.
    pub fn avail_range(&self) -> (Sectors, Sectors) {
        let start = self.metadata_size();
        let size = self.current_capacity();
        // Blockdev size is at least MIN_DEV_SIZE, so this can fail only if
        // size of metadata area exceeds 1 GiB. Initial metadata area size
        // is 4 MiB.
        assert!(start <= size);
        (start, size - start)
    }

    /// The device's UUID.
    pub fn uuid(&self) -> &DevUuid {
        self.bda.dev_uuid()
    }

    /// The device's pool's UUID.
    pub fn pool_uuid(&self) -> &PoolUuid {
        self.bda.pool_uuid()
    }

    /// Last time metadata was written to this device.
    pub fn last_update_time(&self) -> Option<&DateTime<Utc>> {
        self.bda.last_update_time()
    }

    // Find some sector ranges that could be allocated. If more
    // sectors are needed than our capacity, return partial results.
    pub fn request_space(&mut self, size: Sectors) -> (Sectors, Vec<(Sectors, Sectors)>) {
        self.used.request(size)
    }

    // ALL SIZE METHODS

    /// The size of the device as recorded in the metadata.
    pub fn recorded_size(&self) -> Sectors {
        self.bda.dev_size()
    }

    /// The actual size of the device now.
    pub fn current_capacity(&self) -> Sectors {
        self.used.capacity()
    }

    /// The number of Sectors on this device used by Stratis for metadata
    pub fn metadata_size(&self) -> Sectors {
        self.bda.size()
    }

    /// The number of Sectors on this device not allocated for any purpose.
    /// self.current_capacity() - self.metadata_size() >= self.available()
    pub fn available(&self) -> Sectors {
        self.used.available()
    }

    /// The maximum size of variable length metadata that can be accommodated.
    /// self.max_metadata_size() < self.metadata_size()
    pub fn max_metadata_size(&self) -> Sectors {
        self.bda.max_data_size()
    }
}

impl HasUuid for StratBlockDev {
    fn uuid(&self) -> &DevUuid {
        self.bda.dev_uuid()
    }
}

impl BlockDev for StratBlockDev {
    fn devnode(&self) -> PathBuf {
        self.devnode.clone()
    }
}

impl Recordable<BlockDevSave> for StratBlockDev {
    fn record(&self) -> BlockDevSave {
        BlockDevSave { devnode: self.devnode.clone() }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "seq"]
#![feature(collections, core, rustc_private)]

// TODO: Make -w flag work with decimals
// TODO: Support -f flag

extern crate getopts;
extern crate libc;

use std::cmp;

#[path = "../common/util.rs"]
#[macro_use]
mod util;

static NAME: &'static str = "seq";

#[derive(Clone)]
struct SeqOptions {
    separator: String,
    terminator: Option<String>,
    widths: bool
}

fn parse_float(mut s: &str) -> Result<f64, String> {
    if s.starts_with("+") {
        s = &s[1..];
    }
    match s.parse() {
        Ok(n) => Ok(n),
        Err(e) => Err(format!("seq: invalid floating point argument `{}`: {}", s, e))
    }
}

fn escape_sequences(s: &str) -> String {
    s.replace("\\n", "\n").
        replace("\\t", "\t")
}

fn parse_options(args: Vec<String>, options: &mut SeqOptions) -> Result<Vec<String>, i32> {
    let mut seq_args = vec!();
    let program = args[0].clone();
    let mut iter = args.into_iter().skip(1);
    loop {
        match iter.next() {
            Some(arg) => match arg.as_slice() {
                "--help" | "-h" => {
                    print_help(&program);
                    return Err(0);
                }
                "--version" | "-V" => {
                    print_version();
                    return Err(0);
                }
                "-s" | "--separator" => match iter.next() {
                    Some(sep) => options.separator = sep,
                    None => {
                        show_error!("expected a separator after {}", arg);
                        return Err(1);
                    }
                },
                "-t" | "--terminator" => match iter.next() {
                    Some(term) => options.terminator = Some(term),
                    None => {
                        show_error!("expected a terminator after '{}'", arg);
                        return Err(1);
                    }
                },
                "-w" | "--widths" => options.widths = true,
                "--" => {
                    seq_args.extend(iter);
                    break;
                },
                _ => {
                    if arg.len() > 1 && arg.as_slice().char_at(0) == '-' {
                        let argptr: *const String = &arg;  // escape from the borrow checker
                        let mut chiter = unsafe { (*argptr).as_slice() }.chars().skip(1);
                        let mut ch = ' ';
                        while match chiter.next() { Some(m) => { ch = m; true } None => false } {
                            match ch {
                                'h' => {
                                    print_help(&program);
                                    return Err(0);
                                }
                                'V' => {
                                    print_version();
                                    return Err(0);
                                }
                                's' => match iter.next() {
                                    Some(sep) => {
                                        options.separator = sep;
                                        let next = chiter.next();
                                        if next.is_some() {
                                            show_error!("unexpected character ('{}')", next.unwrap());
                                            return Err(1);
                                        }
                                    }
                                    None => {
                                        show_error!("expected a separator after {}", arg);
                                        return Err(1);
                                    }
                                },
                                't' => match iter.next() {
                                    Some(term) => {
                                        options.terminator = Some(term);
                                        let next = chiter.next();
                                        if next.is_some() {
                                            show_error!("unexpected character ('{}')", next.unwrap());
                                            return Err(1);
                                        }
                                    }
                                    None => {
                                        show_error!("expected a terminator after {}", arg);
                                        return Err(1);
                                    }
                                },
                                'w' => options.widths = true,
                                _ => { seq_args.push(arg); break }
                            }
                        }
                    } else {
                        seq_args.push(arg);
                    }
                }
            },
            None => break
        }
    }
    Ok(seq_args)
}

fn print_help(program: &String) {
    let opts = [
        getopts::optopt("s", "separator", "Separator character (defaults to \\n)", ""),
        getopts::optopt("t", "terminator", "Terminator character (defaults to separator)", ""),
        getopts::optflag("w", "widths", "Equalize widths of all numbers by padding with zeros"),
        getopts::optflag("h", "help", "print this help text and exit"),
        getopts::optflag("V", "version", "print version and exit"),
    ];
    println!("seq 1.0.0\n");
    println!("Usage:\n  {} [-w] [-s string] [-t string] [first [step]] last\n", *program);
    println!("{}", getopts::usage("Print sequences of numbers", &opts));
}

fn print_version() {
    println!("seq 1.0.0\n");
}

pub fn uumain(args: Vec<String>) -> i32 {
    let program = args[0].clone();
    let mut options = SeqOptions {
        separator: "\n".to_string(),
        terminator: None,
        widths: false
    };
    let free = match parse_options(args, &mut options) {
        Ok(m) => m,
        Err(f) => return f
    };
    if free.len() < 1 || free.len() > 3 {
        crash!(1, "too {} operands.\nTry '{} --help' for more information.",
               if free.len() < 1 { "few" } else { "many" }, program);
    }
    let mut largest_dec = 0;
    let mut padding = 0;
    let first = if free.len() > 1 {
        let slice = free[0].as_slice();
        let len = slice.len();
        let dec = slice.find('.').unwrap_or(len);
        largest_dec = len - dec;
        padding = dec;
        match parse_float(slice) {
            Ok(n) => n,
            Err(s) => { show_error!("{}", s); return 1; }
        }
    } else {
        1.0
    };
    let step = if free.len() > 2 {
        let slice = free[1].as_slice();
        let len = slice.len();
        let dec = slice.find('.').unwrap_or(len);
        largest_dec = cmp::max(largest_dec, len - dec);
        padding = cmp::max(padding, dec);
        match parse_float(slice) {
            Ok(n) => n,
            Err(s) => { show_error!("{}", s); return 1; }
        }
    } else {
        1.0
    };
    let last = {
        let slice = free[free.len() - 1].as_slice();
        padding = cmp::max(padding, slice.find('.').unwrap_or(slice.len()));
        match parse_float(slice) {
            Ok(n) => n,
            Err(s) => { show_error!("{}", s); return 1; }
        }
    };
    let separator = escape_sequences(options.separator.as_slice());
    let terminator = match options.terminator {
        Some(term) => escape_sequences(term.as_slice()),
        None => separator.clone()
    };
    print_seq(first, step, last, largest_dec, separator, terminator, options.widths, padding);

    0
}

#[inline(always)]
fn done_printing(next: f64, step: f64, last: f64) -> bool {
    if step >= 0f64 {
        next > last
    } else {
        next < last
    }
}

fn print_seq(first: f64, step: f64, last: f64, largest_dec: usize, separator: String, terminator: String, pad: bool, padding: usize) {
    let mut i = 0isize;
    let mut value = first + i as f64 * step;
    while !done_printing(value, step, last) {
        let istr = value.to_string();
        let ilen = istr.len();
        let before_dec = istr.as_slice().find('.').unwrap_or(ilen);
        if pad && before_dec < padding {
            for _ in range(0, padding - before_dec) {
                if !pipe_print!("0") {
                    return;
                }
            }
        }
        pipe_print!("{}", istr);
        let mut idec = ilen - before_dec;
        if idec < largest_dec {
            if idec == 0 {
                if !pipe_print!(".") {
                    return;
                }
                idec += 1;
            }
            for _ in range(idec, largest_dec) {
                if !pipe_print!("0") {
                    return;
                }
            }
        }
        i += 1;
        value = first + i as f64 * step;
        if !done_printing(value, step, last) {
            if !pipe_print!("{}", separator) {
                return;
            }
        }
    }
    if (first >= last && step < 0f64) || (first <= last && step > 0f64) {
        pipe_print!("{}", terminator);
    }
}
<commit_msg>make seq build on nightly<commit_after>#![crate_name = "seq"]
#![feature(rustc_private)]

// TODO: Make -w flag work with decimals
// TODO: Support -f flag

extern crate getopts;
extern crate libc;

use std::cmp;
use std::io::Write;

#[path = "../common/util.rs"]
#[macro_use]
mod util;

static NAME: &'static str = "seq";

#[derive(Clone)]
struct SeqOptions {
    separator: String,
    terminator: Option<String>,
    widths: bool
}

fn parse_float(mut s: &str) -> Result<f64, String> {
    if s.starts_with("+") {
        s = &s[1..];
    }
    match s.parse() {
        Ok(n) => Ok(n),
        Err(e) => Err(format!("seq: invalid floating point argument `{}`: {}", s, e))
    }
}

fn escape_sequences(s: &str) -> String {
    s.replace("\\n", "\n").
        replace("\\t", "\t")
}

fn parse_options(args: Vec<String>, options: &mut SeqOptions) -> Result<Vec<String>, i32> {
    let mut seq_args = vec!();
    let program = args[0].clone();
    let mut iter = args.into_iter().skip(1);
    loop {
        match iter.next() {
            Some(arg) => match &arg[..] {
                "--help" | "-h" => {
                    print_help(&program);
                    return Err(0);
                }
                "--version" | "-V" => {
                    print_version();
                    return Err(0);
                }
                "-s" | "--separator" => match iter.next() {
                    Some(sep) => options.separator = sep,
                    None => {
                        show_error!("expected a separator after {}", arg);
                        return Err(1);
                    }
                },
                "-t" | "--terminator" => match iter.next() {
                    Some(term) => options.terminator = Some(term),
                    None => {
                        show_error!("expected a terminator after '{}'", arg);
                        return Err(1);
                    }
                },
                "-w" | "--widths" => options.widths = true,
                "--" => {
                    seq_args.extend(iter);
                    break;
                },
                _ => {
                    if arg.len() > 1 && arg.chars().next().unwrap() == '-' {
                        let argptr: *const String = &arg;  // escape from the borrow checker
                        let mut chiter = unsafe { &(*argptr)[..] }.chars().skip(1);
                        let mut ch = ' ';
                        while match chiter.next() { Some(m) => { ch = m; true } None => false } {
                            match ch {
                                'h' => {
                                    print_help(&program);
                                    return Err(0);
                                }
                                'V' => {
                                    print_version();
                                    return Err(0);
                                }
                                's' => match iter.next() {
                                    Some(sep) => {
                                        options.separator = sep;
                                        let next = chiter.next();
                                        if next.is_some() {
                                            show_error!("unexpected character ('{}')", next.unwrap());
                                            return Err(1);
                                        }
                                    }
                                    None => {
                                        show_error!("expected a separator after {}", arg);
                                        return Err(1);
                                    }
                                },
                                't' => match iter.next() {
                                    Some(term) => {
                                        options.terminator = Some(term);
                                        let next = chiter.next();
                                        if next.is_some() {
                                            show_error!("unexpected character ('{}')", next.unwrap());
                                            return Err(1);
                                        }
                                    }
                                    None => {
                                        show_error!("expected a terminator after {}", arg);
                                        return Err(1);
                                    }
                                },
                                'w' => options.widths = true,
                                _ => { seq_args.push(arg); break }
                            }
                        }
                    } else {
                        seq_args.push(arg);
                    }
                }
            },
            None => break
        }
    }
    Ok(seq_args)
}

fn print_help(program: &String) {
    let opts = [
        getopts::optopt("s", "separator", "Separator character (defaults to \\n)", ""),
        getopts::optopt("t", "terminator", "Terminator character (defaults to separator)", ""),
        getopts::optflag("w", "widths", "Equalize widths of all numbers by padding with zeros"),
        getopts::optflag("h", "help", "print this help text and exit"),
        getopts::optflag("V", "version", "print version and exit"),
    ];
    println!("seq 1.0.0\n");
    println!("Usage:\n  {} [-w] [-s string] [-t string] [first [step]] last\n", *program);
    println!("{}", getopts::usage("Print sequences of numbers", &opts));
}

fn print_version() {
    println!("seq 1.0.0\n");
}

pub fn uumain(args: Vec<String>) -> i32 {
    let program = args[0].clone();
    let mut options = SeqOptions {
        separator: "\n".to_string(),
        terminator: None,
        widths: false
    };
    let free = match parse_options(args, &mut options) {
        Ok(m) => m,
        Err(f) => return f
    };
    if free.len() < 1 || free.len() > 3 {
        crash!(1, "too {} operands.\nTry '{} --help' for more information.",
               if free.len() < 1 { "few" } else { "many" }, program);
    }
    let mut largest_dec = 0;
    let mut padding = 0;
    let first = if free.len() > 1 {
        let slice = &free[0][..];
        let len = slice.len();
        let dec = slice.find('.').unwrap_or(len);
        largest_dec = len - dec;
        padding = dec;
        match parse_float(slice) {
            Ok(n) => n,
            Err(s) => { show_error!("{}", s); return 1; }
        }
    } else {
        1.0
    };
    let step = if free.len() > 2 {
        let slice = &free[1][..];
        let len = slice.len();
        let dec = slice.find('.').unwrap_or(len);
        largest_dec = cmp::max(largest_dec, len - dec);
        padding = cmp::max(padding, dec);
        match parse_float(slice) {
            Ok(n) => n,
            Err(s) => { show_error!("{}", s); return 1; }
        }
    } else {
        1.0
    };
    let last = {
        let slice = &free[free.len() - 1][..];
        padding = cmp::max(padding, slice.find('.').unwrap_or(slice.len()));
        match parse_float(slice) {
            Ok(n) => n,
            Err(s) => { show_error!("{}", s); return 1; }
        }
    };
    let separator = escape_sequences(&options.separator[..]);
    let terminator = match options.terminator {
        Some(term) => escape_sequences(&term[..]),
        None => separator.clone()
    };
    print_seq(first, step, last, largest_dec, separator, terminator, options.widths, padding);

    0
}

#[inline(always)]
fn done_printing(next: f64, step: f64, last: f64) -> bool {
    if step >= 0f64 {
        next > last
    } else {
        next < last
    }
}

fn print_seq(first: f64, step: f64, last: f64, largest_dec: usize, separator: String, terminator: String, pad: bool, padding: usize) {
    let mut i = 0isize;
    let mut value = first + i as f64 * step;
    while !done_printing(value, step, last) {
        let istr = value.to_string();
        let ilen = istr.len();
        let before_dec = istr.find('.').unwrap_or(ilen);
        if pad && before_dec < padding {
            for _ in 0..(padding - before_dec) {
                if !pipe_print!("0") {
                    return;
                }
            }
        }
        pipe_print!("{}", istr);
        let mut idec = ilen - before_dec;
        if idec < largest_dec {
            if idec == 0 {
                if !pipe_print!(".") {
                    return;
                }
                idec += 1;
            }
            for _ in idec..largest_dec {
                if !pipe_print!("0") {
                    return;
                }
            }
        }
        i += 1;
        value = first + i as f64 * step;
        if !done_printing(value, step, last) {
            if !pipe_print!("{}", separator) {
                return;
            }
        }
    }
    if (first >= last && step < 0f64) || (first <= last && step > 0f64) {
        pipe_print!("{}", terminator);
    }
}
<|endoftext|>


<commit_before>use std::sync::mpsc;
use std::net::{ToSocketAddrs, UdpSocket, SocketAddr};

use std::thread;
use network::{OneshotTask, TaskSender};
use node::{UdpTransport, Transport};
use stun;

pub struct UdpServer {
    host: SocketAddr
}

impl UdpServer {
    pub fn new(host: SocketAddr) -> UdpServer {
        UdpServer {
            host: host
        }
    }

    // TODO: I'd rather have some kind of select on two channels instead of this nested non-blocking
    // recv. It only works because of the 10ms timeout on the socket.
    fn run(&self, sender: TaskSender) -> mpsc::Sender<mpsc::Sender<()>> {
        use std::time::Duration;

        let (shutdown_sender, shutdown_receiver) = mpsc::channel::<mpsc::Sender<()>>();

        let host = self.host;

        thread::spawn(move || {
            let socket = UdpSocket::bind(host).unwrap();
            socket.set_read_timeout(Some(Duration::from_millis(10))).unwrap();

            loop {
                match shutdown_receiver.try_recv() {
                    Err(mpsc::TryRecvError::Empty) => {
                        let mut buf = [0; 4096];
                        match socket.recv(&mut buf) {
                            Ok(size) => {
                                sender.send(OneshotTask::Incoming(buf[..size].iter().cloned().collect()))
                                    .unwrap_or_else(|err| info!("Couldn't handling incoming: {:?}", err));
                            }
                            Err(_) => {
                                //warn!("Error receiving from server: {}", e)
                            }
                        }
                    }

                    Err(mpsc::TryRecvError::Disconnected) => {
                        // The other end of the shutdown_receiver was dropped
                        break
                    }

                    Ok(sentinel) => {
                        sentinel.send(()).unwrap();
                        break;
                    }
                }
            }
        });

        shutdown_sender
    }

    fn transport(&self) -> Transport {
        let mapped_host = stun::get_mapped_address(self.host).expect("Couldn't STUN myself");
        Transport::Udp(UdpTransport::new(mapped_host))
    }
}

pub enum Server {
    Udp(UdpServer)
}

impl Server {
    pub fn create(url: &str) -> Option<Server> {
        if let Ok(mut socket_addrs) = url.to_socket_addrs() {
            if let Some(socket_addr) = socket_addrs.next() {
                return Some(Server::Udp(UdpServer::new(socket_addr)))
            }
        }
        None
    }

    pub fn transport(&self) -> Transport {
        match self {
            Server::Udp(server) => server.transport()
        }
    }

    pub fn run(&self, sender: TaskSender) -> mpsc::Sender<mpsc::Sender<()>> {
        match self {
            Server::Udp(server) => server.run(sender)
        }
    }
}

mod tests {
    use super::Server;

    #[test]
    fn it_creates_udp_servers() {
        let server = Server::create("0.0.0.0:6667");
        match server {
            Some(Server::Udp(_)) => assert!(true),
            _ => assert!(false)
        }
    }
}
<commit_msg>Add protocol type to server specifications<commit_after>use std::sync::mpsc;
use std::net::{ToSocketAddrs, UdpSocket, SocketAddr};

use std::thread;
use network::{OneshotTask, TaskSender};
use node::{UdpTransport, Transport};
use stun;

pub struct UdpServer {
    host: SocketAddr
}

impl UdpServer {
    pub fn new(host: SocketAddr) -> UdpServer {
        UdpServer {
            host: host
        }
    }

    // TODO: I'd rather have some kind of select on two channels instead of this nested non-blocking
    // recv. It only works because of the 10ms timeout on the socket.
    fn run(&self, sender: TaskSender) -> mpsc::Sender<mpsc::Sender<()>> {
        use std::time::Duration;

        let (shutdown_sender, shutdown_receiver) = mpsc::channel::<mpsc::Sender<()>>();

        let host = self.host;

        thread::spawn(move || {
            let socket = UdpSocket::bind(host).unwrap();
            socket.set_read_timeout(Some(Duration::from_millis(10))).unwrap();

            loop {
                match shutdown_receiver.try_recv() {
                    Err(mpsc::TryRecvError::Empty) => {
                        let mut buf = [0; 4096];
                        match socket.recv(&mut buf) {
                            Ok(size) => {
                                sender.send(OneshotTask::Incoming(buf[..size].iter().cloned().collect()))
                                    .unwrap_or_else(|err| info!("Couldn't handling incoming: {:?}", err));
                            }
                            Err(_) => {
                                //warn!("Error receiving from server: {}", e)
                            }
                        }
                    }

                    Err(mpsc::TryRecvError::Disconnected) => {
                        // The other end of the shutdown_receiver was dropped
                        break
                    }

                    Ok(sentinel) => {
                        sentinel.send(()).unwrap();
                        break;
                    }
                }
            }
        });

        shutdown_sender
    }

    fn transport(&self) -> Transport {
        let mapped_host = stun::get_mapped_address(self.host).expect("Couldn't STUN myself");
        Transport::Udp(UdpTransport::new(mapped_host))
    }
}

pub enum Server {
    Udp(UdpServer)
}

impl Server {
    pub fn create(url: &str) -> Option<Server> {
        let parts: Vec<&str> = url.splitn(2, "://").collect();
        let protocol = parts[0];
        let host = parts[1];
        match protocol {
            "udp" => {
                if let Ok(mut socket_addrs) = host.to_socket_addrs() {
                    if let Some(socket_addr) = socket_addrs.next() {
                        return Some(Server::Udp(UdpServer::new(socket_addr)))
                    }
                }
                None
            }
            _ => None
        }
    }

    pub fn transport(&self) -> Transport {
        match self {
            Server::Udp(server) => server.transport()
        }
    }

    pub fn run(&self, sender: TaskSender) -> mpsc::Sender<mpsc::Sender<()>> {
        match self {
            Server::Udp(server) => server.run(sender)
        }
    }
}

mod tests {
    use super::Server;

    #[test]
    fn it_creates_udp_servers() {
        let server = Server::create("udp://0.0.0.0:6667");
        match server {
            Some(Server::Udp(_)) => assert!(true),
            _ => assert!(false)
        }
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::{self, Debug};
use std::io;
use std::net::SocketAddr;
use std::rc::Rc;
use std::time::{Duration, Instant};

use futures::{Async, Future, Poll, Stream};
use mio::{Ready, SetReadiness};
use tokio_core::reactor::{Handle, Timeout};

use skcp::SharedKcp;

pub struct KcpSessionUpdaterInner {
    sessions: HashMap<u32, KcpServerSession>,
    alloc_conv: u32,
    update_interval: Duration,
    is_stop: bool,
    timeout: Timeout,
}

impl Debug for KcpSessionUpdaterInner {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "sessions: {:?}, alloc_conv: {}, update_interval: {:?}",
               self.sessions,
               self.alloc_conv,
               self.update_interval)
    }
}

#[derive(Clone)]
pub struct KcpSessionUpdater {
    inner: Rc<RefCell<KcpSessionUpdaterInner>>,
}

impl Debug for KcpSessionUpdater {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let inner = self.inner.borrow();
        write!(f, "KcpSessionUpdater {{ {:?} }}", &*inner)
    }
}

impl KcpSessionUpdater {
    pub fn new(update_intv: Duration, handle: &Handle) -> io::Result<KcpSessionUpdater> {
        let timeout = Timeout::new(Duration::from_secs(0), handle)?;

        Ok(KcpSessionUpdater {
               inner: Rc::new(RefCell::new(KcpSessionUpdaterInner {
                                               sessions: HashMap::new(),
                                               alloc_conv: 1,
                                               update_interval: update_intv,
                                               is_stop: false,
                                               timeout: timeout,
                                           })),
           })
    }

    pub fn input_by_conv(&mut self, conv: u32, buf: &mut [u8]) -> io::Result<bool> {
        let mut inner = self.inner.borrow_mut();

        match inner.sessions.get_mut(&conv) {
            None => Ok(false),
            Some(session) => {
                session.input(buf)?;
                Ok(true)
            }
        }
    }

    pub fn remove_by_conv(&mut self, conv: u32) {
        let mut inner = self.inner.borrow_mut();
        inner.sessions.remove(&conv);
    }

    pub fn insert_by_conv(&mut self, conv: u32, s: KcpServerSession) {
        let mut inner = self.inner.borrow_mut();
        inner.sessions.insert(conv, s);
    }

    /// Get one unused `conv`
    pub fn get_free_conv(&mut self) -> u32 {
        let mut inner = self.inner.borrow_mut();

        let mut conv = inner.alloc_conv;
        while inner.sessions.contains_key(&conv) {
            let (c, _) = inner.alloc_conv.overflowing_add(1);
            inner.alloc_conv = c;
            if inner.alloc_conv == 0 {
                inner.alloc_conv = 1;
            }

            conv = inner.alloc_conv;
        }

        conv
    }

    /// Stop updater
    pub fn stop(&mut self) {
        let mut inner = self.inner.borrow_mut();
        inner.is_stop = true;
    }
}

impl Stream for KcpSessionUpdater {
    type Item = ();
    type Error = io::Error;
    fn poll(&mut self) -> Poll<Option<()>, io::Error> {
        let mut inner = self.inner.borrow_mut();
        try_ready!(inner.timeout.poll());

        let mut finished = Vec::new();
        for (conv, ses) in &mut inner.sessions {
            match ses.poll() {
                Ok(Async::NotReady) => {}
                Ok(Async::Ready(Some(()))) => {}
                Ok(Async::Ready(None)) => {
                    finished.push(*conv);
                }
                Err(err) => {
                    error!("[SESS] Update conv={} err: {:?}", conv, err);
                    finished.push(*conv);
                }
            }
        }

        for conv in finished {
            inner.sessions.remove(&conv);
        }

        let next = Instant::now() + inner.update_interval;
        inner.timeout.reset(next);

        Ok(Async::Ready(Some(())))
    }
}

/// Shared session for controlling from other objects
pub type SharedKcpSession = Rc<RefCell<KcpSession>>;

/// KCP session mode
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum KcpSessionMode {
    Client,
    Server,
}

/// Session of a KCP conversation
pub struct KcpSession {
    kcp: SharedKcp,
    timer: Option<Timeout>,
    addr: SocketAddr,
    expire_dur: Duration,
    mode: KcpSessionMode,
}

impl KcpSession {
    pub fn new(kcp: SharedKcp,
               addr: SocketAddr,
               expire_dur: Duration,
               handle: &Handle,
               mode: KcpSessionMode)
               -> io::Result<KcpSession> {
        let n = KcpSession {
            kcp: kcp,
            timer: match mode {
                KcpSessionMode::Client => Some(Timeout::new(Duration::from_secs(0), handle)?),
                KcpSessionMode::Server => None,
            },
            addr: addr,
            expire_dur: expire_dur,
            mode: mode,
        };
        Ok(n)
    }

    pub fn new_shared(kcp: SharedKcp,
                      addr: SocketAddr,
                      expire_dur: Duration,
                      handle: &Handle,
                      mode: KcpSessionMode)
                      -> io::Result<SharedKcpSession> {
        let sess = KcpSession::new(kcp, addr, expire_dur, handle, mode)?;
        Ok(Rc::new(RefCell::new(sess)))
    }

    /// Get peer addr
    pub fn addr(&self) -> &SocketAddr {
        &self.addr
    }

    /// Called when you received a packet
    pub fn input(&mut self, buf: &[u8]) -> io::Result<()> {
        trace!("[SESS] input size={} addr={} {:?}", buf.len(), self.addr, ::debug::BsDebug(buf));
        self.kcp.input(buf)?;
        Ok(())
    }

    /// Check if session pending too long
    pub fn is_expired(&self) -> bool {
        self.kcp.elapsed() > self.expire_dur
    }

    /// Called every tick
    pub fn update(&mut self) -> io::Result<()> {
        let next = self.kcp.update()?;

        if let Some(ref mut timer) = self.timer {
            timer.reset(next);
        }

        Ok(())
    }

    /// Called if it is expired
    pub fn expire(&mut self) -> io::Result<()> {
        self.kcp.set_expired()?;
        trace!("[SESS] addr={} is expired", self.addr);
        Ok(())
    }

    /// Check if session is closed
    pub fn is_closed(&self) -> bool {
        self.kcp.is_closed()
    }

    /// Check if it is ready to close
    pub fn can_close(&self) -> bool {
        !self.kcp.has_waitsnd() // Does not have anything to be sent
            && self.kcp.elapsed() > Duration::from_secs(10) // Wait for 10s
    }

    /// Pull like a stream
    pub fn poll(&mut self) -> Poll<Option<()>, io::Error> {
        if let Some(ref mut timer) = self.timer {
            try_ready!(timer.poll());
        }

        // Session is already expired, drop this session
        if self.is_expired() {
            self.expire()?;
            return Ok(Async::Ready(None));
        }

        // Update it
        self.update()?;
        self.kcp.try_notify_writable();

        // Check if it is closed
        if self.is_closed() {
            if self.mode == KcpSessionMode::Client {
                // Take over the UDP's control
                // Because in client mode, when the Stream is closed, session is the only one to be responsible
                // for receving data from udp and input to kcp.
                let _ = self.kcp.fetch();
            }

            // if self.can_close() {
            //     trace!("[SESS] addr={} conv={} closing", self.addr, self.kcp.conv());
            //     return Ok(Async::Ready(None));
            // }
        }

        Ok(Async::Ready(Some(())))
    }

    /// Check if it is readable
    pub fn can_read(&self) -> bool {
        self.kcp.can_read()
    }
}

/// Server accepted session
///
/// This session is updated by the accept function. So it requires to notify readable events when it has
/// data to read.
#[derive(Clone)]
pub struct KcpServerSession {
    session: SharedKcpSession,
    readiness: SetReadiness,
}

impl KcpServerSession {
    pub fn new(sess: SharedKcpSession, r: SetReadiness) -> KcpServerSession {
        let sess = KcpServerSession {
            session: sess,
            readiness: r,
        };

        sess
    }

    /// Calls when you got data from transmission
    pub fn input(&mut self, buf: &[u8]) -> io::Result<()> {
        let mut sess = self.session.borrow_mut();
        sess.input(buf)?;

        // Now we have put data into KCP
        // So it is time to try `recv`. But it may failed, because the inputted data may be an ACK packet.
        if sess.can_read() {
            self.readiness.set_readiness(Ready::readable())
        } else {
            Ok(())
        }
    }
}

impl Stream for KcpServerSession {
    type Item = ();
    type Error = io::Error;
    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        let mut sess = self.session.borrow_mut();
        match sess.poll() {
            Err(err) => {
                // Session is closed
                trace!("[SESS] Close and remove addr={} conv={}, err: {}", sess.addr, sess.kcp.conv(), err);

                // Awake pending reads
                self.readiness.set_readiness(Ready::readable())?;
                Err(err)
            }
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Ok(Async::Ready(Some(x))) => Ok(Async::Ready(Some(x))),
            Ok(Async::Ready(None)) => {
                // Session is closed
                trace!("[SESS] Close and remove addr={} conv={}", sess.addr, sess.kcp.conv());

                // Awake pending reads
                self.readiness.set_readiness(Ready::readable())?;
                Ok(Async::Ready(None))
            }
        }
    }
}

impl Debug for KcpServerSession {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let sess = self.session.borrow();
        write!(f, "KcpServerSession({})", sess.addr())
    }
}

/// Client session
///
/// This session is not requires to notify any events, because all of them is done on the caller side.
#[derive(Clone)]
pub struct KcpClientSession {
    session: SharedKcpSession,
}

impl KcpClientSession {
    pub fn new(sess: SharedKcpSession) -> KcpClientSession {
        KcpClientSession { session: sess }
    }
}

impl Stream for KcpClientSession {
    type Item = ();
    type Error = io::Error;
    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        let mut sess = self.session.borrow_mut();
        sess.poll()
    }
}
<commit_msg>Prints session conv while it is expired<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::{self, Debug};
use std::io;
use std::net::SocketAddr;
use std::rc::Rc;
use std::time::{Duration, Instant};

use futures::{Async, Future, Poll, Stream};
use mio::{Ready, SetReadiness};
use tokio_core::reactor::{Handle, Timeout};

use skcp::SharedKcp;

pub struct KcpSessionUpdaterInner {
    sessions: HashMap<u32, KcpServerSession>,
    alloc_conv: u32,
    update_interval: Duration,
    is_stop: bool,
    timeout: Timeout,
}

impl Debug for KcpSessionUpdaterInner {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "sessions: {:?}, alloc_conv: {}, update_interval: {:?}",
               self.sessions,
               self.alloc_conv,
               self.update_interval)
    }
}

#[derive(Clone)]
pub struct KcpSessionUpdater {
    inner: Rc<RefCell<KcpSessionUpdaterInner>>,
}

impl Debug for KcpSessionUpdater {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let inner = self.inner.borrow();
        write!(f, "KcpSessionUpdater {{ {:?} }}", &*inner)
    }
}

impl KcpSessionUpdater {
    pub fn new(update_intv: Duration, handle: &Handle) -> io::Result<KcpSessionUpdater> {
        let timeout = Timeout::new(Duration::from_secs(0), handle)?;

        Ok(KcpSessionUpdater {
               inner: Rc::new(RefCell::new(KcpSessionUpdaterInner {
                                               sessions: HashMap::new(),
                                               alloc_conv: 1,
                                               update_interval: update_intv,
                                               is_stop: false,
                                               timeout: timeout,
                                           })),
           })
    }

    pub fn input_by_conv(&mut self, conv: u32, buf: &mut [u8]) -> io::Result<bool> {
        let mut inner = self.inner.borrow_mut();

        match inner.sessions.get_mut(&conv) {
            None => Ok(false),
            Some(session) => {
                session.input(buf)?;
                Ok(true)
            }
        }
    }

    pub fn remove_by_conv(&mut self, conv: u32) {
        let mut inner = self.inner.borrow_mut();
        inner.sessions.remove(&conv);
    }

    pub fn insert_by_conv(&mut self, conv: u32, s: KcpServerSession) {
        let mut inner = self.inner.borrow_mut();
        inner.sessions.insert(conv, s);
    }

    /// Get one unused `conv`
    pub fn get_free_conv(&mut self) -> u32 {
        let mut inner = self.inner.borrow_mut();

        let mut conv = inner.alloc_conv;
        while inner.sessions.contains_key(&conv) {
            let (c, _) = inner.alloc_conv.overflowing_add(1);
            inner.alloc_conv = c;
            if inner.alloc_conv == 0 {
                inner.alloc_conv = 1;
            }

            conv = inner.alloc_conv;
        }

        conv
    }

    /// Stop updater
    pub fn stop(&mut self) {
        let mut inner = self.inner.borrow_mut();
        inner.is_stop = true;
    }
}

impl Stream for KcpSessionUpdater {
    type Item = ();
    type Error = io::Error;
    fn poll(&mut self) -> Poll<Option<()>, io::Error> {
        let mut inner = self.inner.borrow_mut();
        try_ready!(inner.timeout.poll());

        let mut finished = Vec::new();
        for (conv, ses) in &mut inner.sessions {
            match ses.poll() {
                Ok(Async::NotReady) => {}
                Ok(Async::Ready(Some(()))) => {}
                Ok(Async::Ready(None)) => {
                    finished.push(*conv);
                }
                Err(err) => {
                    error!("[SESS] Update conv={} err: {:?}", conv, err);
                    finished.push(*conv);
                }
            }
        }

        for conv in finished {
            inner.sessions.remove(&conv);
        }

        let next = Instant::now() + inner.update_interval;
        inner.timeout.reset(next);

        Ok(Async::Ready(Some(())))
    }
}

/// Shared session for controlling from other objects
pub type SharedKcpSession = Rc<RefCell<KcpSession>>;

/// KCP session mode
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum KcpSessionMode {
    Client,
    Server,
}

/// Session of a KCP conversation
pub struct KcpSession {
    kcp: SharedKcp,
    timer: Option<Timeout>,
    addr: SocketAddr,
    expire_dur: Duration,
    mode: KcpSessionMode,
}

impl KcpSession {
    pub fn new(kcp: SharedKcp,
               addr: SocketAddr,
               expire_dur: Duration,
               handle: &Handle,
               mode: KcpSessionMode)
               -> io::Result<KcpSession> {
        let n = KcpSession {
            kcp: kcp,
            timer: match mode {
                KcpSessionMode::Client => Some(Timeout::new(Duration::from_secs(0), handle)?),
                KcpSessionMode::Server => None,
            },
            addr: addr,
            expire_dur: expire_dur,
            mode: mode,
        };
        Ok(n)
    }

    pub fn new_shared(kcp: SharedKcp,
                      addr: SocketAddr,
                      expire_dur: Duration,
                      handle: &Handle,
                      mode: KcpSessionMode)
                      -> io::Result<SharedKcpSession> {
        let sess = KcpSession::new(kcp, addr, expire_dur, handle, mode)?;
        Ok(Rc::new(RefCell::new(sess)))
    }

    /// Get peer addr
    pub fn addr(&self) -> &SocketAddr {
        &self.addr
    }

    /// Called when you received a packet
    pub fn input(&mut self, buf: &[u8]) -> io::Result<()> {
        trace!("[SESS] input size={} addr={} {:?}", buf.len(), self.addr, ::debug::BsDebug(buf));
        self.kcp.input(buf)?;
        Ok(())
    }

    /// Check if session pending too long
    pub fn is_expired(&self) -> bool {
        self.kcp.elapsed() > self.expire_dur
    }

    /// Called every tick
    pub fn update(&mut self) -> io::Result<()> {
        let next = self.kcp.update()?;

        if let Some(ref mut timer) = self.timer {
            timer.reset(next);
        }

        Ok(())
    }

    /// Called if it is expired
    pub fn expire(&mut self) -> io::Result<()> {
        self.kcp.set_expired()?;
        trace!("[SESS] addr={} conv={} is expired", self.addr, self.kcp.conv());
        Ok(())
    }

    /// Check if session is closed
    pub fn is_closed(&self) -> bool {
        self.kcp.is_closed()
    }

    /// Check if it is ready to close
    pub fn can_close(&self) -> bool {
        !self.kcp.has_waitsnd() // Does not have anything to be sent
            && self.kcp.elapsed() > Duration::from_secs(10) // Wait for 10s
    }

    /// Pull like a stream
    pub fn poll(&mut self) -> Poll<Option<()>, io::Error> {
        if let Some(ref mut timer) = self.timer {
            try_ready!(timer.poll());
        }

        // Session is already expired, drop this session
        if self.is_expired() {
            self.expire()?;
            return Ok(Async::Ready(None));
        }

        // Update it
        self.update()?;
        self.kcp.try_notify_writable();

        // Check if it is closed
        if self.is_closed() {
            if self.mode == KcpSessionMode::Client {
                // Take over the UDP's control
                // Because in client mode, when the Stream is closed, session is the only one to be responsible
                // for receving data from udp and input to kcp.
                let _ = self.kcp.fetch();
            }

            // if self.can_close() {
            //     trace!("[SESS] addr={} conv={} closing", self.addr, self.kcp.conv());
            //     return Ok(Async::Ready(None));
            // }
        }

        Ok(Async::Ready(Some(())))
    }

    /// Check if it is readable
    pub fn can_read(&self) -> bool {
        self.kcp.can_read()
    }
}

/// Server accepted session
///
/// This session is updated by the accept function. So it requires to notify readable events when it has
/// data to read.
#[derive(Clone)]
pub struct KcpServerSession {
    session: SharedKcpSession,
    readiness: SetReadiness,
}

impl KcpServerSession {
    pub fn new(sess: SharedKcpSession, r: SetReadiness) -> KcpServerSession {
        let sess = KcpServerSession {
            session: sess,
            readiness: r,
        };

        sess
    }

    /// Calls when you got data from transmission
    pub fn input(&mut self, buf: &[u8]) -> io::Result<()> {
        let mut sess = self.session.borrow_mut();
        sess.input(buf)?;

        // Now we have put data into KCP
        // So it is time to try `recv`. But it may failed, because the inputted data may be an ACK packet.
        if sess.can_read() {
            self.readiness.set_readiness(Ready::readable())
        } else {
            Ok(())
        }
    }
}

impl Stream for KcpServerSession {
    type Item = ();
    type Error = io::Error;
    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        let mut sess = self.session.borrow_mut();
        match sess.poll() {
            Err(err) => {
                // Session is closed
                trace!("[SESS] Close and remove addr={} conv={}, err: {}", sess.addr, sess.kcp.conv(), err);

                // Awake pending reads
                self.readiness.set_readiness(Ready::readable())?;
                Err(err)
            }
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Ok(Async::Ready(Some(x))) => Ok(Async::Ready(Some(x))),
            Ok(Async::Ready(None)) => {
                // Session is closed
                trace!("[SESS] Close and remove addr={} conv={}", sess.addr, sess.kcp.conv());

                // Awake pending reads
                self.readiness.set_readiness(Ready::readable())?;
                Ok(Async::Ready(None))
            }
        }
    }
}

impl Debug for KcpServerSession {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let sess = self.session.borrow();
        write!(f, "KcpServerSession({})", sess.addr())
    }
}

/// Client session
///
/// This session is not requires to notify any events, because all of them is done on the caller side.
#[derive(Clone)]
pub struct KcpClientSession {
    session: SharedKcpSession,
}

impl KcpClientSession {
    pub fn new(sess: SharedKcpSession) -> KcpClientSession {
        KcpClientSession { session: sess }
    }
}

impl Stream for KcpClientSession {
    type Item = ();
    type Error = io::Error;
    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        let mut sess = self.session.borrow_mut();
        sess.poll()
    }
}
<|endoftext|>


<commit_before>//! SHM handling helpers
//!
//! This module provides helpers to handle SHM-based buffers from wayland clients.
//!
//! To use it, first add a `ShmGlobal` to your event loop, specifying the formats
//! you want to support (ARGB8888 and XRGB8888 are always considered as supported,
//! as specified by the wayland protocol) and obtain its `ShmGlobalToken`.
//!
//! ```ignore
//! let handler_id = event_loop.add_handler(ShmGlobal::new());
//! let shm_global = event_loop.register_global::<wl_shm::WlShm,ShmGlobal>(handler_id, 3);
//! let shm_token = {
//!     let state = event_loop.state();
//!     state.get_handler::<ShmGlobal>(handler_id).get_token()
//! };
//! ```
//!
//! Then, when you have a `WlBuffer` and need to retrieve its contents, use the token method to
//! do it:
//!
//! ```ignore
//! shm_token.with_buffer_contents(&buffer,
//!     |slice: &[u8], buffer_metadata: &BufferData| {
//!         // do something to draw it on the screen
//!     }
//! );
//! ```

use std::os::unix::io::RawFd;
use std::sync::Arc;

use wayland_server::{GlobalHandler, EventLoopHandle, Client, Init, Resource, Destroy, resource_is_registered};
use wayland_server::protocol::{wl_shm, wl_shm_pool, wl_buffer};

use self::pool::{Pool, ResizeError};

mod pool;

/// A global for handling SHM pool and buffers
///
/// You must register it to an event loop using `register_with_init`, or it will
/// quickly panic.
pub struct ShmGlobal {
    formats: Vec<wl_shm::Format>,
    handler_id: Option<usize>
}

impl ShmGlobal {
    /// Create a new SHM global advertizing given supported formats.
    ///
    /// This global will always advertize `ARGB8888` and `XRGB8888` format
    /// as they are required by the protocol. Formats given as argument
    /// as additionnaly advertized.
    pub fn new(mut formats: Vec<wl_shm::Format>) -> ShmGlobal {
        // always add the mandatory formats
        formats.push(wl_shm::Format::Argb8888);
        formats.push(wl_shm::Format::Xrgb8888);
        ShmGlobal {
            formats: formats,
            handler_id: None
        }
    }

    /// Retreive a token from the SHM global.
    ///
    /// This can only be called once the `ShmGlobal` has been added to and event loop
    /// and has been initialized. If it is not the case, this method will panic.
    ///
    /// This is needed to retrieve the contents of the shm pools and buffers.
    pub fn get_token(&self) -> ShmGlobalToken {
        ShmGlobalToken {
            hid: self.handler_id.clone().expect("ShmGlobal was not initialized.")
        }
    }
}

/// An SHM global token
///
/// It is needed to access the contents of the buffers & pools managed by the
/// associated ShmGlobal.
pub struct ShmGlobalToken {
    hid: usize
}

/// Error that can occur when accessing an SHM buffer
pub enum BufferAccessError {
    /// This buffer is not managed by the SHM handler
    NotManaged,
    /// An error occured while accessing the memory map
    ///
    /// This can happen if the client advertized a wrong size
    /// for the memory map.
    ///
    /// If this error occurs, the client has been killed as a result.
    BadMap
}

impl ShmGlobalToken {
    /// Call given closure with the contents of the given buffer
    ///
    /// If the buffer is managed by the associated ShmGlobal, its contents are
    /// extracted and the closure is extracted with them:
    ///
    /// - The first argument is a data slice of the contents of the pool
    /// - The second argument is the specification of this buffer is this pool
    ///
    /// If the buffer is not managed by the associated ShmGlobal, the closure is not called
    /// and this method will return `Err(())` (this will be the case for an EGL buffer for example).
    pub fn with_buffer_contents<F>(&self, buffer: &wl_buffer::WlBuffer, f: F) -> Result<(), BufferAccessError>
        where F: FnOnce(&[u8], BufferData)
    {
        if !resource_is_registered::<_, ShmHandler>(buffer, self.hid) {
            return Err(BufferAccessError::NotManaged)
        }
        let data = unsafe { &* (buffer.get_user_data() as *mut InternalBufferData) };

        if data.pool.with_data_slice(|slice| f(slice, data.data.clone())).is_err() {
            // SIGBUS error occured
            return Err(BufferAccessError::BadMap)
        }
        Ok(())
    }
}

impl Init for ShmGlobal {
    fn init(&mut self, evqh: &mut EventLoopHandle, _index: usize) {
        let id = evqh.add_handler_with_init(ShmHandler {
            my_id: ::std::usize::MAX,
            valid_formats: self.formats.clone()
        });
        self.handler_id = Some(id);
    }
}

impl GlobalHandler<wl_shm::WlShm> for ShmGlobal {
    fn bind(&mut self, evqh: &mut EventLoopHandle, _: &Client, global: wl_shm::WlShm) {
        let hid = self.handler_id.clone().expect("ShmGlobal was not initialized.");
        // register an handler for this shm
        evqh.register::<_, ShmHandler>(&global, hid);
        // and then the custom formats
        for f in &self.formats {
            global.format(*f);
        }
    }
}

struct ShmHandler {
    my_id: usize,
    valid_formats: Vec<wl_shm::Format>
}

impl Init for ShmHandler {
    fn init(&mut self, _evqh: &mut EventLoopHandle, index: usize) {
        self.my_id = index;
    }
}

impl wl_shm::Handler for ShmHandler {
    fn create_pool(&mut self, evqh: &mut EventLoopHandle, _client: &Client, shm: &wl_shm::WlShm,
                   pool: wl_shm_pool::WlShmPool, fd: RawFd, size: i32) {
        if size <= 0 {
            shm.post_error(wl_shm::Error::InvalidFd as u32, "Invalid size for a new wl_shm_pool.".into());
            return
        }
        let mmap_pool = match Pool::new(fd, size as usize) {
            Ok(p) => p,
            Err(()) => {
                shm.post_error(wl_shm::Error::InvalidFd as u32, format!("Failed mmap of fd {}.", fd));
                return
            }
        };
        let arc_pool = Box::new(Arc::new(mmap_pool));
        evqh.register_with_destructor::<_, ShmHandler, ShmHandler>(&pool, self.my_id);
        pool.set_user_data(Box::into_raw(arc_pool) as *mut ());
    }
}

impl Destroy<wl_shm_pool::WlShmPool> for ShmHandler {
    fn destroy(pool: &wl_shm_pool::WlShmPool) {
        let arc_pool = unsafe { Box::from_raw(pool.get_user_data() as *mut Arc<Pool>) };
        drop(arc_pool)
    }
}

declare_handler!(ShmHandler, wl_shm::Handler, wl_shm::WlShm);

/// Details of the contents of a buffer relative to its pool
#[derive(Copy,Clone,Debug)]
pub struct BufferData {
    /// Offset of the start of the buffer relative to the beginning of the pool in bytes
    pub offset: i32,
    /// Wwidth of the buffer in bytes
    pub width: i32,
    /// Height of the buffer in bytes
    pub height: i32,
    /// Stride of the buffer in bytes
    pub stride: i32,
    /// Format used by this buffer
    pub format: wl_shm::Format
}

struct InternalBufferData {
    pool: Arc<Pool>,
    data: BufferData
}

impl wl_shm_pool::Handler for ShmHandler {
    fn create_buffer(&mut self, evqh: &mut EventLoopHandle, _client: &Client,
                     pool: &wl_shm_pool::WlShmPool, buffer: wl_buffer::WlBuffer, offset: i32,
                     width: i32, height: i32, stride: i32, format: wl_shm::Format)
    {
        if !self.valid_formats.contains(&format) {
            buffer.post_error(wl_shm::Error::InvalidFormat as u32, String::new());
            return
        }
        let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
        let data = Box::into_raw(Box::new(InternalBufferData {
            pool: arc_pool.clone(),
            data: BufferData {
                offset: offset,
                width: width,
                height: height,
                stride: stride,
                format: format
            }
        }));
        evqh.register_with_destructor::<_, ShmHandler, ShmHandler>(&buffer, self.my_id);
        buffer.set_user_data(data as *mut ());
    }

    fn resize(&mut self, _evqh: &mut EventLoopHandle, _client: &Client,
              pool: &wl_shm_pool::WlShmPool, size: i32)
    {
        let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
        match arc_pool.resize(size) {
            Ok(()) => {},
            Err(ResizeError::InvalidSize) => {
                pool.post_error(wl_shm::Error::InvalidFd as u32, "Invalid new size for a wl_shm_pool.".into());
            },
            Err(ResizeError::MremapFailed) => {
                pool.post_error(wl_shm::Error::InvalidFd as u32, "mremap failed.".into());
            }
        }
    }
}

impl Destroy<wl_buffer::WlBuffer> for ShmHandler {
    fn destroy(buffer: &wl_buffer::WlBuffer) {
        let buffer_data = unsafe { Box::from_raw(buffer.get_user_data() as *mut InternalBufferData) };
        drop(buffer_data)
    }
}

declare_handler!(ShmHandler, wl_shm_pool::Handler, wl_shm_pool::WlShmPool);

impl wl_buffer::Handler for ShmHandler {
}

declare_handler!(ShmHandler, wl_buffer::Handler, wl_buffer::WlBuffer);
<commit_msg>shm: kill bad client & document SIGBUS<commit_after>//! SHM handling helpers
//!
//! This module provides helpers to handle SHM-based buffers from wayland clients.
//!
//! To use it, first add a `ShmGlobal` to your event loop, specifying the formats
//! you want to support (ARGB8888 and XRGB8888 are always considered as supported,
//! as specified by the wayland protocol) and obtain its `ShmGlobalToken`.
//!
//! ```ignore
//! let handler_id = event_loop.add_handler(ShmGlobal::new());
//! let shm_global = event_loop.register_global::<wl_shm::WlShm,ShmGlobal>(handler_id, 3);
//! let shm_token = {
//!     let state = event_loop.state();
//!     state.get_handler::<ShmGlobal>(handler_id).get_token()
//! };
//! ```
//!
//! Then, when you have a `WlBuffer` and need to retrieve its contents, use the token method to
//! do it:
//!
//! ```ignore
//! shm_token.with_buffer_contents(&buffer,
//!     |slice: &[u8], buffer_metadata: &BufferData| {
//!         // do something to draw it on the screen
//!     }
//! );
//! ```
//!
//! **Note**
//!
//! This handler makes itself safe regading the client providing a wring size for the memory pool
//! by using a SIGBUS handler.
//!
//! If you are already using an handler for this signal, you probably don't want to use this handler.

use std::os::unix::io::RawFd;
use std::sync::Arc;

use wayland_server::{GlobalHandler, EventLoopHandle, Client, Init, Resource, Destroy, resource_is_registered};
use wayland_server::protocol::{wl_shm, wl_shm_pool, wl_buffer};

use self::pool::{Pool, ResizeError};

mod pool;

/// A global for handling SHM pool and buffers
///
/// You must register it to an event loop using `register_with_init`, or it will
/// quickly panic.
pub struct ShmGlobal {
    formats: Vec<wl_shm::Format>,
    handler_id: Option<usize>
}

impl ShmGlobal {
    /// Create a new SHM global advertizing given supported formats.
    ///
    /// This global will always advertize `ARGB8888` and `XRGB8888` format
    /// as they are required by the protocol. Formats given as argument
    /// as additionnaly advertized.
    pub fn new(mut formats: Vec<wl_shm::Format>) -> ShmGlobal {
        // always add the mandatory formats
        formats.push(wl_shm::Format::Argb8888);
        formats.push(wl_shm::Format::Xrgb8888);
        ShmGlobal {
            formats: formats,
            handler_id: None
        }
    }

    /// Retreive a token from the SHM global.
    ///
    /// This can only be called once the `ShmGlobal` has been added to and event loop
    /// and has been initialized. If it is not the case, this method will panic.
    ///
    /// This is needed to retrieve the contents of the shm pools and buffers.
    pub fn get_token(&self) -> ShmGlobalToken {
        ShmGlobalToken {
            hid: self.handler_id.clone().expect("ShmGlobal was not initialized.")
        }
    }
}

/// An SHM global token
///
/// It is needed to access the contents of the buffers & pools managed by the
/// associated ShmGlobal.
pub struct ShmGlobalToken {
    hid: usize
}

/// Error that can occur when accessing an SHM buffer
pub enum BufferAccessError {
    /// This buffer is not managed by the SHM handler
    NotManaged,
    /// An error occured while accessing the memory map
    ///
    /// This can happen if the client advertized a wrong size
    /// for the memory map.
    ///
    /// If this error occurs, the client has been killed as a result.
    BadMap
}

impl ShmGlobalToken {
    /// Call given closure with the contents of the given buffer
    ///
    /// If the buffer is managed by the associated ShmGlobal, its contents are
    /// extracted and the closure is extracted with them:
    ///
    /// - The first argument is a data slice of the contents of the pool
    /// - The second argument is the specification of this buffer is this pool
    ///
    /// If the buffer is not managed by the associated ShmGlobal, the closure is not called
    /// and this method will return `Err(())` (this will be the case for an EGL buffer for example).
    pub fn with_buffer_contents<F>(&self, buffer: &wl_buffer::WlBuffer, f: F) -> Result<(), BufferAccessError>
        where F: FnOnce(&[u8], BufferData)
    {
        if !resource_is_registered::<_, ShmHandler>(buffer, self.hid) {
            return Err(BufferAccessError::NotManaged)
        }
        let data = unsafe { &* (buffer.get_user_data() as *mut InternalBufferData) };

        if data.pool.with_data_slice(|slice| f(slice, data.data.clone())).is_err() {
            // SIGBUS error occured
            buffer.post_error(wl_shm::Error::InvalidFd as u32, "Bad pool size.".into());
            return Err(BufferAccessError::BadMap)
        }
        Ok(())
    }
}

impl Init for ShmGlobal {
    fn init(&mut self, evqh: &mut EventLoopHandle, _index: usize) {
        let id = evqh.add_handler_with_init(ShmHandler {
            my_id: ::std::usize::MAX,
            valid_formats: self.formats.clone()
        });
        self.handler_id = Some(id);
    }
}

impl GlobalHandler<wl_shm::WlShm> for ShmGlobal {
    fn bind(&mut self, evqh: &mut EventLoopHandle, _: &Client, global: wl_shm::WlShm) {
        let hid = self.handler_id.clone().expect("ShmGlobal was not initialized.");
        // register an handler for this shm
        evqh.register::<_, ShmHandler>(&global, hid);
        // and then the custom formats
        for f in &self.formats {
            global.format(*f);
        }
    }
}

struct ShmHandler {
    my_id: usize,
    valid_formats: Vec<wl_shm::Format>
}

impl Init for ShmHandler {
    fn init(&mut self, _evqh: &mut EventLoopHandle, index: usize) {
        self.my_id = index;
    }
}

impl wl_shm::Handler for ShmHandler {
    fn create_pool(&mut self, evqh: &mut EventLoopHandle, _client: &Client, shm: &wl_shm::WlShm,
                   pool: wl_shm_pool::WlShmPool, fd: RawFd, size: i32) {
        if size <= 0 {
            shm.post_error(wl_shm::Error::InvalidFd as u32, "Invalid size for a new wl_shm_pool.".into());
            return
        }
        let mmap_pool = match Pool::new(fd, size as usize) {
            Ok(p) => p,
            Err(()) => {
                shm.post_error(wl_shm::Error::InvalidFd as u32, format!("Failed mmap of fd {}.", fd));
                return
            }
        };
        let arc_pool = Box::new(Arc::new(mmap_pool));
        evqh.register_with_destructor::<_, ShmHandler, ShmHandler>(&pool, self.my_id);
        pool.set_user_data(Box::into_raw(arc_pool) as *mut ());
    }
}

impl Destroy<wl_shm_pool::WlShmPool> for ShmHandler {
    fn destroy(pool: &wl_shm_pool::WlShmPool) {
        let arc_pool = unsafe { Box::from_raw(pool.get_user_data() as *mut Arc<Pool>) };
        drop(arc_pool)
    }
}

declare_handler!(ShmHandler, wl_shm::Handler, wl_shm::WlShm);

/// Details of the contents of a buffer relative to its pool
#[derive(Copy,Clone,Debug)]
pub struct BufferData {
    /// Offset of the start of the buffer relative to the beginning of the pool in bytes
    pub offset: i32,
    /// Wwidth of the buffer in bytes
    pub width: i32,
    /// Height of the buffer in bytes
    pub height: i32,
    /// Stride of the buffer in bytes
    pub stride: i32,
    /// Format used by this buffer
    pub format: wl_shm::Format
}

struct InternalBufferData {
    pool: Arc<Pool>,
    data: BufferData
}

impl wl_shm_pool::Handler for ShmHandler {
    fn create_buffer(&mut self, evqh: &mut EventLoopHandle, _client: &Client,
                     pool: &wl_shm_pool::WlShmPool, buffer: wl_buffer::WlBuffer, offset: i32,
                     width: i32, height: i32, stride: i32, format: wl_shm::Format)
    {
        if !self.valid_formats.contains(&format) {
            buffer.post_error(wl_shm::Error::InvalidFormat as u32, String::new());
            return
        }
        let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
        let data = Box::into_raw(Box::new(InternalBufferData {
            pool: arc_pool.clone(),
            data: BufferData {
                offset: offset,
                width: width,
                height: height,
                stride: stride,
                format: format
            }
        }));
        evqh.register_with_destructor::<_, ShmHandler, ShmHandler>(&buffer, self.my_id);
        buffer.set_user_data(data as *mut ());
    }

    fn resize(&mut self, _evqh: &mut EventLoopHandle, _client: &Client,
              pool: &wl_shm_pool::WlShmPool, size: i32)
    {
        let arc_pool = unsafe { &*(pool.get_user_data() as *mut Arc<Pool>) };
        match arc_pool.resize(size) {
            Ok(()) => {},
            Err(ResizeError::InvalidSize) => {
                pool.post_error(wl_shm::Error::InvalidFd as u32, "Invalid new size for a wl_shm_pool.".into());
            },
            Err(ResizeError::MremapFailed) => {
                pool.post_error(wl_shm::Error::InvalidFd as u32, "mremap failed.".into());
            }
        }
    }
}

impl Destroy<wl_buffer::WlBuffer> for ShmHandler {
    fn destroy(buffer: &wl_buffer::WlBuffer) {
        let buffer_data = unsafe { Box::from_raw(buffer.get_user_data() as *mut InternalBufferData) };
        drop(buffer_data)
    }
}

declare_handler!(ShmHandler, wl_shm_pool::Handler, wl_shm_pool::WlShmPool);

impl wl_buffer::Handler for ShmHandler {
}

declare_handler!(ShmHandler, wl_buffer::Handler, wl_buffer::WlBuffer);
<|endoftext|>


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

use core::nonzero::NonZero;
use dom::bindings::codegen::Bindings::ImageDataBinding;
use dom::bindings::codegen::Bindings::ImageDataBinding::ImageDataMethods;
use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::globalscope::GlobalScope;
use euclid::size::Size2D;
use js::jsapi::{Heap, JSContext, JSObject};
use js::jsapi::{JS_GetUint8ClampedArrayData, JS_NewUint8ClampedArray};
use libc::uint8_t;
use std::default::Default;
use std::ptr;
use std::slice;
use std::vec::Vec;

#[dom_struct]
pub struct ImageData {
    reflector_: Reflector,
    width: u32,
    height: u32,
    data: Heap<*mut JSObject>,
}

impl ImageData {
    #[allow(unsafe_code)]
    pub fn new(global: &GlobalScope, width: u32, height: u32, data: Option<Vec<u8>>) -> Root<ImageData> {
        let mut imagedata = box ImageData {
            reflector_: Reflector::new(),
            width: width,
            height: height,
            data: Heap::default(),
        };

        unsafe {
            let cx = global.get_cx();
            let js_object: *mut JSObject = JS_NewUint8ClampedArray(cx, width * height * 4);
            assert!(!js_object.is_null());

            if let Some(vec) = data {
                let mut is_shared = false;
                let js_object_data: *mut uint8_t = JS_GetUint8ClampedArrayData(js_object, &mut is_shared, ptr::null());
                assert!(!is_shared);
                ptr::copy_nonoverlapping(vec.as_ptr(), js_object_data, vec.len())
            }
            (*imagedata).data.set(js_object);
        }

        reflect_dom_object(imagedata,
                           global, ImageDataBinding::Wrap)
    }

    #[allow(unsafe_code)]
    pub fn get_data_array(&self) -> Vec<u8> {
        unsafe {
            let mut is_shared = false;
            assert!(!self.data.get().is_null());
            let data: *const uint8_t =
                JS_GetUint8ClampedArrayData(self.data.get(), &mut is_shared, ptr::null()) as *const uint8_t;
            assert!(!data.is_null());
            assert!(!is_shared);
            let len = self.Width() * self.Height() * 4;
            slice::from_raw_parts(data, len as usize).to_vec()
        }
    }

    pub fn get_size(&self) -> Size2D<i32> {
        Size2D::new(self.Width() as i32, self.Height() as i32)
    }
}

impl ImageDataMethods for ImageData {
    // https://html.spec.whatwg.org/multipage/#dom-imagedata-width
    fn Width(&self) -> u32 {
        self.width
    }

    // https://html.spec.whatwg.org/multipage/#dom-imagedata-height
    fn Height(&self) -> u32 {
        self.height
    }

    #[allow(unsafe_code)]
    // https://html.spec.whatwg.org/multipage/#dom-imagedata-data
    unsafe fn Data(&self, _: *mut JSContext) -> NonZero<*mut JSObject> {
        assert!(!self.data.get().is_null());
        NonZero::new(self.data.get())
    }
}
<commit_msg>Use the typed array APIs in ImageData.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use core::nonzero::NonZero;
use dom::bindings::codegen::Bindings::ImageDataBinding;
use dom::bindings::codegen::Bindings::ImageDataBinding::ImageDataMethods;
use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::globalscope::GlobalScope;
use euclid::size::Size2D;
use js::jsapi::{Heap, JSContext, JSObject};
use js::rust::Runtime;
use js::typedarray::Uint8ClampedArray;
use std::default::Default;
use std::ptr;
use std::vec::Vec;

#[dom_struct]
pub struct ImageData {
    reflector_: Reflector,
    width: u32,
    height: u32,
    data: Heap<*mut JSObject>,
}

impl ImageData {
    #[allow(unsafe_code)]
    pub fn new(global: &GlobalScope, width: u32, height: u32, data: Option<Vec<u8>>) -> Root<ImageData> {
        let mut imagedata = box ImageData {
            reflector_: Reflector::new(),
            width: width,
            height: height,
            data: Heap::default(),
        };

        unsafe {
            let cx = global.get_cx();
            rooted!(in (cx) let mut js_object = ptr::null_mut());
            let data = data.as_ref().map(|d| &d[..]);
            Uint8ClampedArray::create(cx, width * height * 4, data, js_object.handle_mut()).unwrap();
            (*imagedata).data.set(js_object.get());
        }

        reflect_dom_object(imagedata,
                           global, ImageDataBinding::Wrap)
    }

    #[allow(unsafe_code)]
    pub fn get_data_array(&self) -> Vec<u8> {
        unsafe {
            assert!(!self.data.get().is_null());
            let cx = Runtime::get();
            assert!(!cx.is_null());
            typedarray!(in(cx) let array: Uint8ClampedArray = self.data.get());
            let vec = array.unwrap().as_slice().to_vec();
            vec
        }
    }

    pub fn get_size(&self) -> Size2D<i32> {
        Size2D::new(self.Width() as i32, self.Height() as i32)
    }
}

impl ImageDataMethods for ImageData {
    // https://html.spec.whatwg.org/multipage/#dom-imagedata-width
    fn Width(&self) -> u32 {
        self.width
    }

    // https://html.spec.whatwg.org/multipage/#dom-imagedata-height
    fn Height(&self) -> u32 {
        self.height
    }

    #[allow(unsafe_code)]
    // https://html.spec.whatwg.org/multipage/#dom-imagedata-data
    unsafe fn Data(&self, _: *mut JSContext) -> NonZero<*mut JSObject> {
        assert!(!self.data.get().is_null());
        NonZero::new(self.data.get())
    }
}
<|endoftext|>