<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.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.

//! Implementation of `std::os` functionality for unix systems

#![allow(unused_imports)] // lots of cfg code here

use os::unix::prelude::*;

use error::Error as StdError;
use ffi::{OsString, OsStr};
use fmt;
use io::{self, Read, Write};
use iter;
use marker::PhantomData;
use mem;
use memchr;
use path::{self, PathBuf};
use ptr;
use slice;
use str;
use sys_common::mutex::Mutex;
use sys::{cvt, fd, syscall};
use vec;

const TMPBUF_SZ: usize = 128;
static ENV_LOCK: Mutex = Mutex::new();

/// Returns the platform-specific value of errno
pub fn errno() -> i32 {
    0
}

/// Gets a detailed string description for the given error number.
pub fn error_string(errno: i32) -> String {
    if let Some(string) = syscall::STR_ERROR.get(errno as usize) {
        string.to_string()
    } else {
        "unknown error".to_string()
    }
}

pub fn getcwd() -> io::Result<PathBuf> {
    let mut buf = [0; 4096];
    let count = cvt(syscall::getcwd(&mut buf))?;
    Ok(PathBuf::from(OsString::from_vec(buf[.. count].to_vec())))
}

pub fn chdir(p: &path::Path) -> io::Result<()> {
    cvt(syscall::chdir(p.to_str().unwrap())).and(Ok(()))
}

pub struct SplitPaths<'a> {
    iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
                    fn(&'a [u8]) -> PathBuf>,
}

pub fn split_paths(unparsed: &OsStr) -> SplitPaths {
    fn bytes_to_path(b: &[u8]) -> PathBuf {
        PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
    }
    fn is_colon(b: &u8) -> bool { *b == b':' }
    let unparsed = unparsed.as_bytes();
    SplitPaths {
        iter: unparsed.split(is_colon as fn(&u8) -> bool)
                      .map(bytes_to_path as fn(&[u8]) -> PathBuf)
    }
}

impl<'a> Iterator for SplitPaths<'a> {
    type Item = PathBuf;
    fn next(&mut self) -> Option<PathBuf> { self.iter.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

#[derive(Debug)]
pub struct JoinPathsError;

pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
    where I: Iterator<Item=T>, T: AsRef<OsStr>
{
    let mut joined = Vec::new();
    let sep = b':';

    for (i, path) in paths.enumerate() {
        let path = path.as_ref().as_bytes();
        if i > 0 { joined.push(sep) }
        if path.contains(&sep) {
            return Err(JoinPathsError)
        }
        joined.extend_from_slice(path);
    }
    Ok(OsStringExt::from_vec(joined))
}

impl fmt::Display for JoinPathsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "path segment contains separator `:`".fmt(f)
    }
}

impl StdError for JoinPathsError {
    fn description(&self) -> &str { "failed to join paths" }
}

pub fn current_exe() -> io::Result<PathBuf> {
    use fs::File;

    let mut file = File::open("sys:exe")?;

    let mut path = String::new();
    file.read_to_string(&mut path)?;

    if path.ends_with('\n') {
        path.pop();
    }

    Ok(PathBuf::from(path))
}

pub struct Env {
    iter: vec::IntoIter<(OsString, OsString)>,
    _dont_send_or_sync_me: PhantomData<*mut ()>,
}

impl Iterator for Env {
    type Item = (OsString, OsString);
    fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

/// Returns a vector of (variable, value) byte-vector pairs for all the
/// environment variables of the current process.
pub fn env() -> Env {
    let mut variables: Vec<(OsString, OsString)> = Vec::new();
    if let Ok(mut file) = ::fs::File::open("env:") {
        let mut string = String::new();
        if file.read_to_string(&mut string).is_ok() {
            for line in string.lines() {
                let mut parts = line.splitn(2, '=');
                if let Some(name) = parts.next() {
                    let value = parts.next().unwrap_or("");
                    variables.push((OsString::from(name.to_string()),
                                    OsString::from(value.to_string())));
                }
            }
        }
    }
    Env { iter: variables.into_iter(), _dont_send_or_sync_me: PhantomData }
}

pub fn getenv(key: &OsStr) -> io::Result<Option<OsString>> {
    if ! key.is_empty() {
        if let Ok(mut file) = ::fs::File::open(&("env:".to_owned() + key.to_str().unwrap())) {
            let mut string = String::new();
            file.read_to_string(&mut string)?;
            Ok(Some(OsString::from(string)))
        } else {
            Ok(None)
        }
    } else {
        Ok(None)
    }
}

pub fn setenv(key: &OsStr, value: &OsStr) -> io::Result<()> {
    if ! key.is_empty() {
        let mut file = ::fs::File::open(&("env:".to_owned() + key.to_str().unwrap()))?;
        file.write_all(value.as_bytes())?;
        file.set_len(value.len() as u64)?;
    }
    Ok(())
}

pub fn unsetenv(key: &OsStr) -> io::Result<()> {
    ::fs::remove_file(&("env:".to_owned() + key.to_str().unwrap()))?;
    Ok(())
}

pub fn page_size() -> usize {
    4096
}

pub fn temp_dir() -> PathBuf {
    ::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
        PathBuf::from("/tmp")
    })
}

pub fn home_dir() -> Option<PathBuf> {
    return ::env::var_os("HOME").map(PathBuf::from);
}

pub fn exit(code: i32) -> ! {
    let _ = syscall::exit(code as usize);
    unreachable!();
}
<commit_msg>Rollup merge of #39212 - redox-os:master, r=brson<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.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.

//! Implementation of `std::os` functionality for unix systems

#![allow(unused_imports)] // lots of cfg code here

use os::unix::prelude::*;

use error::Error as StdError;
use ffi::{OsString, OsStr};
use fmt;
use io::{self, Read, Write};
use iter;
use marker::PhantomData;
use mem;
use memchr;
use path::{self, PathBuf};
use ptr;
use slice;
use str;
use sys_common::mutex::Mutex;
use sys::{cvt, fd, syscall};
use vec;

const TMPBUF_SZ: usize = 128;
static ENV_LOCK: Mutex = Mutex::new();

extern {
    #[link_name = "__errno_location"]
    fn errno_location() -> *mut i32;
}

/// Returns the platform-specific value of errno
pub fn errno() -> i32 {
    unsafe {
        (*errno_location())
    }
}

/// Gets a detailed string description for the given error number.
pub fn error_string(errno: i32) -> String {
    if let Some(string) = syscall::STR_ERROR.get(errno as usize) {
        string.to_string()
    } else {
        "unknown error".to_string()
    }
}

pub fn getcwd() -> io::Result<PathBuf> {
    let mut buf = [0; 4096];
    let count = cvt(syscall::getcwd(&mut buf))?;
    Ok(PathBuf::from(OsString::from_vec(buf[.. count].to_vec())))
}

pub fn chdir(p: &path::Path) -> io::Result<()> {
    cvt(syscall::chdir(p.to_str().unwrap())).and(Ok(()))
}

pub struct SplitPaths<'a> {
    iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
                    fn(&'a [u8]) -> PathBuf>,
}

pub fn split_paths(unparsed: &OsStr) -> SplitPaths {
    fn bytes_to_path(b: &[u8]) -> PathBuf {
        PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
    }
    fn is_colon(b: &u8) -> bool { *b == b':' }
    let unparsed = unparsed.as_bytes();
    SplitPaths {
        iter: unparsed.split(is_colon as fn(&u8) -> bool)
                      .map(bytes_to_path as fn(&[u8]) -> PathBuf)
    }
}

impl<'a> Iterator for SplitPaths<'a> {
    type Item = PathBuf;
    fn next(&mut self) -> Option<PathBuf> { self.iter.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

#[derive(Debug)]
pub struct JoinPathsError;

pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
    where I: Iterator<Item=T>, T: AsRef<OsStr>
{
    let mut joined = Vec::new();
    let sep = b':';

    for (i, path) in paths.enumerate() {
        let path = path.as_ref().as_bytes();
        if i > 0 { joined.push(sep) }
        if path.contains(&sep) {
            return Err(JoinPathsError)
        }
        joined.extend_from_slice(path);
    }
    Ok(OsStringExt::from_vec(joined))
}

impl fmt::Display for JoinPathsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "path segment contains separator `:`".fmt(f)
    }
}

impl StdError for JoinPathsError {
    fn description(&self) -> &str { "failed to join paths" }
}

pub fn current_exe() -> io::Result<PathBuf> {
    use fs::File;

    let mut file = File::open("sys:exe")?;

    let mut path = String::new();
    file.read_to_string(&mut path)?;

    if path.ends_with('\n') {
        path.pop();
    }

    Ok(PathBuf::from(path))
}

pub struct Env {
    iter: vec::IntoIter<(OsString, OsString)>,
    _dont_send_or_sync_me: PhantomData<*mut ()>,
}

impl Iterator for Env {
    type Item = (OsString, OsString);
    fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}

/// Returns a vector of (variable, value) byte-vector pairs for all the
/// environment variables of the current process.
pub fn env() -> Env {
    let mut variables: Vec<(OsString, OsString)> = Vec::new();
    if let Ok(mut file) = ::fs::File::open("env:") {
        let mut string = String::new();
        if file.read_to_string(&mut string).is_ok() {
            for line in string.lines() {
                let mut parts = line.splitn(2, '=');
                if let Some(name) = parts.next() {
                    let value = parts.next().unwrap_or("");
                    variables.push((OsString::from(name.to_string()),
                                    OsString::from(value.to_string())));
                }
            }
        }
    }
    Env { iter: variables.into_iter(), _dont_send_or_sync_me: PhantomData }
}

pub fn getenv(key: &OsStr) -> io::Result<Option<OsString>> {
    if ! key.is_empty() {
        if let Ok(mut file) = ::fs::File::open(&("env:".to_owned() + key.to_str().unwrap())) {
            let mut string = String::new();
            file.read_to_string(&mut string)?;
            Ok(Some(OsString::from(string)))
        } else {
            Ok(None)
        }
    } else {
        Ok(None)
    }
}

pub fn setenv(key: &OsStr, value: &OsStr) -> io::Result<()> {
    if ! key.is_empty() {
        let mut file = ::fs::File::open(&("env:".to_owned() + key.to_str().unwrap()))?;
        file.write_all(value.as_bytes())?;
        file.set_len(value.len() as u64)?;
    }
    Ok(())
}

pub fn unsetenv(key: &OsStr) -> io::Result<()> {
    ::fs::remove_file(&("env:".to_owned() + key.to_str().unwrap()))?;
    Ok(())
}

pub fn page_size() -> usize {
    4096
}

pub fn temp_dir() -> PathBuf {
    ::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
        PathBuf::from("/tmp")
    })
}

pub fn home_dir() -> Option<PathBuf> {
    return ::env::var_os("HOME").map(PathBuf::from);
}

pub fn exit(code: i32) -> ! {
    let _ = syscall::exit(code as usize);
    unreachable!();
}
<|endoftext|>


<commit_before>// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use base::{ioctl_ior_nr, ioctl_iow_nr, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref};
use data_model::Le32;

use super::constants::*;
use super::virtio_input_absinfo;
use super::virtio_input_bitmap;
use super::virtio_input_device_ids;
use super::InputError;
use super::Result;

use std::collections::BTreeMap;
use std::os::raw::c_uint;
use std::ptr::null;

use base::{AsRawDescriptor, Descriptor};

const EVDEV: c_uint = 69;

#[repr(C)]
#[derive(Copy, Clone)]
struct evdev_buffer {
    buffer: [std::os::raw::c_uchar; 128],
}

impl evdev_buffer {
    fn new() -> evdev_buffer {
        evdev_buffer { buffer: [0u8; 128] }
    }

    fn get(&self, bit: usize) -> bool {
        let idx = bit / 8;
        let inner_bit = bit % 8;
        self.buffer
            .get(idx)
            .map_or(false, |val| val & (1u8 << inner_bit) != 0)
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
struct evdev_id {
    bustype: u16,
    vendor: u16,
    product: u16,
    version: u16,
}

impl evdev_id {
    fn new() -> evdev_id {
        evdev_id {
            bustype: 0,
            vendor: 0,
            product: 0,
            version: 0,
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
struct evdev_abs_info {
    // These should technically by signed ints, but Le32 is only compatible with u32 and we only
    // forward the bytes but don't care about its actual values.
    value: u32,
    minimum: u32,
    maximum: u32,
    fuzz: u32,
    flat: u32,
    resolution: u32,
}

impl evdev_abs_info {
    fn new() -> evdev_abs_info {
        evdev_abs_info {
            value: 0,
            minimum: 0,
            maximum: 0,
            fuzz: 0,
            flat: 0,
            resolution: 0,
        }
    }
}

impl From<evdev_abs_info> for virtio_input_absinfo {
    fn from(other: evdev_abs_info) -> Self {
        virtio_input_absinfo {
            min: Le32::from(other.minimum),
            max: Le32::from(other.maximum),
            fuzz: Le32::from(other.fuzz),
            flat: Le32::from(other.flat),
        }
    }
}

ioctl_ior_nr!(EVIOCGID, EVDEV, 0x02, evdev_id);
ioctl_ior_nr!(EVIOCGNAME, EVDEV, 0x06, evdev_buffer);
ioctl_ior_nr!(EVIOCGUNIQ, EVDEV, 0x08, evdev_buffer);
ioctl_ior_nr!(EVIOCGPROP, EVDEV, 0x09, evdev_buffer);
ioctl_ior_nr!(EVIOCGBIT, EVDEV, 0x20 + evt, evdev_buffer, evt);
ioctl_ior_nr!(EVIOCGABS, EVDEV, 0x40 + abs, evdev_abs_info, abs);
ioctl_iow_nr!(EVIOCGRAB, EVDEV, 0x90, u32);

fn errno() -> base::Error {
    base::Error::last()
}

/// Gets id information from an event device (see EVIOCGID ioctl for details).
pub fn device_ids<T: AsRawDescriptor>(descriptor: &T) -> Result<virtio_input_device_ids> {
    let mut dev_id = evdev_id::new();
    let len = unsafe {
        // Safe because the kernel won't write more than size of evdev_id and we check the return
        // value
        ioctl_with_mut_ref(
            &Descriptor(descriptor.as_raw_descriptor()),
            EVIOCGID(),
            &mut dev_id,
        )
    };
    if len < 0 {
        return Err(InputError::EvdevIdError(errno()));
    }
    Ok(virtio_input_device_ids::new(
        dev_id.bustype,
        dev_id.vendor,
        dev_id.product,
        dev_id.version,
    ))
}

/// Gets the name of an event device (see EVIOCGNAME ioctl for details).
pub fn name<T: AsRawDescriptor>(descriptor: &T) -> Result<Vec<u8>> {
    let mut name = evdev_buffer::new();
    let len = unsafe {
        // Safe because the kernel won't write more than size of evdev_buffer and we check the
        // return value
        ioctl_with_mut_ref(
            &Descriptor(descriptor.as_raw_descriptor()),
            EVIOCGNAME(),
            &mut name,
        )
    };
    if len < 0 {
        return Err(InputError::EvdevNameError(errno()));
    }
    Ok(name.buffer[0..len as usize].to_vec())
}

/// Gets the unique (serial) name of an event device (see EVIOCGUNIQ ioctl for details).
pub fn serial_name<T: AsRawDescriptor>(descriptor: &T) -> Result<Vec<u8>> {
    let mut uniq = evdev_buffer::new();
    let len = unsafe {
        // Safe because the kernel won't write more than size of evdev_buffer and we check the
        // return value
        ioctl_with_mut_ref(
            &Descriptor(descriptor.as_raw_descriptor()),
            EVIOCGUNIQ(),
            &mut uniq,
        )
    };
    if len < 0 {
        return Err(InputError::EvdevSerialError(errno()));
    }
    Ok(uniq.buffer[0..len as usize].to_vec())
}

/// Gets the properties of an event device (see EVIOCGPROP ioctl for details).
pub fn properties<T: AsRawDescriptor>(descriptor: &T) -> Result<virtio_input_bitmap> {
    let mut props = evdev_buffer::new();
    let len = unsafe {
        // Safe because the kernel won't write more than size of evdev_buffer and we check the
        // return value
        ioctl_with_mut_ref(
            &Descriptor(descriptor.as_raw_descriptor()),
            EVIOCGPROP(),
            &mut props,
        )
    };
    if len < 0 {
        return Err(InputError::EvdevPropertiesError(errno()));
    }
    Ok(virtio_input_bitmap::new(props.buffer))
}

/// Gets the event types supported by an event device as well as the event codes supported for each
/// type (see EVIOCGBIT ioctl for details).
pub fn supported_events<T: AsRawDescriptor>(
    descriptor: &T,
) -> Result<BTreeMap<u16, virtio_input_bitmap>> {
    let mut evts: BTreeMap<u16, virtio_input_bitmap> = BTreeMap::new();

    let mut evt_types = evdev_buffer::new();
    let len = unsafe {
        // Safe because the kernel won't write more than size of evdev_buffer and we check the
        // return value
        ioctl_with_mut_ref(
            &Descriptor(descriptor.as_raw_descriptor()),
            EVIOCGBIT(0),
            &mut evt_types,
        )
    };
    if len < 0 {
        return Err(InputError::EvdevEventTypesError(errno()));
    }

    // no need to ask for zero (EV_SYN) since it's always supported and treated as a special case
    for ev in 1..EV_MAX {
        if ev == EV_REP || !evt_types.get(ev as usize) {
            // Event type not supported, skip it.
            continue;
        }
        // Create a new zero-filled buffer every time to avoid carry-overs.
        let mut evt_codes = evdev_buffer::new();
        let len = unsafe {
            // Safe because the kernel won't write more than size of evdev_buffer and we check the
            // return value
            ioctl_with_mut_ref(
                &Descriptor(descriptor.as_raw_descriptor()),
                EVIOCGBIT(ev as c_uint),
                &mut evt_codes,
            )
        };
        if len < 0 {
            return Err(InputError::EvdevEventTypesError(errno()));
        }
        evts.insert(ev, virtio_input_bitmap::new(evt_codes.buffer));
    }
    Ok(evts)
}

/// Gets the absolute axes of an event device (see EVIOCGABS ioctl for details).
pub fn abs_info<T: AsRawDescriptor>(descriptor: &T) -> BTreeMap<u16, virtio_input_absinfo> {
    let mut ret: BTreeMap<u16, virtio_input_absinfo> = BTreeMap::new();

    for abs in 0..ABS_MAX {
        // Create a new one, zero-ed out every time to avoid carry-overs.
        let mut abs_info = evdev_abs_info::new();
        let len = unsafe {
            // Safe because the kernel won't write more than size of evdev_buffer and we check the
            // return value
            ioctl_with_mut_ref(
                &Descriptor(descriptor.as_raw_descriptor()),
                EVIOCGABS(abs as c_uint),
                &mut abs_info,
            )
        };
        if len > 0 {
            ret.insert(abs, virtio_input_absinfo::from(abs_info));
        }
    }
    ret
}

/// Grabs an event device (see EVIOCGGRAB ioctl for details). After this function succeeds the given
/// descriptor has exclusive access to the device, effectively making it unusable for any other process in
/// the host.
pub fn grab_evdev<T: AsRawDescriptor>(descriptor: &mut T) -> Result<()> {
    let val: u32 = 1;
    let ret = unsafe {
        // Safe because the kernel only read the value of the ptr and we check the return value
        ioctl_with_ref(
            &Descriptor(descriptor.as_raw_descriptor()),
            EVIOCGRAB(),
            &val,
        )
    };
    if ret == 0 {
        Ok(())
    } else {
        Err(InputError::EvdevGrabError(errno()))
    }
}

pub fn ungrab_evdev<T: AsRawDescriptor>(descriptor: &mut T) -> Result<()> {
    let ret = unsafe {
        // Safe because the kernel only reads the value of the ptr (doesn't dereference) and
        // we check the return value
        ioctl_with_ptr(
            &Descriptor(descriptor.as_raw_descriptor()),
            EVIOCGRAB(),
            null::<u32>(),
        )
    };
    if ret == 0 {
        Ok(())
    } else {
        Err(InputError::EvdevGrabError(errno()))
    }
}
<commit_msg>devices: input: fix ioctl handling<commit_after>// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use base::{ioctl_ior_nr, ioctl_iow_nr, ioctl_with_mut_ref, ioctl_with_ptr, ioctl_with_ref};
use data_model::Le32;

use super::constants::*;
use super::virtio_input_absinfo;
use super::virtio_input_bitmap;
use super::virtio_input_device_ids;
use super::InputError;
use super::Result;

use std::collections::BTreeMap;
use std::os::raw::c_uint;
use std::ptr::null;

use base::{AsRawDescriptor, Descriptor};

const EVDEV: c_uint = 69;

#[repr(C)]
#[derive(Copy, Clone)]
struct evdev_buffer {
    buffer: [std::os::raw::c_uchar; 128],
}

impl evdev_buffer {
    fn new() -> evdev_buffer {
        evdev_buffer { buffer: [0u8; 128] }
    }

    fn get(&self, bit: usize) -> bool {
        let idx = bit / 8;
        let inner_bit = bit % 8;
        self.buffer
            .get(idx)
            .map_or(false, |val| val & (1u8 << inner_bit) != 0)
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
struct evdev_id {
    bustype: u16,
    vendor: u16,
    product: u16,
    version: u16,
}

impl evdev_id {
    fn new() -> evdev_id {
        evdev_id {
            bustype: 0,
            vendor: 0,
            product: 0,
            version: 0,
        }
    }
}

#[repr(C)]
#[derive(Copy, Clone)]
struct evdev_abs_info {
    // These should technically by signed ints, but Le32 is only compatible with u32 and we only
    // forward the bytes but don't care about its actual values.
    value: u32,
    minimum: u32,
    maximum: u32,
    fuzz: u32,
    flat: u32,
    resolution: u32,
}

impl evdev_abs_info {
    fn new() -> evdev_abs_info {
        evdev_abs_info {
            value: 0,
            minimum: 0,
            maximum: 0,
            fuzz: 0,
            flat: 0,
            resolution: 0,
        }
    }
}

impl From<evdev_abs_info> for virtio_input_absinfo {
    fn from(other: evdev_abs_info) -> Self {
        virtio_input_absinfo {
            min: Le32::from(other.minimum),
            max: Le32::from(other.maximum),
            fuzz: Le32::from(other.fuzz),
            flat: Le32::from(other.flat),
        }
    }
}

ioctl_ior_nr!(EVIOCGID, EVDEV, 0x02, evdev_id);
ioctl_ior_nr!(EVIOCGNAME, EVDEV, 0x06, evdev_buffer);
ioctl_ior_nr!(EVIOCGUNIQ, EVDEV, 0x08, evdev_buffer);
ioctl_ior_nr!(EVIOCGPROP, EVDEV, 0x09, evdev_buffer);
ioctl_ior_nr!(EVIOCGBIT, EVDEV, 0x20 + evt, evdev_buffer, evt);
ioctl_ior_nr!(EVIOCGABS, EVDEV, 0x40 + abs, evdev_abs_info, abs);
ioctl_iow_nr!(EVIOCGRAB, EVDEV, 0x90, u32);

fn errno() -> base::Error {
    base::Error::last()
}

/// Gets id information from an event device (see EVIOCGID ioctl for details).
pub fn device_ids<T: AsRawDescriptor>(descriptor: &T) -> Result<virtio_input_device_ids> {
    let mut dev_id = evdev_id::new();
    let len = unsafe {
        // Safe because the kernel won't write more than size of evdev_id and we check the return
        // value
        ioctl_with_mut_ref(
            &Descriptor(descriptor.as_raw_descriptor()),
            EVIOCGID(),
            &mut dev_id,
        )
    };
    if len < 0 {
        return Err(InputError::EvdevIdError(errno()));
    }
    Ok(virtio_input_device_ids::new(
        dev_id.bustype,
        dev_id.vendor,
        dev_id.product,
        dev_id.version,
    ))
}

/// Gets the name of an event device (see EVIOCGNAME ioctl for details).
pub fn name<T: AsRawDescriptor>(descriptor: &T) -> Result<Vec<u8>> {
    let mut name = evdev_buffer::new();
    let len = unsafe {
        // Safe because the kernel won't write more than size of evdev_buffer and we check the
        // return value
        ioctl_with_mut_ref(
            &Descriptor(descriptor.as_raw_descriptor()),
            EVIOCGNAME(),
            &mut name,
        )
    };
    if len < 0 {
        return Err(InputError::EvdevNameError(errno()));
    }
    Ok(name.buffer[0..len as usize].to_vec())
}

/// Gets the unique (serial) name of an event device (see EVIOCGUNIQ ioctl for details).
pub fn serial_name<T: AsRawDescriptor>(descriptor: &T) -> Result<Vec<u8>> {
    let mut uniq = evdev_buffer::new();
    let len = unsafe {
        // Safe because the kernel won't write more than size of evdev_buffer and we check the
        // return value
        ioctl_with_mut_ref(
            &Descriptor(descriptor.as_raw_descriptor()),
            EVIOCGUNIQ(),
            &mut uniq,
        )
    };
    if len < 0 {
        return Err(InputError::EvdevSerialError(errno()));
    }
    Ok(uniq.buffer[0..len as usize].to_vec())
}

/// Gets the properties of an event device (see EVIOCGPROP ioctl for details).
pub fn properties<T: AsRawDescriptor>(descriptor: &T) -> Result<virtio_input_bitmap> {
    let mut props = evdev_buffer::new();
    let len = unsafe {
        // Safe because the kernel won't write more than size of evdev_buffer and we check the
        // return value
        ioctl_with_mut_ref(
            &Descriptor(descriptor.as_raw_descriptor()),
            EVIOCGPROP(),
            &mut props,
        )
    };
    if len < 0 {
        return Err(InputError::EvdevPropertiesError(errno()));
    }
    Ok(virtio_input_bitmap::new(props.buffer))
}

/// Gets the event types supported by an event device as well as the event codes supported for each
/// type (see EVIOCGBIT ioctl for details).
pub fn supported_events<T: AsRawDescriptor>(
    descriptor: &T,
) -> Result<BTreeMap<u16, virtio_input_bitmap>> {
    let mut evts: BTreeMap<u16, virtio_input_bitmap> = BTreeMap::new();

    let mut evt_types = evdev_buffer::new();
    let len = unsafe {
        // Safe because the kernel won't write more than size of evdev_buffer and we check the
        // return value
        ioctl_with_mut_ref(
            &Descriptor(descriptor.as_raw_descriptor()),
            EVIOCGBIT(0),
            &mut evt_types,
        )
    };
    if len < 0 {
        return Err(InputError::EvdevEventTypesError(errno()));
    }

    // no need to ask for zero (EV_SYN) since it's always supported and treated as a special case
    for ev in 1..EV_MAX {
        if ev == EV_REP || !evt_types.get(ev as usize) {
            // Event type not supported, skip it.
            continue;
        }
        // Create a new zero-filled buffer every time to avoid carry-overs.
        let mut evt_codes = evdev_buffer::new();
        let len = unsafe {
            // Safe because the kernel won't write more than size of evdev_buffer and we check the
            // return value
            ioctl_with_mut_ref(
                &Descriptor(descriptor.as_raw_descriptor()),
                EVIOCGBIT(ev as c_uint),
                &mut evt_codes,
            )
        };
        if len < 0 {
            return Err(InputError::EvdevEventTypesError(errno()));
        }
        evts.insert(ev, virtio_input_bitmap::new(evt_codes.buffer));
    }
    Ok(evts)
}

/// Gets the absolute axes of an event device (see EVIOCGABS ioctl for details).
pub fn abs_info<T: AsRawDescriptor>(descriptor: &T) -> BTreeMap<u16, virtio_input_absinfo> {
    let mut map: BTreeMap<u16, virtio_input_absinfo> = BTreeMap::new();

    for abs in 0..ABS_MAX {
        // Create a new one, zero-ed out every time to avoid carry-overs.
        let mut abs_info = evdev_abs_info::new();
        let ret = unsafe {
            // Safe because the kernel won't write more than size of evdev_buffer and we check the
            // return value
            ioctl_with_mut_ref(
                &Descriptor(descriptor.as_raw_descriptor()),
                EVIOCGABS(abs as c_uint),
                &mut abs_info,
            )
        };
        if ret == 0 {
            map.insert(abs, virtio_input_absinfo::from(abs_info));
        }
    }
    map
}

/// Grabs an event device (see EVIOCGGRAB ioctl for details). After this function succeeds the given
/// descriptor has exclusive access to the device, effectively making it unusable for any other process in
/// the host.
pub fn grab_evdev<T: AsRawDescriptor>(descriptor: &mut T) -> Result<()> {
    let val: u32 = 1;
    let ret = unsafe {
        // Safe because the kernel only read the value of the ptr and we check the return value
        ioctl_with_ref(
            &Descriptor(descriptor.as_raw_descriptor()),
            EVIOCGRAB(),
            &val,
        )
    };
    if ret == 0 {
        Ok(())
    } else {
        Err(InputError::EvdevGrabError(errno()))
    }
}

pub fn ungrab_evdev<T: AsRawDescriptor>(descriptor: &mut T) -> Result<()> {
    let ret = unsafe {
        // Safe because the kernel only reads the value of the ptr (doesn't dereference) and
        // we check the return value
        ioctl_with_ptr(
            &Descriptor(descriptor.as_raw_descriptor()),
            EVIOCGRAB(),
            null::<u32>(),
        )
    };
    if ret == 0 {
        Ok(())
    } else {
        Err(InputError::EvdevGrabError(errno()))
    }
}
<|endoftext|>


<commit_before>extern crate uuid;

use std::sync::mpsc::{channel, Sender, Receiver};
use std::collections::{HashMap};
use std::io::Write;

use self::uuid::Uuid;
use store::DataStore;

/// a distribution service
pub struct Distributor<S:Write, D:DataStore> {
    rx: Receiver<Kind<S>>, //receiver ch with data to be redistrubuted
    sx: HashMap<Uuid,S>, //local cache of streams to comm to
    store: Option<D>,
}

impl<S:Write, D:DataStore> Distributor<S,D>  {
    pub fn new (store: Option<D>) -> (Sender<Kind<S>>, Distributor<S,D>) {
        let (tx,rx) = channel();
        (tx, //sending channel to comm with Distributor
         Distributor {
             rx: rx,
             sx: HashMap::new(),
             store: store,
         })
    }

    pub fn run (&mut self) {
        let mut dead: Vec<Uuid> = vec!();

        for n in self.rx.iter() {
            match n {
                Kind::Broadcast(data) => {
                    for (uuid,mut stream) in self.sx.iter_mut() {
                        Distributor::<S,D>::write(stream,&uuid,&data,&mut dead, &self.store);
                    }
                },
                Kind::Select(uuid,data) => {
                    if let Some(stream) = self.sx.get_mut(&uuid) {
                        Distributor::<S,D>::write(stream,&uuid,&data,&mut dead, &self.store);
                    }
                },
                Kind::Group(mut uuids,data) => {
                    for uuid in uuids.drain(..) {
                        if let Some(stream) = self.sx.get_mut(&uuid) {
                            Distributor::<S,D>::write(stream,&uuid,&data,&mut dead, &self.store);
                        }
                    }
                },
                Kind::Add(uuid,stream) => { self.sx.insert(uuid,stream); }
                Kind::Remove(uuid) => { self.sx.remove(&uuid); }
            }

            // remove dead streams
            for n in dead.drain(..) {
                self.sx.remove(&n);
            }
        }
    }

    // FIXME: cannot use &mut self here!
    fn write (stream: &mut S,
              uuid: &Uuid,
              data: &Vec<u8>,
              dead: &mut Vec<Uuid>,
              store: &Option<D>) {
        if stream.write_all(data).is_err() {
            dead.push(uuid.clone());
        }
        else {
            if let &Some(ref store) = store {
                store.msg_store(uuid, data);
            }
        }
    }
}

#[allow(dead_code)]
pub enum Kind<S> {
    Add(Uuid,S),
    Remove(Uuid),

    Broadcast(Vec<u8>), //broadcast style data
    Select(Uuid,Vec<u8>), //send to single stream
    Group(Vec<Uuid>,Vec<u8>), //send to few streams
}
<commit_msg>fix cache logic<commit_after>extern crate uuid;

use std::sync::mpsc::{channel, Sender, Receiver};
use std::collections::{HashMap};
use std::io::Write;

use self::uuid::Uuid;
use store::DataStore;

/// a distribution service
pub struct Distributor<S:Write, D:DataStore> {
    rx: Receiver<Kind<S>>, //receiver ch with data to be redistrubuted
    sx: HashMap<Uuid,S>, //local cache of streams to comm to
    store: Option<D>,
}

impl<S:Write, D:DataStore> Distributor<S,D>  {
    pub fn new (store: Option<D>) -> (Sender<Kind<S>>, Distributor<S,D>) {
        let (tx,rx) = channel();
        (tx, //sending channel to comm with Distributor
         Distributor {
             rx: rx,
             sx: HashMap::new(),
             store: store,
         })
    }

    pub fn run (&mut self) {
        let mut dead: Vec<Uuid> = vec!();

        for n in self.rx.iter() {
            match n {
                Kind::Broadcast(data) => {
                    for (uuid,mut stream) in self.sx.iter_mut() {
                        Distributor::<S,D>::write(stream,&uuid,&data,&mut dead, &self.store);
                    }
                },
                Kind::Select(uuid,data) => {
                    if let Some(stream) = self.sx.get_mut(&uuid) {
                        Distributor::<S,D>::write(stream,&uuid,&data,&mut dead, &self.store);
                    }
                },
                Kind::Group(mut uuids,data) => {
                    for uuid in uuids.drain(..) {
                        if let Some(stream) = self.sx.get_mut(&uuid) {
                            Distributor::<S,D>::write(stream,&uuid,&data,&mut dead, &self.store);
                        }
                    }
                },
                Kind::Add(uuid,stream) => { self.sx.insert(uuid,stream); }
                Kind::Remove(uuid) => { self.sx.remove(&uuid); }
            }

            // remove dead streams
            for n in dead.drain(..) {
                self.sx.remove(&n);
            }
        }
    }

    // FIXME: cannot use &mut self here!
    fn write (stream: &mut S,
              uuid: &Uuid,
              data: &Vec<u8>,
              dead: &mut Vec<Uuid>,
              store: &Option<D>) {
        if stream.write_all(data).is_err() {
            dead.push(uuid.clone());
            if let &Some(ref store) = store {
                store.msg_store(uuid, data);
            }
        }
    }
}

#[allow(dead_code)]
pub enum Kind<S> {
    Add(Uuid,S),
    Remove(Uuid),

    Broadcast(Vec<u8>), //broadcast style data
    Select(Uuid,Vec<u8>), //send to single stream
    Group(Vec<Uuid>,Vec<u8>), //send to few streams
}
<|endoftext|>


<commit_before>use ::libc;
use ::cssparser::{Parser, ParserInput, Token, BasicParseError};
use ::glib::translate::*;
use ::glib_sys;

use std::f64::consts::*;
use std::mem;
use std::ptr;
use std::slice;
use std::str;

#[derive(Debug, Clone, PartialEq)]
pub struct ParseError {
    pub display: String
}

impl ParseError {
    pub fn new<T: AsRef<str>> (msg: T) -> ParseError {
        ParseError { display: msg.as_ref ().to_string () }
    }
}

impl<'a> From<BasicParseError<'a>> for ParseError {
    fn from (_: BasicParseError) -> ParseError {
        ParseError::new ("parse error")
    }
}

// angle:
// https://www.w3.org/TR/SVG/types.html#DataTypeAngle
//
// angle ::= number ("deg" | "grad" | "rad")?
//
// Returns an f64 angle in degrees

pub fn angle_degrees (s: &str) -> Result <f64, ParseError> {
    let mut input = ParserInput::new (s);
    let mut parser = Parser::new (&mut input);

    let token = parser.next ()
        .map_err (|_| ParseError::new ("expected angle"))?;

    match token {
        &Token::Number { value, .. } => Ok (value as f64),

        &Token::Dimension { value, ref unit, .. } => {
            let value = value as f64;

            match unit.as_ref () {
                "deg"  => Ok (value),
                "grad" => Ok (value * 360.0 / 400.0),
                "rad"  => Ok (value * 180.0 / PI),
                _      => Err (ParseError::new ("expected angle"))
            }
        },

        _ => Err (ParseError::new ("expected angle"))
    }.and_then (|r|
                parser.expect_exhausted ()
                .map (|_| r)
                .map_err (|_| ParseError::new ("expected angle")))
}

fn optional_comma (parser: &mut Parser) {
    let _ = parser.try (|p| p.expect_comma ());
}

// number-optional-number
//
// https://www.w3.org/TR/SVG/types.html#DataTypeNumberOptionalNumber

pub fn number_optional_number (s: &str) -> Result <(f64, f64), ParseError> {
    let mut input = ParserInput::new (s);
    let mut parser = Parser::new (&mut input);

    let x = parser.expect_number ()? as f64;

    if !parser.is_exhausted () {
        let position = parser.position ();

        match *parser.next ()? {
            Token::Comma => {},
            _ => parser.reset (position)
        };

        let y = parser.expect_number ()? as f64;

        parser.expect_exhausted ()?;

        Ok ((x, y))
    } else {
        Ok ((x, x))
    }
}

#[no_mangle]
pub extern fn rsvg_css_parse_number_optional_number (s: *const libc::c_char,
                                                     out_x: *mut f64,
                                                     out_y: *mut f64) -> glib_sys::gboolean {
    assert! (!s.is_null ());
    assert! (!out_x.is_null ());
    assert! (!out_y.is_null ());

    let string = unsafe { String::from_glib_none (s) };

    match number_optional_number (&string) {
        Ok ((x, y)) => {
            unsafe {
                *out_x = x;
                *out_y = y;
            }
            true
        },

        Err (_) => {
            unsafe {
                *out_x = 0.0;
                *out_y = 0.0;
            }
            false
        }
    }.to_glib ()
}

// Parse a list-of-points as for polyline and polygon elements
// https://www.w3.org/TR/SVG/shapes.html#PointsBNF

pub fn list_of_points (string: &str) -> Result <Vec<(f64, f64)>, ParseError> {
    let mut input = ParserInput::new (string);
    let mut parser = Parser::new (&mut input);

    let mut v = Vec::new ();

    loop {
        let x = parser.expect_number ()? as f64;

        optional_comma (&mut parser);

        let y = parser.expect_number ()? as f64;

        v.push ((x, y));

        if parser.is_exhausted () {
            break;
        }

        match parser.next_including_whitespace () {
            Ok (&Token::WhiteSpace(_)) => (),
            _ => optional_comma (&mut parser)
        }
    }

    Ok (v)
}

// Lists of number values

pub enum ListLength {
    Exact (usize),
    Maximum (usize)
}

#[derive(Debug, PartialEq)]
pub enum NumberListError {
    IncorrectNumberOfElements,
    Parse (ParseError)
}

pub fn number_list (s: &str, length: ListLength) -> Result <Vec<f64>, NumberListError> {
    let n;

    match length {
        ListLength::Exact (l)   => { assert! (l > 0); n = l; }
        ListLength::Maximum (l) => { assert! (l > 0); n = l; }
    }

    let mut input = ParserInput::new (s);
    let mut parser = Parser::new (&mut input);

    let mut v = Vec::<f64>::with_capacity (n);

    for i in 0..n {
        v.push (parser.expect_number ().map_err (|_| NumberListError::Parse (ParseError::new ("expected number")))? as f64);

        if i != n - 1 {
            optional_comma (&mut parser);
        }

        if parser.is_exhausted () {
            if let ListLength::Maximum (_) = length {
                break;
            }
        }
    }

    parser.expect_exhausted ().map_err (|_| NumberListError::IncorrectNumberOfElements)?;

    Ok(v)
}

#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum NumberListLength {
    Exact,
    Maximum
}

#[no_mangle]
pub extern fn rsvg_css_parse_number_list (in_str:   *const libc::c_char,
                                          nlength:  NumberListLength,
                                          size:     libc::size_t,
                                          out_list: *mut *const libc::c_double,
                                          out_list_length: *mut libc::size_t) -> glib_sys::gboolean {
    assert! (!in_str.is_null ());
    assert! (!out_list.is_null ());
    assert! (!out_list_length.is_null ());

    let length = match nlength {
        NumberListLength::Exact   => ListLength::Exact (size),
        NumberListLength::Maximum => ListLength::Maximum (size)
    };

    let s = unsafe { String::from_glib_none (in_str) };

    let result = number_list (&s, length);

    match result {
        Ok (number_list) => {
            let num_elems = number_list.len ();

            let c_array = unsafe {
                glib_sys::g_malloc_n (num_elems,
                                      mem::size_of::<libc::c_double> ())
                    as *mut libc::c_double
            };

            let mut array = unsafe { slice::from_raw_parts_mut (c_array, num_elems) };

            array.copy_from_slice (&number_list);

            unsafe {
                *out_list = c_array;
                *out_list_length = num_elems;
            }

            true
        },

        Err (_) => {
            unsafe {
                *out_list = ptr::null ();
                *out_list_length = 0;
            }
            false
        }
    }.to_glib ()
}

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

    #[test]
    fn parses_number_optional_number () {
        assert_eq! (number_optional_number ("1, 2"), Ok ((1.0, 2.0)));
        assert_eq! (number_optional_number ("1 2"),  Ok ((1.0, 2.0)));
        assert_eq! (number_optional_number ("1"),    Ok ((1.0, 1.0)));

        assert_eq! (number_optional_number ("-1, -2"), Ok ((-1.0, -2.0)));
        assert_eq! (number_optional_number ("-1 -2"),  Ok ((-1.0, -2.0)));
        assert_eq! (number_optional_number ("-1"),     Ok ((-1.0, -1.0)));
    }

    #[test]
    fn invalid_number_optional_number () {
        assert! (number_optional_number ("").is_err ());
        assert! (number_optional_number ("1x").is_err ());
        assert! (number_optional_number ("x1").is_err ());
        assert! (number_optional_number ("1 x").is_err ());
        assert! (number_optional_number ("1 , x").is_err ());
        assert! (number_optional_number ("1 , 2x").is_err ());
        assert! (number_optional_number ("1 2 x").is_err ());
    }

    #[test]
    fn parses_list_of_points () {
        assert_eq! (list_of_points (" 1 2 "),      Ok (vec! [(1.0, 2.0)]));
        assert_eq! (list_of_points ("1 2 3 4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points ("1,2,3,4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points ("1,2 3,4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points ("1,2 -3,4"), Ok (vec! [(1.0, 2.0), (-3.0, 4.0)]));
        assert_eq! (list_of_points ("1,2,-3,4"), Ok (vec! [(1.0, 2.0), (-3.0, 4.0)]));
    }

    #[test]
    fn errors_on_invalid_list_of_points () {
        assert! (list_of_points ("-1-2-3-4").is_err ());
        assert! (list_of_points ("1 2-3,-4").is_err ());
    }

    #[test]
    fn parses_angle () {
        assert_eq! (angle_degrees ("0"),        Ok (0.0));
        assert_eq! (angle_degrees ("15"),       Ok (15.0));
        assert_eq! (angle_degrees ("180.5deg"), Ok (180.5));
        assert_eq! (angle_degrees ("1rad"),     Ok (180.0 / PI));
        assert_eq! (angle_degrees ("-400grad"), Ok (-360.0));

        assert! (angle_degrees ("").is_err ());
        assert! (angle_degrees ("foo").is_err ());
        assert! (angle_degrees ("300foo").is_err ());
    }

    #[test]
    fn parses_number_list () {
        assert_eq! (number_list ("5", ListLength::Exact (1)),
                    Ok (vec! [5.0]));

        assert_eq! (number_list ("1 2 3 4", ListLength::Exact (4)),
                    Ok (vec! [1.0, 2.0, 3.0, 4.0]));

        assert_eq! (number_list ("5", ListLength::Maximum (1)),
                    Ok (vec! [5.0]));

        assert_eq! (number_list ("1.0, -2.5", ListLength::Maximum (2)),
                    Ok (vec! [1.0, -2.5]));

        assert_eq! (number_list ("5 6", ListLength::Maximum (3)),
                    Ok (vec! [5.0, 6.0]));
    }

    #[test]
    fn errors_on_invalid_number_list () {
        // empty
        assert! (number_list ("", ListLength::Exact (1)).is_err ());

        // garbage
        assert! (number_list ("foo", ListLength::Exact (1)).is_err ());
        assert! (number_list ("1foo", ListLength::Exact (2)).is_err ());
        assert! (number_list ("1 foo", ListLength::Exact (2)).is_err ());
        assert! (number_list ("1 foo 2", ListLength::Exact (2)).is_err ());
        assert! (number_list ("1,foo", ListLength::Exact (2)).is_err ());

        // too many
        assert! (number_list ("1 2", ListLength::Exact (1)).is_err ());
        assert! (number_list ("1,2,3", ListLength::Maximum (2)).is_err ());

        // extra token
        assert! (number_list ("1,", ListLength::Exact (1)).is_err ());

        // too few
        assert! (number_list ("1", ListLength::Exact (2)).is_err ());
        assert! (number_list ("1 2", ListLength::Exact (3)).is_err ());
    }
}
<commit_msg>Refactor some more to avoid Ok() all over the place<commit_after>use ::libc;
use ::cssparser::{Parser, ParserInput, Token, BasicParseError};
use ::glib::translate::*;
use ::glib_sys;

use std::f64::consts::*;
use std::mem;
use std::ptr;
use std::slice;
use std::str;

#[derive(Debug, Clone, PartialEq)]
pub struct ParseError {
    pub display: String
}

impl ParseError {
    pub fn new<T: AsRef<str>> (msg: T) -> ParseError {
        ParseError { display: msg.as_ref ().to_string () }
    }
}

impl<'a> From<BasicParseError<'a>> for ParseError {
    fn from (_: BasicParseError) -> ParseError {
        ParseError::new ("parse error")
    }
}

// angle:
// https://www.w3.org/TR/SVG/types.html#DataTypeAngle
//
// angle ::= number ("deg" | "grad" | "rad")?
//
// Returns an f64 angle in degrees

pub fn angle_degrees (s: &str) -> Result <f64, ParseError> {
    let mut input = ParserInput::new (s);
    let mut parser = Parser::new (&mut input);

    let angle = {
        let token = parser.next ()
            .map_err (|_| ParseError::new ("expected angle"))?;

        match token {
            &Token::Number { value, .. } => value as f64,

            &Token::Dimension { value, ref unit, .. } => {
                let value = value as f64;

                match unit.as_ref () {
                    "deg"  => value,
                    "grad" => value * 360.0 / 400.0,
                    "rad"  => value * 180.0 / PI,
                    _      => return Err (ParseError::new ("expected angle"))
                }
            },

            _ => return Err (ParseError::new ("expected angle"))
        }
    };

    parser.expect_exhausted ().map_err (|_| ParseError::new ("expected angle"))?;

    Ok (angle)
}

fn optional_comma (parser: &mut Parser) {
    let _ = parser.try (|p| p.expect_comma ());
}

// number-optional-number
//
// https://www.w3.org/TR/SVG/types.html#DataTypeNumberOptionalNumber

pub fn number_optional_number (s: &str) -> Result <(f64, f64), ParseError> {
    let mut input = ParserInput::new (s);
    let mut parser = Parser::new (&mut input);

    let x = parser.expect_number ()? as f64;

    if !parser.is_exhausted () {
        let position = parser.position ();

        match *parser.next ()? {
            Token::Comma => {},
            _ => parser.reset (position)
        };

        let y = parser.expect_number ()? as f64;

        parser.expect_exhausted ()?;

        Ok ((x, y))
    } else {
        Ok ((x, x))
    }
}

#[no_mangle]
pub extern fn rsvg_css_parse_number_optional_number (s: *const libc::c_char,
                                                     out_x: *mut f64,
                                                     out_y: *mut f64) -> glib_sys::gboolean {
    assert! (!s.is_null ());
    assert! (!out_x.is_null ());
    assert! (!out_y.is_null ());

    let string = unsafe { String::from_glib_none (s) };

    match number_optional_number (&string) {
        Ok ((x, y)) => {
            unsafe {
                *out_x = x;
                *out_y = y;
            }
            true
        },

        Err (_) => {
            unsafe {
                *out_x = 0.0;
                *out_y = 0.0;
            }
            false
        }
    }.to_glib ()
}

// Parse a list-of-points as for polyline and polygon elements
// https://www.w3.org/TR/SVG/shapes.html#PointsBNF

pub fn list_of_points (string: &str) -> Result <Vec<(f64, f64)>, ParseError> {
    let mut input = ParserInput::new (string);
    let mut parser = Parser::new (&mut input);

    let mut v = Vec::new ();

    loop {
        let x = parser.expect_number ()? as f64;

        optional_comma (&mut parser);

        let y = parser.expect_number ()? as f64;

        v.push ((x, y));

        if parser.is_exhausted () {
            break;
        }

        match parser.next_including_whitespace () {
            Ok (&Token::WhiteSpace(_)) => (),
            _ => optional_comma (&mut parser)
        }
    }

    Ok (v)
}

// Lists of number values

pub enum ListLength {
    Exact (usize),
    Maximum (usize)
}

#[derive(Debug, PartialEq)]
pub enum NumberListError {
    IncorrectNumberOfElements,
    Parse (ParseError)
}

pub fn number_list (s: &str, length: ListLength) -> Result <Vec<f64>, NumberListError> {
    let n;

    match length {
        ListLength::Exact (l)   => { assert! (l > 0); n = l; }
        ListLength::Maximum (l) => { assert! (l > 0); n = l; }
    }

    let mut input = ParserInput::new (s);
    let mut parser = Parser::new (&mut input);

    let mut v = Vec::<f64>::with_capacity (n);

    for i in 0..n {
        v.push (parser.expect_number ().map_err (|_| NumberListError::Parse (ParseError::new ("expected number")))? as f64);

        if i != n - 1 {
            optional_comma (&mut parser);
        }

        if parser.is_exhausted () {
            if let ListLength::Maximum (_) = length {
                break;
            }
        }
    }

    parser.expect_exhausted ().map_err (|_| NumberListError::IncorrectNumberOfElements)?;

    Ok(v)
}

#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum NumberListLength {
    Exact,
    Maximum
}

#[no_mangle]
pub extern fn rsvg_css_parse_number_list (in_str:   *const libc::c_char,
                                          nlength:  NumberListLength,
                                          size:     libc::size_t,
                                          out_list: *mut *const libc::c_double,
                                          out_list_length: *mut libc::size_t) -> glib_sys::gboolean {
    assert! (!in_str.is_null ());
    assert! (!out_list.is_null ());
    assert! (!out_list_length.is_null ());

    let length = match nlength {
        NumberListLength::Exact   => ListLength::Exact (size),
        NumberListLength::Maximum => ListLength::Maximum (size)
    };

    let s = unsafe { String::from_glib_none (in_str) };

    let result = number_list (&s, length);

    match result {
        Ok (number_list) => {
            let num_elems = number_list.len ();

            let c_array = unsafe {
                glib_sys::g_malloc_n (num_elems,
                                      mem::size_of::<libc::c_double> ())
                    as *mut libc::c_double
            };

            let mut array = unsafe { slice::from_raw_parts_mut (c_array, num_elems) };

            array.copy_from_slice (&number_list);

            unsafe {
                *out_list = c_array;
                *out_list_length = num_elems;
            }

            true
        },

        Err (_) => {
            unsafe {
                *out_list = ptr::null ();
                *out_list_length = 0;
            }
            false
        }
    }.to_glib ()
}

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

    #[test]
    fn parses_number_optional_number () {
        assert_eq! (number_optional_number ("1, 2"), Ok ((1.0, 2.0)));
        assert_eq! (number_optional_number ("1 2"),  Ok ((1.0, 2.0)));
        assert_eq! (number_optional_number ("1"),    Ok ((1.0, 1.0)));

        assert_eq! (number_optional_number ("-1, -2"), Ok ((-1.0, -2.0)));
        assert_eq! (number_optional_number ("-1 -2"),  Ok ((-1.0, -2.0)));
        assert_eq! (number_optional_number ("-1"),     Ok ((-1.0, -1.0)));
    }

    #[test]
    fn invalid_number_optional_number () {
        assert! (number_optional_number ("").is_err ());
        assert! (number_optional_number ("1x").is_err ());
        assert! (number_optional_number ("x1").is_err ());
        assert! (number_optional_number ("1 x").is_err ());
        assert! (number_optional_number ("1 , x").is_err ());
        assert! (number_optional_number ("1 , 2x").is_err ());
        assert! (number_optional_number ("1 2 x").is_err ());
    }

    #[test]
    fn parses_list_of_points () {
        assert_eq! (list_of_points (" 1 2 "),      Ok (vec! [(1.0, 2.0)]));
        assert_eq! (list_of_points ("1 2 3 4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points ("1,2,3,4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points ("1,2 3,4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points ("1,2 -3,4"), Ok (vec! [(1.0, 2.0), (-3.0, 4.0)]));
        assert_eq! (list_of_points ("1,2,-3,4"), Ok (vec! [(1.0, 2.0), (-3.0, 4.0)]));
    }

    #[test]
    fn errors_on_invalid_list_of_points () {
        assert! (list_of_points ("-1-2-3-4").is_err ());
        assert! (list_of_points ("1 2-3,-4").is_err ());
    }

    #[test]
    fn parses_angle () {
        assert_eq! (angle_degrees ("0"),        Ok (0.0));
        assert_eq! (angle_degrees ("15"),       Ok (15.0));
        assert_eq! (angle_degrees ("180.5deg"), Ok (180.5));
        assert_eq! (angle_degrees ("1rad"),     Ok (180.0 / PI));
        assert_eq! (angle_degrees ("-400grad"), Ok (-360.0));

        assert! (angle_degrees ("").is_err ());
        assert! (angle_degrees ("foo").is_err ());
        assert! (angle_degrees ("300foo").is_err ());
    }

    #[test]
    fn parses_number_list () {
        assert_eq! (number_list ("5", ListLength::Exact (1)),
                    Ok (vec! [5.0]));

        assert_eq! (number_list ("1 2 3 4", ListLength::Exact (4)),
                    Ok (vec! [1.0, 2.0, 3.0, 4.0]));

        assert_eq! (number_list ("5", ListLength::Maximum (1)),
                    Ok (vec! [5.0]));

        assert_eq! (number_list ("1.0, -2.5", ListLength::Maximum (2)),
                    Ok (vec! [1.0, -2.5]));

        assert_eq! (number_list ("5 6", ListLength::Maximum (3)),
                    Ok (vec! [5.0, 6.0]));
    }

    #[test]
    fn errors_on_invalid_number_list () {
        // empty
        assert! (number_list ("", ListLength::Exact (1)).is_err ());

        // garbage
        assert! (number_list ("foo", ListLength::Exact (1)).is_err ());
        assert! (number_list ("1foo", ListLength::Exact (2)).is_err ());
        assert! (number_list ("1 foo", ListLength::Exact (2)).is_err ());
        assert! (number_list ("1 foo 2", ListLength::Exact (2)).is_err ());
        assert! (number_list ("1,foo", ListLength::Exact (2)).is_err ());

        // too many
        assert! (number_list ("1 2", ListLength::Exact (1)).is_err ());
        assert! (number_list ("1,2,3", ListLength::Maximum (2)).is_err ());

        // extra token
        assert! (number_list ("1,", ListLength::Exact (1)).is_err ());

        // too few
        assert! (number_list ("1", ListLength::Exact (2)).is_err ());
        assert! (number_list ("1 2", ListLength::Exact (3)).is_err ());
    }
}
<|endoftext|>


<commit_before>//! Two- and three-dimensional array support.

use cl::*;
use cl::ll::*;
use mem::*;
use std::mem;
use std::vec::Vec;
use libc::{size_t, c_void};

use hl::KernelArg;

pub struct Array3D<T> {
    width: uint,
    height: uint,
    depth: uint,
    dat: Vec<T>
}

pub struct Array3DCL<T> {
    width: uint,
    height: uint,
    depth: uint,
    buf: cl_mem,
}

impl<T: Clone> Array3D<T> {
    pub fn new(width: uint, height: uint, depth: uint, val: |uint, uint, uint| -> T) -> Array3D<T>
    {
        let mut dat: Vec<T> = Vec::new();
        for x in range(0, width) {
            for y in range(0, height) {
                for z in range(0, depth) {
                    dat.push(val(x, y, z));
                }
            }
        }

        Array3D {
            width: width,
            height: height,
            depth: depth,
            dat: dat
        }
    }

    pub fn set(&mut self, x: uint, y: uint, z: uint, val: T)
    {
        self.dat.as_mut_slice()[self.width*self.height*z + self.width*y + x] = val;
    }

    pub fn get(&self, x: uint, y: uint, z: uint) -> T
    {
        self.dat.as_slice()[self.width*self.height*z + self.width*y + x].clone()
    }
}

#[unsafe_destructor]
impl<T> Drop for Array3DCL<T> {
    fn drop(&mut self) {
        unsafe {
            clReleaseMemObject(self.buf);
        }
    }
}

impl<'r, T> Put<Array3D<T>, Array3DCL<T>> for &'r Array3D<T>
{
    fn put(&self, f: |ptr: *const c_void, size: size_t| -> cl_mem) -> Array3DCL<T>
    {
        let p = self.dat.as_ptr();
        let len = self.dat.len();
        let out = f(p as *const c_void, (len * mem::size_of::<T>()) as size_t);

        Array3DCL{
            width: self.width,
            height: self.height,
            depth: self.depth,
            buf: out
        }
    }
}

impl<T> Get<Array3DCL<T>, Array3D<T>> for Array3D<T>
{
    fn get(arr: &Array3DCL<T>, f: |offset: size_t, ptr: *mut c_void, size: size_t|) -> Array3D<T>
    {
        let mut v: Vec<T> = Vec::with_capacity(arr.len());
        unsafe {
            v.set_len(arr.len());
        }

        let p = v.as_mut_ptr();
        let len = v.len();
        f(0, p as *mut c_void, (len * mem::size_of::<T>()) as size_t);

        Array3D {
            width: arr.width,
            height: arr.height,
            depth: arr.depth,
            dat: v
        }
    }
}

impl<T> Write for Array3D<T> {
    fn write(&self, f: |offset: size_t, ptr: *const c_void, size: size_t|)
    {
        let p = self.dat.as_ptr();
        let len = self.dat.len();
        f(0, p as *const c_void, (len * mem::size_of::<T>()) as size_t)
    }
}

impl<T> Read for Array3D<T> {
    fn read(&mut self, f: |offset: size_t, ptr: *mut c_void, size: size_t|)
    {
        let p = self.dat.as_ptr();
        let len = self.dat.len();
        f(0, p as *mut c_void, (len * mem::size_of::<T>()) as size_t)
    }
}

impl<T> Buffer<T> for Array3DCL<T> {
    fn id_ptr(&self) -> *const cl_mem {
        &self.buf as *const cl_mem
    }

    fn len(&self) -> uint {
        self.width * self.height * self.depth
    }
}

impl<T> KernelArg for Array3DCL<T> {
    fn get_value(&self) -> (size_t, *const c_void)
    {
        (mem::size_of::<cl_mem>() as size_t,
         self.id_ptr() as *const c_void)
    }
}

pub struct Array2D<T> {
    width: uint,
    height: uint,
    dat: Vec<T>,
}

pub struct Array2DCL<T> {
    width: uint,
    height: uint,
    buf: cl_mem,
}

impl<T: Clone> Array2D<T> {
    pub fn new(width: uint, height: uint, val: |uint, uint| -> T) -> Array2D<T> {
        let mut dat: Vec<T> = Vec::new();
        for x in range(0, width) {
            for y in range(0, height) {
                dat.push(val(x, y));
            }
        }
        Array2D {
            width: width,
            height: height,
            dat: dat,
        }
    }

    pub fn set(&mut self, x: uint, y: uint, val: T) {
        self.dat.as_mut_slice()[self.width*y + x] = val;
    }

    pub fn get(&self, x: uint, y: uint) -> T {
        self.dat.as_slice()[self.width*y + x].clone()
    }
}

#[unsafe_destructor]
impl<T> Drop for Array2DCL<T> {
    fn drop(&mut self) {
        unsafe {
            clReleaseMemObject(self.buf);
        }
    }
}

impl<'r, T> Put<Array2D<T>, Array2DCL<T>> for &'r Array2D<T>
{
    fn put(&self, f: |ptr: *const c_void, size: size_t| -> cl_mem) -> Array2DCL<T>
    {
        let p = self.dat.as_ptr();
        let len = self.dat.len();
        let out = f(p as *const c_void, (len * mem::size_of::<T>()) as size_t);

        Array2DCL{
            width: self.width,
            height: self.height,
            buf: out
        }
    }
}

impl<T> Get<Array2DCL<T>, Array2D<T>> for Array2D<T>
{
    fn get(arr: &Array2DCL<T>, f: |offset: size_t, ptr: *mut c_void, size: size_t|) -> Array2D<T>
    {
        let mut v: Vec<T> = Vec::with_capacity(arr.len());
        unsafe {
            v.set_len(arr.len())
        }

        let p = v.as_mut_ptr();
        let len = v.len();
        f(0, p as *mut c_void, (len * mem::size_of::<T>()) as size_t);

        Array2D {
            width: arr.width,
            height: arr.height,
            dat: v
        }
    }
}

impl<T> Write for Array2D<T> {
    fn write(&self, f: |offset: size_t, ptr: *const c_void, size: size_t|)
    {
        let p = self.dat.as_ptr();
        let len = self.dat.len();
        f(0, p as *const c_void, (len * mem::size_of::<T>()) as size_t)
    }
}

impl<T> Read for Array2D<T> {
    fn read(&mut self, f: |offset: size_t, ptr: *mut c_void, size: size_t|)
    {
        let p = self.dat.as_ptr();
        let len = self.dat.len();
        f(0, p as *mut c_void, (len * mem::size_of::<T>()) as size_t)
    }
}

impl<T> Buffer<T> for Array2DCL<T> {
    fn id_ptr(&self) -> *const cl_mem {
        &self.buf as *const cl_mem
    }

    fn len(&self) -> uint {
        self.width * self.height
    }
}

impl<T> KernelArg for Array2DCL<T> {
    fn get_value(&self) -> (size_t, *const c_void)
    {
        (mem::size_of::<cl_mem>() as size_t,
         self.id_ptr() as *const c_void)
    }
}
<commit_msg>Fixed unsafe code<commit_after>//! Two- and three-dimensional array support.

use cl::*;
use cl::ll::*;
use mem::*;
use std::mem;
use std::vec::Vec;
use libc::{size_t, c_void};

use hl::KernelArg;

pub struct Array3D<T> {
    width: uint,
    height: uint,
    depth: uint,
    dat: Vec<T>
}

pub struct Array3DCL<T> {
    width: uint,
    height: uint,
    depth: uint,
    buf: cl_mem,
}

impl<T: Clone> Array3D<T> {
    pub fn new(width: uint, height: uint, depth: uint, val: |uint, uint, uint| -> T) -> Array3D<T>
    {
        let mut dat: Vec<T> = Vec::new();
        for x in range(0, width) {
            for y in range(0, height) {
                for z in range(0, depth) {
                    dat.push(val(x, y, z));
                }
            }
        }

        Array3D {
            width: width,
            height: height,
            depth: depth,
            dat: dat
        }
    }

    pub fn set(&mut self, x: uint, y: uint, z: uint, val: T)
    {
        self.dat.as_mut_slice()[self.width*self.height*z + self.width*y + x] = val;
    }

    pub fn get(&self, x: uint, y: uint, z: uint) -> T
    {
        self.dat.as_slice()[self.width*self.height*z + self.width*y + x].clone()
    }
}

#[unsafe_destructor]
impl<T> Drop for Array3DCL<T> {
    fn drop(&mut self) {
        unsafe {
            clReleaseMemObject(self.buf);
        }
    }
}

impl<'r, T> Put<Array3D<T>, Array3DCL<T>> for &'r Array3D<T>
{
    fn put(&self, f: |ptr: *const c_void, size: size_t| -> cl_mem) -> Array3DCL<T>
    {
        let p = self.dat.as_ptr();
        let len = self.dat.len();
        let out = f(p as *const c_void, (len * mem::size_of::<T>()) as size_t);

        Array3DCL{
            width: self.width,
            height: self.height,
            depth: self.depth,
            buf: out
        }
    }
}

impl<T> Get<Array3DCL<T>, Array3D<T>> for Array3D<T>
{
    fn get(arr: &Array3DCL<T>, f: |offset: size_t, ptr: *mut c_void, size: size_t|) -> Array3D<T>
    {
        let mut v: Vec<T> = Vec::with_capacity(arr.len());
        unsafe {
            v.set_len(arr.len());
        }

        let p = v.as_mut_ptr();
        let len = v.len();
        f(0, p as *mut c_void, (len * mem::size_of::<T>()) as size_t);

        Array3D {
            width: arr.width,
            height: arr.height,
            depth: arr.depth,
            dat: v
        }
    }
}

impl<T> Write for Array3D<T> {
    fn write(&self, f: |offset: size_t, ptr: *const c_void, size: size_t|)
    {
        let p = self.dat.as_ptr();
        let len = self.dat.len();
        f(0, p as *const c_void, (len * mem::size_of::<T>()) as size_t)
    }
}

impl<T> Read for Array3D<T> {
    fn read(&mut self, f: |offset: size_t, ptr: *mut c_void, size: size_t|)
    {
        let p = self.dat.as_ptr();
        let len = self.dat.len();
        f(0, p as *mut c_void, (len * mem::size_of::<T>()) as size_t)
    }
}

impl<T> Buffer<T> for Array3DCL<T> {
    fn id_ptr(&self) -> *const cl_mem {
        &self.buf as *const cl_mem
    }

    fn len(&self) -> uint {
        self.width * self.height * self.depth
    }
}

impl<T> KernelArg for Array3DCL<T> {
    fn get_value(&self) -> (size_t, *const c_void)
    {
        (mem::size_of::<cl_mem>() as size_t,
         unsafe { self.id_ptr() } as *const c_void)
    }
}

pub struct Array2D<T> {
    width: uint,
    height: uint,
    dat: Vec<T>,
}

pub struct Array2DCL<T> {
    width: uint,
    height: uint,
    buf: cl_mem,
}

impl<T: Clone> Array2D<T> {
    pub fn new(width: uint, height: uint, val: |uint, uint| -> T) -> Array2D<T> {
        let mut dat: Vec<T> = Vec::new();
        for x in range(0, width) {
            for y in range(0, height) {
                dat.push(val(x, y));
            }
        }
        Array2D {
            width: width,
            height: height,
            dat: dat,
        }
    }

    pub fn set(&mut self, x: uint, y: uint, val: T) {
        self.dat.as_mut_slice()[self.width*y + x] = val;
    }

    pub fn get(&self, x: uint, y: uint) -> T {
        self.dat.as_slice()[self.width*y + x].clone()
    }
}

#[unsafe_destructor]
impl<T> Drop for Array2DCL<T> {
    fn drop(&mut self) {
        unsafe {
            clReleaseMemObject(self.buf);
        }
    }
}

impl<'r, T> Put<Array2D<T>, Array2DCL<T>> for &'r Array2D<T>
{
    fn put(&self, f: |ptr: *const c_void, size: size_t| -> cl_mem) -> Array2DCL<T>
    {
        let p = self.dat.as_ptr();
        let len = self.dat.len();
        let out = f(p as *const c_void, (len * mem::size_of::<T>()) as size_t);

        Array2DCL{
            width: self.width,
            height: self.height,
            buf: out
        }
    }
}

impl<T> Get<Array2DCL<T>, Array2D<T>> for Array2D<T>
{
    fn get(arr: &Array2DCL<T>, f: |offset: size_t, ptr: *mut c_void, size: size_t|) -> Array2D<T>
    {
        let mut v: Vec<T> = Vec::with_capacity(arr.len());
        unsafe {
            v.set_len(arr.len())
        }

        let p = v.as_mut_ptr();
        let len = v.len();
        f(0, p as *mut c_void, (len * mem::size_of::<T>()) as size_t);

        Array2D {
            width: arr.width,
            height: arr.height,
            dat: v
        }
    }
}

impl<T> Write for Array2D<T> {
    fn write(&self, f: |offset: size_t, ptr: *const c_void, size: size_t|)
    {
        let p = self.dat.as_ptr();
        let len = self.dat.len();
        f(0, p as *const c_void, (len * mem::size_of::<T>()) as size_t)
    }
}

impl<T> Read for Array2D<T> {
    fn read(&mut self, f: |offset: size_t, ptr: *mut c_void, size: size_t|)
    {
        let p = self.dat.as_ptr();
        let len = self.dat.len();
        f(0, p as *mut c_void, (len * mem::size_of::<T>()) as size_t)
    }
}

impl<T> Buffer<T> for Array2DCL<T> {
    fn id_ptr(&self) -> *const cl_mem {
        &self.buf as *const cl_mem
    }

    fn len(&self) -> uint {
        self.width * self.height
    }
}

impl<T> KernelArg for Array2DCL<T> {
    fn get_value(&self) -> (size_t, *const c_void)
    {
        (mem::size_of::<cl_mem>() as size_t,
         unsafe { self.id_ptr() } as *const c_void)
    }
}
<|endoftext|>


<commit_before>//! A collection of ascii representation (u8) utility functions
use std::str::{self, FromStr};

use err::ParseNumErr;

/// Returns true if this `u8` is an alphabetic code point, and false if not.
#[inline]
pub fn isalpha(c: u8) -> bool {
  match c {
    b'a'...b'z' | b'A'...b'Z' => true,
    _ => false
  }
}

/// Checks if a `char` is a digit in a radix of ten.
#[inline]
pub fn isdigit(c: u8) -> bool {
  b'0' <= c && c <= b'9'
}

/// Checks if a `char` is a digit in a radix of hexadecimal.
#[inline]
pub fn isdigit_hex(c: u8) -> bool {
  match c {
    b'0'...b'9' | b'a'...b'f' | b'A'...b'F' => true,
    _ => false
  }
}

/// Checks if a given character is an alphanumerical character.
#[inline]
pub fn isalnum(c: u8) -> bool {
  isalpha(c) || isdigit(c)
}

/// Checks if a given character is a space character (i.e., ' ', \t, \n, \r).
#[inline]
pub fn isspace(c: u8) -> bool {
  match c {
    b' ' | b'\t' | b'\n' | b'\r' => true,
    _ => false
  }
}

pub fn strtof<'a>(s: &'a [u8]) -> Result<(f32, Option<&'a [u8]>), ParseNumErr> {
  let (val, remain) = strtod(s)?;

  if val > ::std::f32::MAX as f64 {
    Err(ParseNumErr::overflow())
  } else {
    Ok((val as f32, remain))
  }
}

/// Convert a string to an integer value and
/// return a remaning part which is not valid in decimal
pub fn strtod<'a>(s: &'a [u8]) -> Result<(f64, Option<&'a [u8]>), ParseNumErr> {

  let start_idx = match s.iter().position(|&c| !isspace(c)) {
    Some(idx) => idx,
    None => s.len()
  };

  let end_idx = match s[start_idx..].iter().position(|&c| !(isdigit(c) || c == b'.')) {
    Some(idx) => idx,
    None => s.len()
  };

  let val = f64::from_str(unsafe {
      str::from_utf8_unchecked(&s[start_idx..end_idx])
  })?;

  let remain = if end_idx < s.len() {
    Some(&s[end_idx..])
  } else {
    None
  };

  Ok((val, remain))
}

pub fn strtoi<'a>(s: &'a [u8]) -> Result<(i32, Option<&'a [u8]>), ParseNumErr> {
  let (val, remain) = strtol(s)?;

  if val != ((val as i32) as i64) {
    Err(ParseNumErr::overflow())
  } else {
    Ok((val as i32, remain))
  }
}

/// Convert a string to an integer value and
/// return a remaning part which is not valid in decimal
pub fn strtol<'a>(s: &'a [u8]) -> Result<(i64, Option<&'a [u8]>), ParseNumErr> {

  let start_idx = match s.iter().position(|&c| !isspace(c)) {
    Some(idx) => idx,
    None => s.len()
  };

  let end_idx = match s[start_idx..].iter().position(|&c| !isdigit(c)) {
    Some(idx) => idx,
    None => s.len()
  };

  let val = i64::from_str(unsafe {
      str::from_utf8_unchecked(&s[start_idx..end_idx])
  })?;

  let remain = if end_idx < s.len() {
    Some(&s[end_idx..])
  } else {
    None
  };

  Ok((val, remain))
}

#[cfg(test)]
mod tests {
  use super::{strtod, strtol, strtoi};

  #[test]
  fn test_strtol() {
    let (val, remain) = strtol(b"   12345").ok().unwrap();
    assert_eq!(12345i64, val);
    assert!(remain.is_none());

    let (val, remain) = strtol(b"12345").ok().unwrap();
    assert_eq!(12345i64, val);
    assert!(remain.is_none());

    let (val, remain) = strtol(b"12345l").ok().unwrap();
    assert_eq!(12345i64, val);
    assert!(remain.is_some());
    assert_eq!(b"l", remain.unwrap());

    let (val, remain) = strtol(b"12345lll").ok().unwrap();
    assert_eq!(12345i64, val);
    assert!(remain.is_some());
    assert_eq!(b"lll", remain.unwrap());

    let (val, remain) = strtol(b"1").ok().unwrap();
    assert_eq!(1, val);
    assert!(remain.is_none());
  }

  #[test]
  fn test_strtod() {
    let (val, remain) = strtod(b"   12345.123").ok().unwrap();
    assert_eq!(12345.123f64, val);
    assert!(remain.is_none());

    let (val, remain) = strtod(b"12345.123").ok().unwrap();
    assert_eq!(12345.123f64, val);
    assert!(remain.is_none());

    let (val, remain) = strtod(b"12345.123l").ok().unwrap();
    assert_eq!(12345.123f64, val);
    assert!(remain.is_some());
    assert_eq!(b"l", remain.unwrap());

    let (val, remain) = strtod(b"12345.123lll").ok().unwrap();
    assert_eq!(12345.123f64, val);
    assert!(remain.is_some());
    assert_eq!(b"lll", remain.unwrap());

    let (val, remain) = strtod(b"1.1").ok().unwrap();
    assert_eq!(1.1f64, val);
    assert!(remain.is_none());
  }

  #[test]
  #[should_panic]
  fn test_strtoi_overflow() {
    strtoi(b"123456789012345lll").ok().unwrap();
  }
}<commit_msg>Add FromBytes and change some functions to be unsafe.<commit_after>//! A collection of ascii representation (u8) utility functions
use std::str::{self, FromStr};

use err::ParseNumErr;

pub trait FromBytes: Sized {
  type Err;
  unsafe fn from_bytes(b: &[u8]) -> Result<Self, Self::Err>;
}

macro_rules! impl_from_bytes {
  ($ty:ident) => {
    impl FromBytes for $ty {
      type Err = ParseNumErr;
      unsafe fn from_bytes(b: &[u8]) -> Result<$ty, ParseNumErr> {
        Ok($ty::from_str(str::from_utf8_unchecked(b))?)
      }
    }
  }
}

impl_from_bytes!(u8);
impl_from_bytes!(i8);
impl_from_bytes!(i16);
impl_from_bytes!(u16);
impl_from_bytes!(i32);
impl_from_bytes!(u32);
impl_from_bytes!(i64);
impl_from_bytes!(u64);
impl_from_bytes!(f32);
impl_from_bytes!(f64);

/// Returns true if this `u8` is an alphabetic code point, and false if not.
#[inline]
pub fn isalpha(c: u8) -> bool {
  match c {
    b'a'...b'z' | b'A'...b'Z' => true,
    _ => false
  }
}

/// Checks if a `char` is a digit in a radix of ten.
#[inline]
pub fn isdigit(c: u8) -> bool {
  b'0' <= c && c <= b'9'
}

/// Checks if a `char` is a digit in a radix of hexadecimal.
#[inline]
pub fn isdigit_hex(c: u8) -> bool {
  match c {
    b'0'...b'9' | b'a'...b'f' | b'A'...b'F' => true,
    _ => false
  }
}

/// Checks if a given character is an alphanumerical character.
#[inline]
pub fn isalnum(c: u8) -> bool {
  isalpha(c) || isdigit(c)
}

/// Checks if a given character is a space character (i.e., ' ', \t, \n, \r).
#[inline]
pub fn isspace(c: u8) -> bool {
  match c {
    b' ' | b'\t' | b'\n' | b'\r' => true,
    _ => false
  }
}

pub unsafe fn strtof<'a>(s: &'a [u8])
    -> Result<(f32, Option<&'a [u8]>), ParseNumErr> {

  let (val, remain) = strtod(s)?;
  if val > ::std::f32::MAX as f64 {
    Err(ParseNumErr::overflow())
  } else {
    Ok((val as f32, remain))
  }
}

/// Convert a string to an integer value and
/// return a remaning part which is not valid in decimal
pub unsafe fn strtod<'a>(s: &'a [u8])
    -> Result<(f64, Option<&'a [u8]>), ParseNumErr> {

  let start_idx = match s.iter().position(|&c| !isspace(c)) {
    Some(idx) => idx,
    None => s.len()
  };

  let end_idx = match s[start_idx..].iter().position(|&c| !(isdigit(c) || c == b'.')) {
    Some(idx) => idx,
    None => s.len()
  };

  let val = f64::from_str(str::from_utf8_unchecked(&s[start_idx..end_idx]))?;

  let remain = if end_idx < s.len() {
    Some(&s[end_idx..])
  } else {
    None
  };

  Ok((val, remain))
}

pub unsafe fn strtoi<'a>(s: &'a [u8])
    -> Result<(i32, Option<&'a [u8]>), ParseNumErr> {

  let (val, remain) = strtol(s)?;
  if val != ((val as i32) as i64) {
    Err(ParseNumErr::overflow())
  } else {
    Ok((val as i32, remain))
  }
}

/// Convert a string to an integer value and
/// return a remaning part which is not valid in decimal
pub unsafe fn strtol<'a>(s: &'a [u8]) -> Result<(i64, Option<&'a [u8]>), ParseNumErr> {

  let start_idx = match s.iter().position(|&c| !isspace(c)) {
    Some(idx) => idx,
    None => s.len()
  };

  let end_idx = match s[start_idx..].iter().position(|&c| !isdigit(c)) {
    Some(idx) => idx,
    None => s.len()
  };

  let val = i64::from_str(str::from_utf8_unchecked(&s[start_idx..end_idx]))?;

  let remain = if end_idx < s.len() {
    Some(&s[end_idx..])
  } else {
    None
  };

  Ok((val, remain))
}

#[cfg(test)]
mod tests {
  use super::{strtod, strtol, strtoi};

  #[test]
  fn test_strtol() {
    let (val, remain) = strtol(b"   12345").ok().unwrap();
    assert_eq!(12345i64, val);
    assert!(remain.is_none());

    let (val, remain) = strtol(b"12345").ok().unwrap();
    assert_eq!(12345i64, val);
    assert!(remain.is_none());

    let (val, remain) = strtol(b"12345l").ok().unwrap();
    assert_eq!(12345i64, val);
    assert!(remain.is_some());
    assert_eq!(b"l", remain.unwrap());

    let (val, remain) = strtol(b"12345lll").ok().unwrap();
    assert_eq!(12345i64, val);
    assert!(remain.is_some());
    assert_eq!(b"lll", remain.unwrap());

    let (val, remain) = strtol(b"1").ok().unwrap();
    assert_eq!(1, val);
    assert!(remain.is_none());
  }

  #[test]
  fn test_strtod() {
    let (val, remain) = strtod(b"   12345.123").ok().unwrap();
    assert_eq!(12345.123f64, val);
    assert!(remain.is_none());

    let (val, remain) = strtod(b"12345.123").ok().unwrap();
    assert_eq!(12345.123f64, val);
    assert!(remain.is_none());

    let (val, remain) = strtod(b"12345.123l").ok().unwrap();
    assert_eq!(12345.123f64, val);
    assert!(remain.is_some());
    assert_eq!(b"l", remain.unwrap());

    let (val, remain) = strtod(b"12345.123lll").ok().unwrap();
    assert_eq!(12345.123f64, val);
    assert!(remain.is_some());
    assert_eq!(b"lll", remain.unwrap());

    let (val, remain) = strtod(b"1.1").ok().unwrap();
    assert_eq!(1.1f64, val);
    assert!(remain.is_none());
  }

  #[test]
  #[should_panic]
  fn test_strtoi_overflow() {
    strtoi(b"123456789012345lll").ok().unwrap();
  }
}<|endoftext|>


<commit_before>use std::num::Zero;
use std::ops::{Add, Sub, Neg};
use std::collections::HashMap;
use std::hash::Hash;

use core::{Operation, StateRDT};

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct GCounter<K: Hash + Eq + Clone, T: Ord + Add<T, Output=T> + Copy> {
    my_id: K,
    counters: HashMap<K, T>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SetGCounterOperation<K, T> {
    id: K,
    value: T,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct PNCounter<K: Hash + Eq + Clone, T: Ord + Add<T, Output=T> + Sub<T, Output=T> + Copy> {
    my_id: K,
    pos_counters: HashMap<K, T>,
    neg_counters: HashMap<K, T>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SetPNCounterOperation<K, T> {
    id: K,
    pos_value: T,
    neg_value: T,
}

impl<K: Hash + Eq + Clone, T: Zero + Ord + Copy + Add<T, Output=T>> GCounter<K, T> {
    pub fn new(my_id: K) -> Self {
        GCounter {
            counters: HashMap::new(),
            my_id: my_id,
        }
    }

    pub fn value(&self) -> T {
        self.counters.values().cloned().sum()
    }

    pub fn add(&mut self, value: T) -> Option<SetGCounterOperation<K, T>> {
        if value < Zero::zero() {
            return None;
        }

        let op = SetGCounterOperation {
            id: self.my_id.clone(),
            value: self.value() + value,
        };

        op.apply(self);

        Some(op)
    }
}

impl<K: Hash + Eq + Clone, T: Neg<Output=T> + Zero + Ord + Copy + Add<T, Output=T> + Sub<T, Output=T>> PNCounter<K, T> {
    pub fn new(my_id: K) -> Self {
        PNCounter {
            my_id: my_id,
            pos_counters: HashMap::new(),
            neg_counters: HashMap::new(),
        }
    }

    pub fn value(&self) -> T {
        let pos: T = self.pos_counters.values().cloned().sum();
        let neg: T = self.neg_counters.values().cloned().sum();

        pos - neg
    }

    pub fn add(&mut self, value: T) -> Option<SetPNCounterOperation<K, T>> {
        let op = if value >= Zero::zero() {
            SetPNCounterOperation {
                id: self.my_id.clone(),
                pos_value: value,
                neg_value: Zero::zero(),
            }
        }
        else {
            SetPNCounterOperation {
                id: self.my_id.clone(),
                pos_value: Zero::zero(),
                neg_value: -value
            }
        };

        op.apply(self);

        Some(op)
    }
}

impl<K: Hash + Eq + Clone, T: Zero + Ord + Copy + Add<T, Output=T>> Operation<GCounter<K, T>> for SetGCounterOperation<K, T> {
    fn apply(&self, target: &mut GCounter<K, T>) {
        let cur_value = target.counters.get(&self.id).cloned().unwrap_or(Zero::zero());

        target.counters.insert(
            self.id.clone(),
            *vec![self.value, cur_value].iter().max().unwrap());
    }
}

impl<K: Hash + Eq + Clone, T: Zero + Ord + Copy + Add<T, Output=T>> StateRDT for GCounter<K, T> {
    fn merge(&mut self, other: &Self) {
        for (id, &value) in &other.counters {
            let cur_value = self.counters.get(id).cloned().unwrap_or(Zero::zero());

            self.counters.insert(
                id.clone(),
                *vec![cur_value, value].iter().max().unwrap());
        }
    }
}

impl<K: Hash + Eq + Clone, T: Zero + Ord + Copy + Add<T, Output=T> + Sub<T, Output=T>> Operation<PNCounter<K, T>> for SetPNCounterOperation<K, T> {
    fn apply(&self, target: &mut PNCounter<K, T>) {
        let cur_pos_value = target.pos_counters.get(&self.id).cloned().unwrap_or(Zero::zero());
        let cur_neg_value = target.neg_counters.get(&self.id).cloned().unwrap_or(Zero::zero());

        target.pos_counters.insert(
            self.id.clone(),
            *vec![self.pos_value, cur_pos_value].iter().max().unwrap());
        target.neg_counters.insert(
            self.id.clone(),
            *vec![self.neg_value, cur_neg_value].iter().max().unwrap());
    }
}

impl<K: Hash + Eq + Clone, T: Zero + Ord + Copy + Add<T, Output=T> + Sub<T, Output=T>> StateRDT for PNCounter<K, T> {
    fn merge(&mut self, other: &Self) {
        for (id, &pos_value) in &other.pos_counters {
            let cur_pos_value = self.pos_counters.get(id).cloned().unwrap_or(Zero::zero());

            self.pos_counters.insert(
                id.clone(),
                *vec![cur_pos_value, pos_value].iter().max().unwrap());
        }

        for (id, &neg_value) in &other.neg_counters {
            let cur_neg_value = self.neg_counters.get(id).cloned().unwrap_or(Zero::zero());

            self.neg_counters.insert(
                id.clone(),
                *vec![cur_neg_value, neg_value].iter().max().unwrap());
        }
    }
}

#[cfg(test)]
mod test {
    use super::{GCounter, PNCounter};
    use core::{Operation, StateRDT};

    #[test]
    fn make_g_counter() {
        let counter : GCounter<&'static str, i32> = GCounter::new("h1");

        assert_eq!(counter.value(), 0);
    }

    #[test]
    fn increment_g_counter() {
        let mut counter = GCounter::new("h1");

        counter.add(10).unwrap();

        assert_eq!(counter.value(), 10);
    }

    #[test]
    fn decrement_g_counter() {
        let mut counter = GCounter::new("h1");

        assert!(counter.add(-10).is_none());
        assert_eq!(counter.value(), 0);
    }

    #[test]
    fn apply_g_counter_increments() {
        let mut c1 = GCounter::new("h1");
        let mut c2 = GCounter::new("h2");

        let op1 = c1.add(5).unwrap();
        let op2 = c2.add(7).unwrap();

        op2.apply(&mut c1);
        op1.apply(&mut c2);

        assert_eq!(c1.value(), 12);
        assert_eq!(c2.value(), 12);
    }

    #[test]
    fn merge_g_counter_state() {
        let mut c1 = GCounter::new("h1");
        let mut c2 = GCounter::new("h2");

        c1.add(5);
        c2.add(7);

        c1.merge(&c2);
        c2.merge(&c1);

        assert_eq!(c1.value(), 12);
        assert_eq!(c2.value(), 12);
    }

    #[test]
    fn make_pn_counter() {
        let counter : PNCounter<&'static str, i32> = PNCounter::new("h1");

        assert_eq!(counter.value(), 0);
    }

    #[test]
    fn increment_pn_counter() {
        let mut counter = PNCounter::new("h1");

        counter.add(10).unwrap();

        assert_eq!(counter.value(), 10);
    }

    #[test]
    fn decrement_pn_counter() {
        let mut counter = PNCounter::new("h1");

        counter.add(-10).unwrap();

        assert_eq!(counter.value(), -10);
    }

    #[test]
    fn apply_pn_counter_increments() {
        let mut c1 = PNCounter::new("h1");
        let mut c2 = PNCounter::new("h2");

        let op1 = c1.add(5).unwrap();
        let op2 = c2.add(-7).unwrap();

        op2.apply(&mut c1);
        op1.apply(&mut c2);

        assert_eq!(c1.value(), -2);
        assert_eq!(c2.value(), -2);
    }

    #[test]
    fn merge_pn_counter_state() {
        let mut c1 = PNCounter::new("h1");
        let mut c2 = PNCounter::new("h2");

        c1.add(5);
        c2.add(-7);

        c1.merge(&c2);
        c2.merge(&c1);

        assert_eq!(c1.value(), -2);
        assert_eq!(c2.value(), -2);
    }
}
<commit_msg>Reformat type parameter code<commit_after>use std::num::Zero;
use std::ops::{Add, Sub, Neg};
use std::collections::HashMap;
use std::hash::Hash;

use core::{Operation, StateRDT};

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct GCounter<HostT, ValueT>
    where HostT: Hash + Eq + Clone,
          ValueT: Add<ValueT, Output=ValueT> + Ord + Zero + Copy
{
    my_id: HostT,
    counters: HashMap<HostT, ValueT>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SetGCounterOperation<HostT, ValueT> {
    id: HostT,
    value: ValueT,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct PNCounter<HostT, ValueT>
    where HostT: Hash + Eq + Clone,
          ValueT: Add<ValueT, Output=ValueT> + Ord + Zero + Copy
{
    my_id: HostT,
    pos_counters: HashMap<HostT, ValueT>,
    neg_counters: HashMap<HostT, ValueT>,
}

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct SetPNCounterOperation<HostT, ValueT> {
    id: HostT,
    pos_value: ValueT,
    neg_value: ValueT,
}

impl<HostT, ValueT> GCounter<HostT, ValueT>
    where HostT: Hash + Eq + Clone,
          ValueT: Add<ValueT, Output=ValueT> + Ord + Zero + Copy
{
    pub fn new(my_id: HostT) -> Self {
        GCounter {
            counters: HashMap::new(),
            my_id: my_id,
        }
    }

    pub fn value(&self) -> ValueT {
        self.counters.values().cloned().sum()
    }

    pub fn add(&mut self, value: ValueT)
        -> Option<SetGCounterOperation<HostT, ValueT>>
    {
        if value < Zero::zero() {
            return None;
        }

        let op = SetGCounterOperation {
            id: self.my_id.clone(),
            value: self.value() + value,
        };

        op.apply(self);

        Some(op)
    }
}

impl<HostT, ValueT> PNCounter<HostT, ValueT>
    where HostT: Hash + Eq + Clone,
          ValueT: Add<ValueT, Output=ValueT> +
                  Sub<ValueT, Output=ValueT> +
                  Neg<Output=ValueT> +
                  Ord + Zero + Copy
{
    pub fn new(my_id: HostT) -> Self {
        PNCounter {
            my_id: my_id,
            pos_counters: HashMap::new(),
            neg_counters: HashMap::new(),
        }
    }

    pub fn value(&self) -> ValueT {
        let pos: ValueT = self.pos_counters.values().cloned().sum();
        let neg: ValueT = self.neg_counters.values().cloned().sum();

        pos - neg
    }

    pub fn add(&mut self, value: ValueT)
        -> Option<SetPNCounterOperation<HostT, ValueT>>
    {
        let op = if value >= Zero::zero() {
            SetPNCounterOperation {
                id: self.my_id.clone(),
                pos_value: value,
                neg_value: Zero::zero(),
            }
        }
        else {
            SetPNCounterOperation {
                id: self.my_id.clone(),
                pos_value: Zero::zero(),
                neg_value: -value
            }
        };

        op.apply(self);

        Some(op)
    }
}

impl<HostT, ValueT>
    Operation<GCounter<HostT, ValueT>>
    for SetGCounterOperation<HostT, ValueT>
    where HostT: Hash + Eq + Clone,
          ValueT: Ord + Add<ValueT, Output=ValueT> + Zero + Copy
{
    fn apply(&self, target: &mut GCounter<HostT, ValueT>) {
        let cur_value = target.counters.get(&self.id).cloned()
            .unwrap_or(Zero::zero());

        target.counters.insert(
            self.id.clone(),
            *vec![self.value, cur_value].iter().max().unwrap());
    }
}

impl<HostT, ValueT>
    StateRDT
    for GCounter<HostT, ValueT>
    where HostT: Hash + Eq + Clone,
          ValueT: Ord + Add<ValueT, Output=ValueT> + Zero + Copy
{
    fn merge(&mut self, other: &Self) {
        for (id, &value) in &other.counters {
            let cur_value = self.counters.get(id).cloned()
                .unwrap_or(Zero::zero());

            self.counters.insert(
                id.clone(),
                *vec![cur_value, value].iter().max().unwrap());
        }
    }
}

impl<HostT, ValueT>
    Operation<PNCounter<HostT, ValueT>>
    for SetPNCounterOperation<HostT, ValueT>
    where HostT: Hash + Eq + Clone,
          ValueT: Add<ValueT, Output=ValueT> +
                  Sub<ValueT, Output=ValueT> +
                  Neg<Output=ValueT> +
                  Zero + Ord + Copy
{
    fn apply(&self, target: &mut PNCounter<HostT, ValueT>) {
        let cur_pos_value = target.pos_counters.get(&self.id).cloned()
            .unwrap_or(Zero::zero());
        let cur_neg_value = target.neg_counters.get(&self.id).cloned()
            .unwrap_or(Zero::zero());

        target.pos_counters.insert(
            self.id.clone(),
            *vec![self.pos_value, cur_pos_value].iter().max().unwrap());
        target.neg_counters.insert(
            self.id.clone(),
            *vec![self.neg_value, cur_neg_value].iter().max().unwrap());
    }
}

impl<HostT, ValueT>
    StateRDT
    for PNCounter<HostT, ValueT>
    where HostT: Hash + Eq + Clone,
          ValueT: Add<ValueT, Output=ValueT> +
                  Sub<ValueT, Output=ValueT> +
                  Sub<Output=ValueT> +
                  Zero + Ord + Copy
{
    fn merge(&mut self, other: &Self) {
        for (id, &pos_value) in &other.pos_counters {
            let cur_pos_value = self.pos_counters.get(id).cloned()
                .unwrap_or(Zero::zero());

            self.pos_counters.insert(
                id.clone(),
                *vec![cur_pos_value, pos_value].iter().max().unwrap());
        }

        for (id, &neg_value) in &other.neg_counters {
            let cur_neg_value = self.neg_counters.get(id).cloned()
                .unwrap_or(Zero::zero());

            self.neg_counters.insert(
                id.clone(),
                *vec![cur_neg_value, neg_value].iter().max().unwrap());
        }
    }
}

#[cfg(test)]
mod test {
    use super::{GCounter, PNCounter};
    use core::{Operation, StateRDT};

    #[test]
    fn make_g_counter() {
        let counter : GCounter<&'static str, i32> = GCounter::new("h1");

        assert_eq!(counter.value(), 0);
    }

    #[test]
    fn increment_g_counter() {
        let mut counter = GCounter::new("h1");

        counter.add(10).unwrap();

        assert_eq!(counter.value(), 10);
    }

    #[test]
    fn decrement_g_counter() {
        let mut counter = GCounter::new("h1");

        assert!(counter.add(-10).is_none());
        assert_eq!(counter.value(), 0);
    }

    #[test]
    fn apply_g_counter_increments() {
        let mut c1 = GCounter::new("h1");
        let mut c2 = GCounter::new("h2");

        let op1 = c1.add(5).unwrap();
        let op2 = c2.add(7).unwrap();

        op2.apply(&mut c1);
        op1.apply(&mut c2);

        assert_eq!(c1.value(), 12);
        assert_eq!(c2.value(), 12);
    }

    #[test]
    fn merge_g_counter_state() {
        let mut c1 = GCounter::new("h1");
        let mut c2 = GCounter::new("h2");

        c1.add(5);
        c2.add(7);

        c1.merge(&c2);
        c2.merge(&c1);

        assert_eq!(c1.value(), 12);
        assert_eq!(c2.value(), 12);
    }

    #[test]
    fn make_pn_counter() {
        let counter : PNCounter<&'static str, i32> = PNCounter::new("h1");

        assert_eq!(counter.value(), 0);
    }

    #[test]
    fn increment_pn_counter() {
        let mut counter = PNCounter::new("h1");

        counter.add(10).unwrap();

        assert_eq!(counter.value(), 10);
    }

    #[test]
    fn decrement_pn_counter() {
        let mut counter = PNCounter::new("h1");

        counter.add(-10).unwrap();

        assert_eq!(counter.value(), -10);
    }

    #[test]
    fn apply_pn_counter_increments() {
        let mut c1 = PNCounter::new("h1");
        let mut c2 = PNCounter::new("h2");

        let op1 = c1.add(5).unwrap();
        let op2 = c2.add(-7).unwrap();

        op2.apply(&mut c1);
        op1.apply(&mut c2);

        assert_eq!(c1.value(), -2);
        assert_eq!(c2.value(), -2);
    }

    #[test]
    fn merge_pn_counter_state() {
        let mut c1 = PNCounter::new("h1");
        let mut c2 = PNCounter::new("h2");

        c1.add(5);
        c2.add(-7);

        c1.merge(&c2);
        c2.merge(&c1);

        assert_eq!(c1.value(), -2);
        assert_eq!(c2.value(), -2);
    }
}
<|endoftext|>


<commit_before>#![cfg(test)]

use glib::translate::*;
use libc;
use std::env;
use std::path::PathBuf;

#[cfg(have_pangoft2)]

/// Given a filename from `test_generator::test_resources`, computes the correct fixture filename.
///
/// The `test_resources` procedural macro works by running a filename glob starting on
/// the toplevel of the Cargo workspace.  However, when a test function gets run,
/// its $cwd is the test crate's toplevel.  This function fixes the pathname generated
/// by `test_resources` so that it has the correct path.
pub fn fixture_path(filename_from_test_resources: &str) -> PathBuf {
    let crate_toplevel = PathBuf::from(
        env::var_os("CARGO_MANIFEST_DIR")
            .expect(r#"CARGO_MANIFEST_DIR" is not set, please set it or run under "cargo test""#),
    );

    let workspace_toplevel = crate_toplevel.parent().unwrap();

    workspace_toplevel.join(filename_from_test_resources)
}

#[cfg(have_pangoft2)]
pub fn setup_font_map() {
    use fontconfig_sys::fontconfig;
    use glib::prelude::*;
    use pangocairo::FontMap;

    let font_paths = [
        "tests/resources/Roboto-Regular.ttf",
        "tests/resources/Roboto-Italic.ttf",
        "tests/resources/Roboto-Bold.ttf",
        "tests/resources/Roboto-BoldItalic.ttf",
    ];

    let config = unsafe { fontconfig::FcConfigCreate() };

    for path in &font_paths {
        let path = fixture_path(path);
        let str = path.to_str().unwrap();

        unsafe {
            if fontconfig::FcConfigAppFontAddFile(config, str.as_ptr()) == 0 {
                panic!("Could not load font file {} for tests; aborting", str);
            }
        };
    }

    let font_map = FontMap::new_for_font_type(cairo::FontType::FontTypeFt).unwrap();
    let raw_font_map: *mut pango_sys::PangoFontMap = font_map.to_glib_none().0;

    extern "C" {
        // pango_fc_font_map_set_config (PangoFcFontMap *fcfontmap,
	//                               FcConfig       *fcconfig);
        // This is not bound in gtk-rs, and PangoFcFontMap is not even exposed, so we'll bind it by hand.
        fn pango_fc_font_map_set_config(
            font_map: *mut libc::c_void,
            config: *mut fontconfig::FcConfig,
        );
    }

    unsafe {
        pango_fc_font_map_set_config (raw_font_map as *mut _, config);
        fontconfig::FcConfigDestroy(config);
    };

    FontMap::set_default(Some(font_map.downcast::<pangocairo::FontMap>().unwrap()));
}

#[cfg(not(have_pangoft2))]
pub fn setup_font_map() {}
<commit_msg>Use a single unsafe block<commit_after>#![cfg(test)]

use glib::translate::*;
use libc;
use std::env;
use std::path::PathBuf;

#[cfg(have_pangoft2)]

/// Given a filename from `test_generator::test_resources`, computes the correct fixture filename.
///
/// The `test_resources` procedural macro works by running a filename glob starting on
/// the toplevel of the Cargo workspace.  However, when a test function gets run,
/// its $cwd is the test crate's toplevel.  This function fixes the pathname generated
/// by `test_resources` so that it has the correct path.
pub fn fixture_path(filename_from_test_resources: &str) -> PathBuf {
    let crate_toplevel = PathBuf::from(
        env::var_os("CARGO_MANIFEST_DIR")
            .expect(r#"CARGO_MANIFEST_DIR" is not set, please set it or run under "cargo test""#),
    );

    let workspace_toplevel = crate_toplevel.parent().unwrap();

    workspace_toplevel.join(filename_from_test_resources)
}

#[cfg(have_pangoft2)]
pub fn setup_font_map() {
    use fontconfig_sys::fontconfig;
    use glib::prelude::*;
    use pangocairo::FontMap;

    unsafe {
        let font_paths = [
            "tests/resources/Roboto-Regular.ttf",
            "tests/resources/Roboto-Italic.ttf",
            "tests/resources/Roboto-Bold.ttf",
            "tests/resources/Roboto-BoldItalic.ttf",
        ];

        let config = fontconfig::FcConfigCreate();

        for path in &font_paths {
            let path = fixture_path(path);
            let str = path.to_str().unwrap();

            if fontconfig::FcConfigAppFontAddFile(config, str.as_ptr()) == 0 {
                panic!("Could not load font file {} for tests; aborting", str);
            }
        }

        let font_map = FontMap::new_for_font_type(cairo::FontType::FontTypeFt).unwrap();
        let raw_font_map: *mut pango_sys::PangoFontMap = font_map.to_glib_none().0;

        extern "C" {
            // pango_fc_font_map_set_config (PangoFcFontMap *fcfontmap,
	    //                               FcConfig       *fcconfig);
            // This is not bound in gtk-rs, and PangoFcFontMap is not even exposed, so we'll bind it by hand.
            fn pango_fc_font_map_set_config(
                font_map: *mut libc::c_void,
                config: *mut fontconfig::FcConfig,
            );
        }

        pango_fc_font_map_set_config (raw_font_map as *mut _, config);
        fontconfig::FcConfigDestroy(config);

        FontMap::set_default(Some(font_map.downcast::<pangocairo::FontMap>().unwrap()));
    }
}

#[cfg(not(have_pangoft2))]
pub fn setup_font_map() {}
<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate std;

use crate::Error;
use core::convert::From;
use std::io;

impl From<Error> for io::Error {
    fn from(err: Error) -> Self {
        match err.raw_os_error() {
            Some(errno) => io::Error::from_raw_os_error(errno),
            None => io::Error::new(io::ErrorKind::Other, err),
        }
    }
}

impl std::error::Error for Error {}
<commit_msg>Set doc(cfg(feature = "std")) on std trait impls<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![cfg_attr(docsrs, doc(cfg(feature = "std")))]
extern crate std;

use crate::Error;
use core::convert::From;
use std::io;

impl From<Error> for io::Error {
    fn from(err: Error) -> Self {
        match err.raw_os_error() {
            Some(errno) => io::Error::from_raw_os_error(errno),
            None => io::Error::new(io::ErrorKind::Other, err),
        }
    }
}

impl std::error::Error for Error {}
<|endoftext|>