<commit_before>//
use std::fs::File;
use std::io::prelude::*;
//
pub type Id = u64;
pub type Offset = u64;
pub type PageSize = usize;

//
#[derive(Debug)]
pub enum OpenMode {
    ReadOnly = 0,
    ReadWrite = 1,
}

/// The **Buffer** represent a linear array of bytes.

/// it can be in memory only or backed by an on disk file.

/// The editor **Modes** use this api to read/modify the content
/// of the file at the byte level
#[derive(Debug)]
pub struct Buffer {
    pub id: Id,
    pub file_name: String,
    pub size: usize, // proxy to underlying structs
    pub nr_changes: u64, // number of changes since last save
    pub file: File, //
    mode: OpenMode, //
    pub data: Vec<u8>, // file bytes
}

impl Buffer {
    /// Creates a new `Buffer`.
    ///
    /// file_name param[in] path to the file we want to load in the buffer,
    /// use "/dev/null" to create empty buffer
    /// this function allocate a buffer
    /// if file_name is null the content will be stored in heap
    /// if file_name is non null the the content will be read from the file
    /// if document_name is null , file_name will be used to give a name to the buffer
    /// mode = 0 : read only , mode 1 : read_write
    /// the allocated_bid pointer will be filled on successfull open operation
    pub fn new(file_name: &String, mode: OpenMode) -> Option<Buffer> {

        // TODO: check permission
        let mut file = match File::open(file_name) {
            Ok(f) => f,
            Err(e) => {
                println!("cannot open '{}' : {}", file_name, e);
                return None;
            }
        };

        // TODO: check file's type => ignore directory (for now)

        let mut data = Vec::new();
        let size = file.read_to_end(&mut data).unwrap_or(0);

        println!("'{}' opened mode '{:?}' size '{}'", file_name, mode, size);
        /*
            for c in &data {
                println!("c {} char '{}' ", *c, *c as char);
            }
        */
        Some(Buffer {
                 id: 0,
                 file_name: file_name.clone(),
                 mode: mode,
                 size: size,
                 nr_changes: 0,
                 file: file,
                 data: data,
             })
    }

    /// close a previously opened buffer see buffer_open
    pub fn close(&mut self) -> bool {
        false
    }

    /// returns the name of the file associated to the buffer
    pub fn get_file_name(&self) -> String {
        self.file_name.clone()
    }

    /// change the on disk target file
    pub fn set_file_name(&mut self, name: String) -> bool {
        self.file_name = name;
        true
    }

    /// returns the number of bytes a given buffer contains
    pub fn size(&self) -> usize {
        self.size
    }

    /// returns the number of changes sine the last save

    ///     0  => the no change since last save

    ///     >0 => the number of changes since last save

    pub fn nr_changes(&self) -> u64 {
        self.nr_changes
    }

    /// copy the content of the buffer up to 'nr_bytes' into the data Vec
    /// the read bytes are appended to the data Vec
    /// return XXX on error (use ioresult)
    pub fn read(&self, offset: u64, nr_bytes: usize, data: &mut Vec<u8>) -> usize {
        let start_offset = ::std::cmp::min(offset as usize, self.size);
        let end_offset = ::std::cmp::min(start_offset + nr_bytes, self.size);
        let nr_copied = (end_offset - start_offset) as usize;
        data.reserve(nr_copied);
        for b in &self.data[start_offset..end_offset] {
            data.push(*b);
        }
        nr_copied
    }

    /// insert the 'data' Vec content in the buffer up to 'nr_bytes'
    /// return the number of written bytes (TODO: use io::Result)
    pub fn write(&mut self, offset: u64, nr_bytes: usize, data: &Vec<u8>) -> usize {

        let index = offset as usize;
        for n in 0..nr_bytes {
            self.data.insert(index + n, data[n]);
        }
        self.size += nr_bytes;

        nr_bytes
    }

    /// remove up to 'nr_bytes' from the buffer starting at offset
    /// if removed_data is provided will call self.read(offset, nr_bytes, data)
    /// before remove the bytes
    pub fn remove(&mut self,
                  offset: u64,
                  nr_bytes: usize,
                  removed_data: Option<&mut Vec<u8>>)
                  -> usize {

        let start_offset = ::std::cmp::min(offset as usize, self.size);
        let end_offset = ::std::cmp::min(start_offset + nr_bytes, self.size);
        let nr_bytes_removed = (end_offset - start_offset) as usize;

        // copy removed data
        if let Some(v) = removed_data {
            self.read(offset, nr_bytes_removed, v);
        }

        self.data.drain(start_offset..end_offset);
        self.size -= nr_bytes_removed;

        nr_bytes_removed
    }

    /// can be used to know the number of blocks that compose the buffer,
    /// api to be used by indexer etc...
    pub fn nr_pages(&self) -> u64 {
        1
    }

    /// returns the position and size of a given page
    pub fn get_page_info(&self, page_index: u64) -> (Offset, PageSize) {
        if page_index > 0 {
            (0, self.size)
        } else {
            (0, self.size)
        }
    }
}

#[test]
fn test_buffer() {
    let mut bb = Buffer::new(&"/dev/null".to_owned(), OpenMode::ReadWrite).unwrap();

    let data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

    bb.write(0, 10, &data);
    assert_eq!(bb.data, data);
    assert_eq!(data.len(), bb.size());

    let mut rdata = Vec::new();

    let nread = bb.read(0, bb.size(), &mut rdata);
    assert_eq!(rdata, data);
    assert_eq!(nread, bb.size());

    let data = vec![0, 1, 2, 6, 7, 8, 9];
    let mut rm = vec![];
    let n = bb.remove(3, 3, Some(&mut rm));
    assert_eq!(n, 3);
    assert_eq!(bb.data, data);
    let rm_expect = vec![3, 4, 5];
    assert_eq!(rm, rm_expect);
    println!("rm {:?}", rm);
    println!("rm_expect {:?}", rm_expect);
}
<commit_msg>buffer : update the change count<commit_after>//
use std::fs::File;
use std::io::prelude::*;
//
pub type Id = u64;
pub type Offset = u64;
pub type PageSize = usize;

//
#[derive(Debug)]
pub enum OpenMode {
    ReadOnly = 0,
    ReadWrite = 1,
}

/// The **Buffer** represent a linear array of bytes.

/// it can be in memory only or backed by an on disk file.

/// The editor **Modes** use this api to read/modify the content
/// of the file at the byte level
#[derive(Debug)]
pub struct Buffer {
    pub id: Id,
    pub file_name: String,
    pub size: usize, // proxy to underlying structs
    pub nr_changes: u64, // number of changes since last save
    pub file: File, //
    mode: OpenMode, //
    pub data: Vec<u8>, // file bytes
}

impl Buffer {
    /// Creates a new `Buffer`.
    ///
    /// file_name param[in] path to the file we want to load in the buffer,
    /// use "/dev/null" to create empty buffer
    /// this function allocate a buffer
    /// if file_name is null the content will be stored in heap
    /// if file_name is non null the the content will be read from the file
    /// if document_name is null , file_name will be used to give a name to the buffer
    /// mode = 0 : read only , mode 1 : read_write
    /// the allocated_bid pointer will be filled on successfull open operation
    pub fn new(file_name: &String, mode: OpenMode) -> Option<Buffer> {

        // TODO: check permission
        let mut file = match File::open(file_name) {
            Ok(f) => f,
            Err(e) => {
                println!("cannot open '{}' : {}", file_name, e);
                return None;
            }
        };

        // TODO: check file's type => ignore directory (for now)

        let mut data = Vec::new();
        let size = file.read_to_end(&mut data).unwrap_or(0);

        println!("'{}' opened mode '{:?}' size '{}'", file_name, mode, size);
        /*
            for c in &data {
                println!("c {} char '{}' ", *c, *c as char);
            }
        */
        Some(Buffer {
                 id: 0,
                 file_name: file_name.clone(),
                 mode: mode,
                 size: size,
                 nr_changes: 0,
                 file: file,
                 data: data,
             })
    }

    /// close a previously opened buffer see buffer_open
    pub fn close(&mut self) -> bool {
        false
    }

    /// returns the name of the file associated to the buffer
    pub fn get_file_name(&self) -> String {
        self.file_name.clone()
    }

    /// change the on disk target file
    pub fn set_file_name(&mut self, name: String) -> bool {
        self.file_name = name;
        true
    }

    /// returns the number of bytes a given buffer contains
    pub fn size(&self) -> usize {
        self.size
    }

    /// returns the number of changes sine the last save

    ///     0  => the no change since last save

    ///     >0 => the number of changes since last save

    pub fn nr_changes(&self) -> u64 {
        self.nr_changes
    }

    /// copy the content of the buffer up to 'nr_bytes' into the data Vec
    /// the read bytes are appended to the data Vec
    /// return XXX on error (use ioresult)
    pub fn read(&self, offset: u64, nr_bytes: usize, data: &mut Vec<u8>) -> usize {
        let start_offset = ::std::cmp::min(offset as usize, self.size);
        let end_offset = ::std::cmp::min(start_offset + nr_bytes, self.size);
        let nr_copied = (end_offset - start_offset) as usize;
        data.reserve(nr_copied);
        for b in &self.data[start_offset..end_offset] {
            data.push(*b);
        }
        nr_copied
    }

    /// insert the 'data' Vec content in the buffer up to 'nr_bytes'
    /// return the number of written bytes (TODO: use io::Result)
    pub fn write(&mut self, offset: u64, nr_bytes: usize, data: &Vec<u8>) -> usize {

        let index = offset as usize;
        for n in 0..nr_bytes {
            self.data.insert(index + n, data[n]);
        }
        self.size += nr_bytes;
        self.nr_changes += 1;

        nr_bytes
    }

    /// remove up to 'nr_bytes' from the buffer starting at offset
    /// if removed_data is provided will call self.read(offset, nr_bytes, data)
    /// before remove the bytes
    pub fn remove(&mut self,
                  offset: u64,
                  nr_bytes: usize,
                  removed_data: Option<&mut Vec<u8>>)
                  -> usize {

        let start_offset = ::std::cmp::min(offset as usize, self.size);
        let end_offset = ::std::cmp::min(start_offset + nr_bytes, self.size);
        let nr_bytes_removed = (end_offset - start_offset) as usize;

        // copy removed data
        if let Some(v) = removed_data {
            self.read(offset, nr_bytes_removed, v);
        }

        self.data.drain(start_offset..end_offset);
        self.size -= nr_bytes_removed;
        self.nr_changes += 1;

        nr_bytes_removed
    }

    /// can be used to know the number of blocks that compose the buffer,
    /// api to be used by indexer etc...
    pub fn nr_pages(&self) -> u64 {
        1
    }

    /// returns the position and size of a given page
    pub fn get_page_info(&self, page_index: u64) -> (Offset, PageSize) {
        if page_index > 0 {
            (0, self.size)
        } else {
            (0, self.size)
        }
    }
}

#[test]
fn test_buffer() {
    let mut bb = Buffer::new(&"/dev/null".to_owned(), OpenMode::ReadWrite).unwrap();

    let data = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

    bb.write(0, 10, &data);
    assert_eq!(bb.data, data);
    assert_eq!(data.len(), bb.size());

    let mut rdata = Vec::new();

    let nread = bb.read(0, bb.size(), &mut rdata);
    assert_eq!(rdata, data);
    assert_eq!(nread, bb.size());

    let data = vec![0, 1, 2, 6, 7, 8, 9];
    let mut rm = vec![];
    let n = bb.remove(3, 3, Some(&mut rm));
    assert_eq!(n, 3);
    assert_eq!(bb.data, data);
    let rm_expect = vec![3, 4, 5];
    assert_eq!(rm, rm_expect);
    println!("rm {:?}", rm);
    println!("rm_expect {:?}", rm_expect);
}
<|endoftext|>


<commit_before>use super::defines::AfError;
use super::error::HANDLE_ERROR;
use super::util::free_host;

use libc::{c_char, c_int, size_t};
use std::borrow::Cow;
use std::ffi::{CStr, CString};

extern "C" {
    fn af_get_version(major: *mut c_int, minor: *mut c_int, patch: *mut c_int) -> c_int;
    fn af_get_revision() -> *const c_char;
    fn af_info() -> c_int;
    fn af_info_string(str: *mut *mut c_char, verbose: bool) -> c_int;
    fn af_device_info(
        d_name: *mut c_char,
        d_platform: *mut c_char,
        d_toolkit: *mut c_char,
        d_compute: *mut c_char,
    ) -> c_int;
    fn af_init() -> c_int;
    fn af_get_device_count(nDevices: *mut c_int) -> c_int;
    fn af_get_dbl_support(available: *mut c_int, device: c_int) -> c_int;
    fn af_set_device(device: c_int) -> c_int;
    fn af_get_device(device: *mut c_int) -> c_int;
    fn af_device_mem_info(
        alloc_bytes: *mut size_t,
        alloc_buffers: *mut size_t,
        lock_bytes: *mut size_t,
        lock_buffers: *mut size_t,
    ) -> c_int;
    fn af_print_mem_info(msg: *const c_char, device_id: c_int) -> c_int;
    fn af_set_mem_step_size(step_bytes: size_t) -> c_int;
    fn af_get_mem_step_size(step_bytes: *mut size_t) -> c_int;
    fn af_device_gc() -> c_int;
    fn af_sync(device: c_int) -> c_int;
}

/// Get ArrayFire Version Number
///
/// # Return Values
/// A triplet of integers indicating major, minor & fix release version numbers.
pub fn get_version() -> (i32, i32, i32) {
    unsafe {
        let mut maj: i32 = 0;
        let mut min: i32 = 0;
        let mut pat: i32 = 0;
        let err_val = af_get_version(
            &mut maj as *mut c_int,
            &mut min as *mut c_int,
            &mut pat as *mut c_int,
        );
        HANDLE_ERROR(AfError::from(err_val));
        (maj, min, pat)
    }
}

/// Get ArrayFire Revision (commit) information of the library.
///
/// # Return Values
/// This returns a `Cow<'static, str>` as the string is constructed at compile time.
pub fn get_revision() -> Cow<'static, str> {
    unsafe { CStr::from_ptr(af_get_revision()).to_string_lossy() }
}

/// Print library meta-info
///
/// # Examples
///
/// An example output of `af::info` call looks like below
///
/// ```text
/// ArrayFire v3.0.0 (CUDA, 64-bit Mac OSX, build d8d4b38)
/// Platform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000
/// [0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0
/// ```
pub fn info() {
    unsafe {
        let err_val = af_info();
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Return library meta-info as `String`
///
/// # Examples
///
/// An example output of `af::info_string` call looks like below
///
/// ```text
/// ArrayFire v3.0.0 (CUDA, 64-bit Mac OSX, build d8d4b38)
/// Platform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000
/// [0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0
/// ```
pub fn info_string(verbose: bool) -> String {
    let result: String;
    unsafe {
        let mut tmp: *mut c_char = ::std::ptr::null_mut();
        let err_val = af_info_string(&mut tmp, verbose);
        HANDLE_ERROR(AfError::from(err_val));
        result = CStr::from_ptr(tmp).to_string_lossy().into_owned();
        free_host(tmp);
    }
    result
}

/// Gets the information about device and platform as strings.
///
/// # Return Values
/// A tuple of `String` indicating the name, platform, toolkit and compute.
pub fn device_info() -> (String, String, String, String) {
    let mut name = [0 as c_char; 64];
    let mut platform = [0 as c_char; 10];
    let mut toolkit = [0 as c_char; 64];
    let mut compute = [0 as c_char; 10];
    unsafe {
        let err_val = af_device_info(
            &mut name[0],
            &mut platform[0],
            &mut toolkit[0],
            &mut compute[0],
        );
        HANDLE_ERROR(AfError::from(err_val));
        (
            CStr::from_ptr(name.as_mut_ptr())
                .to_string_lossy()
                .into_owned(),
            CStr::from_ptr(platform.as_mut_ptr())
                .to_string_lossy()
                .into_owned(),
            CStr::from_ptr(toolkit.as_mut_ptr())
                .to_string_lossy()
                .into_owned(),
            CStr::from_ptr(compute.as_mut_ptr())
                .to_string_lossy()
                .into_owned(),
        )
    }
}

/// Initialize ArrayFire library
///
/// 0th device will be the default device unless init call
/// is followed by set_device
pub fn init() {
    unsafe {
        let err_val = af_init();
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Get total number of available devices
pub fn device_count() -> i32 {
    unsafe {
        let mut temp: i32 = 0;
        let err_val = af_get_device_count(&mut temp as *mut c_int);
        HANDLE_ERROR(AfError::from(err_val));
        temp
    }
}

/// Check if a device has double support
///
/// # Parameters
///
/// - `device` is the device for which double support is checked for
///
/// # Return Values
///
/// `True` if `device` device has double support, `False` otherwise.
pub fn is_double_available(device: i32) -> bool {
    unsafe {
        let mut temp: i32 = 0;
        let err_val = af_get_dbl_support(&mut temp as *mut c_int, device as c_int);
        HANDLE_ERROR(AfError::from(err_val));
        temp > 0
    }
}

/// Set active device
///
/// # Parameters
///
/// - `device` is the value of the device identifier which has to be set as active
pub fn set_device(device: i32) {
    unsafe {
        let err_val = af_set_device(device as c_int);
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Get the current active device id
pub fn get_device() -> i32 {
    unsafe {
        let mut temp: i32 = 0;
        let err_val = af_get_device(&mut temp as *mut c_int);
        HANDLE_ERROR(AfError::from(err_val));
        temp
    }
}

/// Get memory information from the memory manager for the current active device
///
/// # Parameters
///
/// This function doesn't take any input parameters
///
/// # Return Values
///
/// A quadruple of values regarding the following information.
///
/// * Number of bytes allocated
/// * Number of buffers allocated
/// * Number of bytes locked
/// * Number of buffers locked
pub fn device_mem_info() -> (usize, usize, usize, usize) {
    unsafe {
        let mut o0: usize = 0;
        let mut o1: usize = 0;
        let mut o2: usize = 0;
        let mut o3: usize = 0;
        let err_val = af_device_mem_info(
            &mut o0 as *mut size_t,
            &mut o1 as *mut size_t,
            &mut o2 as *mut size_t,
            &mut o3 as *mut size_t,
        );
        HANDLE_ERROR(AfError::from(err_val));
        (o0, o1, o2, o3)
    }
}

/// Print buffer details from the ArrayFire device manager
///
/// This information is printed in the form of a table.
///
/// # Parameters
///
/// - `msg` is a message to print before the table
/// - `device` is the id of the device for which buffer details are to be printed
///
/// # Return Values
///
/// None
pub fn print_mem_info(msg: String, device: i32) {
    unsafe {
        let cmsg = CString::new(msg.as_bytes());
        match cmsg {
            Ok(v) => {
                let err_val = af_print_mem_info(
                    v.to_bytes_with_nul().as_ptr() as *const c_char,
                    device as c_int,
                );
                HANDLE_ERROR(AfError::from(err_val));
            }
            Err(_) => HANDLE_ERROR(AfError::ERR_INTERNAL),
        }
    }
}

/// Set the minimum memory chunk size
///
/// # Parameters
///
/// - `step_bytes` is the size of minimum memory chunk in bytes
///
/// # Return Values
///
/// None
pub fn set_mem_step_size(step_bytes: usize) {
    unsafe {
        let err_val = af_set_mem_step_size(step_bytes as size_t);
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Get the minimum memory chunk size
///
/// # Parameters
///
/// None
///
/// # Return Values
///
/// Returns is the size of minimum memory chunk in bytes
pub fn get_mem_step_size() -> usize {
    unsafe {
        let mut temp: usize = 0;
        let err_val = af_get_mem_step_size(&mut temp as *mut size_t);
        HANDLE_ERROR(AfError::from(err_val));
        temp
    }
}

/// Call the garbage collection routine
pub fn device_gc() {
    unsafe {
        let err_val = af_device_gc();
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Sync all operations on given device
///
/// # Parameters
///
/// - `device` on which the operations are to be synced
///
/// # Return Values
///
/// None
pub fn sync(device: i32) {
    unsafe {
        let err_val = af_sync(device as c_int);
        HANDLE_ERROR(AfError::from(err_val));
    }
}
<commit_msg>Pinned memory allocation and free functions<commit_after>use super::defines::AfError;
use super::error::HANDLE_ERROR;
use super::util::{dim_t, free_host, void_ptr};

use libc::{c_char, c_int, size_t};
use std::borrow::Cow;
use std::ffi::{CStr, CString};

extern "C" {
    fn af_get_version(major: *mut c_int, minor: *mut c_int, patch: *mut c_int) -> c_int;
    fn af_get_revision() -> *const c_char;
    fn af_info() -> c_int;
    fn af_info_string(str: *mut *mut c_char, verbose: bool) -> c_int;
    fn af_device_info(
        d_name: *mut c_char,
        d_platform: *mut c_char,
        d_toolkit: *mut c_char,
        d_compute: *mut c_char,
    ) -> c_int;
    fn af_init() -> c_int;
    fn af_get_device_count(nDevices: *mut c_int) -> c_int;
    fn af_get_dbl_support(available: *mut c_int, device: c_int) -> c_int;
    fn af_set_device(device: c_int) -> c_int;
    fn af_get_device(device: *mut c_int) -> c_int;
    fn af_device_mem_info(
        alloc_bytes: *mut size_t,
        alloc_buffers: *mut size_t,
        lock_bytes: *mut size_t,
        lock_buffers: *mut size_t,
    ) -> c_int;
    fn af_print_mem_info(msg: *const c_char, device_id: c_int) -> c_int;
    fn af_set_mem_step_size(step_bytes: size_t) -> c_int;
    fn af_get_mem_step_size(step_bytes: *mut size_t) -> c_int;
    fn af_device_gc() -> c_int;
    fn af_sync(device: c_int) -> c_int;

    fn af_alloc_pinned(non_pagable_ptr: *mut void_ptr, bytes: dim_t) -> c_int;
    fn af_free_pinned(non_pagable_ptr: void_ptr) -> c_int;
}

/// Get ArrayFire Version Number
///
/// # Return Values
/// A triplet of integers indicating major, minor & fix release version numbers.
pub fn get_version() -> (i32, i32, i32) {
    unsafe {
        let mut maj: i32 = 0;
        let mut min: i32 = 0;
        let mut pat: i32 = 0;
        let err_val = af_get_version(
            &mut maj as *mut c_int,
            &mut min as *mut c_int,
            &mut pat as *mut c_int,
        );
        HANDLE_ERROR(AfError::from(err_val));
        (maj, min, pat)
    }
}

/// Get ArrayFire Revision (commit) information of the library.
///
/// # Return Values
/// This returns a `Cow<'static, str>` as the string is constructed at compile time.
pub fn get_revision() -> Cow<'static, str> {
    unsafe { CStr::from_ptr(af_get_revision()).to_string_lossy() }
}

/// Print library meta-info
///
/// # Examples
///
/// An example output of `af::info` call looks like below
///
/// ```text
/// ArrayFire v3.0.0 (CUDA, 64-bit Mac OSX, build d8d4b38)
/// Platform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000
/// [0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0
/// ```
pub fn info() {
    unsafe {
        let err_val = af_info();
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Return library meta-info as `String`
///
/// # Examples
///
/// An example output of `af::info_string` call looks like below
///
/// ```text
/// ArrayFire v3.0.0 (CUDA, 64-bit Mac OSX, build d8d4b38)
/// Platform: CUDA Toolkit 7, Driver: CUDA Driver Version: 7000
/// [0] GeForce GT 750M, 2048 MB, CUDA Compute 3.0
/// ```
pub fn info_string(verbose: bool) -> String {
    let result: String;
    unsafe {
        let mut tmp: *mut c_char = ::std::ptr::null_mut();
        let err_val = af_info_string(&mut tmp, verbose);
        HANDLE_ERROR(AfError::from(err_val));
        result = CStr::from_ptr(tmp).to_string_lossy().into_owned();
        free_host(tmp);
    }
    result
}

/// Gets the information about device and platform as strings.
///
/// # Return Values
/// A tuple of `String` indicating the name, platform, toolkit and compute.
pub fn device_info() -> (String, String, String, String) {
    let mut name = [0 as c_char; 64];
    let mut platform = [0 as c_char; 10];
    let mut toolkit = [0 as c_char; 64];
    let mut compute = [0 as c_char; 10];
    unsafe {
        let err_val = af_device_info(
            &mut name[0],
            &mut platform[0],
            &mut toolkit[0],
            &mut compute[0],
        );
        HANDLE_ERROR(AfError::from(err_val));
        (
            CStr::from_ptr(name.as_mut_ptr())
                .to_string_lossy()
                .into_owned(),
            CStr::from_ptr(platform.as_mut_ptr())
                .to_string_lossy()
                .into_owned(),
            CStr::from_ptr(toolkit.as_mut_ptr())
                .to_string_lossy()
                .into_owned(),
            CStr::from_ptr(compute.as_mut_ptr())
                .to_string_lossy()
                .into_owned(),
        )
    }
}

/// Initialize ArrayFire library
///
/// 0th device will be the default device unless init call
/// is followed by set_device
pub fn init() {
    unsafe {
        let err_val = af_init();
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Get total number of available devices
pub fn device_count() -> i32 {
    unsafe {
        let mut temp: i32 = 0;
        let err_val = af_get_device_count(&mut temp as *mut c_int);
        HANDLE_ERROR(AfError::from(err_val));
        temp
    }
}

/// Check if a device has double support
///
/// # Parameters
///
/// - `device` is the device for which double support is checked for
///
/// # Return Values
///
/// `True` if `device` device has double support, `False` otherwise.
pub fn is_double_available(device: i32) -> bool {
    unsafe {
        let mut temp: i32 = 0;
        let err_val = af_get_dbl_support(&mut temp as *mut c_int, device as c_int);
        HANDLE_ERROR(AfError::from(err_val));
        temp > 0
    }
}

/// Set active device
///
/// # Parameters
///
/// - `device` is the value of the device identifier which has to be set as active
pub fn set_device(device: i32) {
    unsafe {
        let err_val = af_set_device(device as c_int);
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Get the current active device id
pub fn get_device() -> i32 {
    unsafe {
        let mut temp: i32 = 0;
        let err_val = af_get_device(&mut temp as *mut c_int);
        HANDLE_ERROR(AfError::from(err_val));
        temp
    }
}

/// Get memory information from the memory manager for the current active device
///
/// # Parameters
///
/// This function doesn't take any input parameters
///
/// # Return Values
///
/// A quadruple of values regarding the following information.
///
/// * Number of bytes allocated
/// * Number of buffers allocated
/// * Number of bytes locked
/// * Number of buffers locked
pub fn device_mem_info() -> (usize, usize, usize, usize) {
    unsafe {
        let mut o0: usize = 0;
        let mut o1: usize = 0;
        let mut o2: usize = 0;
        let mut o3: usize = 0;
        let err_val = af_device_mem_info(
            &mut o0 as *mut size_t,
            &mut o1 as *mut size_t,
            &mut o2 as *mut size_t,
            &mut o3 as *mut size_t,
        );
        HANDLE_ERROR(AfError::from(err_val));
        (o0, o1, o2, o3)
    }
}

/// Print buffer details from the ArrayFire device manager
///
/// This information is printed in the form of a table.
///
/// # Parameters
///
/// - `msg` is a message to print before the table
/// - `device` is the id of the device for which buffer details are to be printed
///
/// # Return Values
///
/// None
pub fn print_mem_info(msg: String, device: i32) {
    unsafe {
        let cmsg = CString::new(msg.as_bytes());
        match cmsg {
            Ok(v) => {
                let err_val = af_print_mem_info(
                    v.to_bytes_with_nul().as_ptr() as *const c_char,
                    device as c_int,
                );
                HANDLE_ERROR(AfError::from(err_val));
            }
            Err(_) => HANDLE_ERROR(AfError::ERR_INTERNAL),
        }
    }
}

/// Set the minimum memory chunk size
///
/// # Parameters
///
/// - `step_bytes` is the size of minimum memory chunk in bytes
///
/// # Return Values
///
/// None
pub fn set_mem_step_size(step_bytes: usize) {
    unsafe {
        let err_val = af_set_mem_step_size(step_bytes as size_t);
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Get the minimum memory chunk size
///
/// # Parameters
///
/// None
///
/// # Return Values
///
/// Returns is the size of minimum memory chunk in bytes
pub fn get_mem_step_size() -> usize {
    unsafe {
        let mut temp: usize = 0;
        let err_val = af_get_mem_step_size(&mut temp as *mut size_t);
        HANDLE_ERROR(AfError::from(err_val));
        temp
    }
}

/// Call the garbage collection routine
pub fn device_gc() {
    unsafe {
        let err_val = af_device_gc();
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Sync all operations on given device
///
/// # Parameters
///
/// - `device` on which the operations are to be synced
///
/// # Return Values
///
/// None
pub fn sync(device: i32) {
    unsafe {
        let err_val = af_sync(device as c_int);
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Allocate non-pageable memory on HOST memory
pub unsafe fn alloc_pinned(bytes: usize) -> void_ptr {
    let mut out: void_ptr = std::ptr::null_mut();
    let err_val = af_alloc_pinned(&mut out as *mut void_ptr, bytes as dim_t);
    HANDLE_ERROR(AfError::from(err_val));
    out
}

/// Free the pointer returned by [alloc_pinned](./fn.alloc_pinned.html)
pub unsafe fn free_pinned(ptr: void_ptr) {
    let err_val = af_free_pinned(ptr);
    HANDLE_ERROR(AfError::from(err_val));
}
<|endoftext|>


<commit_before>use chrono::NaiveTime;

const STEFAN_BOLTZMANN_CONSTANT: f64 = 5.670367 / 100_000_000.0;

pub fn kelvin_to_celcius(k: f64) -> f64 {
    k - 273.15
}

/// Température, en kelvins, d'un objet, en fonction de son albedo, de son émissivité
/// et de son irradiance par le Soleil.
pub fn kelvin_temperature(albedo: f64, emissivity: f64, irradiance: f64) -> f64 {
    assert!(0.0 <= albedo && albedo <= 1.0);
    assert!(0.0 <= emissivity && emissivity <= 1.0);

    (((1.0 - albedo) * irradiance) / (4.0 * emissivity * STEFAN_BOLTZMANN_CONSTANT)).powf(1.0 / 4.0)
}

// WIP

// need day_of_year()
// -> .ordinal() (1-indexed)

// l'ensoleillement (insolation, english) est une mesure d'énergie
// l'irradiance (irradiance, english) est une mesure de puissance

/// Irradiance d'un point, en Watts par mètre carré, en fonction de la masse d'air
/// devant être traversée par les rayons du Soleil.
pub fn irradiance(air_mass: f64) -> f64 {
    1.353 * 0.7f64.powf(air_mass.powf(0.678)) * 1000.0
}

/// Masse d'air devant être traversée par les rayons du Soleil en fonction de l'angle
/// zénithal.
pub fn air_mass(zenith_angle: f64) -> f64 {
    assert!(0.0 <= zenith_angle && zenith_angle <= 90.0);
    1.0 / zenith_angle.to_radians().cos()
}

/// Angle zénithal en fonction de l'angle d'élévation.
pub fn zenith_angle(elevation_angle: f64) -> f64 {
    assert!(0.0 <= elevation_angle && elevation_angle <= 90.0);
    90.0 - elevation_angle
}

/// Angle d'élévation en fonction de l'angle de déclinaison, de la latitude et de l'angle horaire.
pub fn elevation_angle(declination_angle: f64, latitude: f64, hour_angle: f64) -> f64 {
    assert!(-23.45 <= declination_angle && declination_angle <= 23.45);
    assert!(-90.0 <= latitude && latitude <= 90.0);
    assert!(-180.0 <= hour_angle && hour_angle <= 180.0);
    (declination_angle.to_radians().sin() * latitude.to_radians().sin() +
     declination_angle.to_radians().cos() * latitude.to_radians().cos() *
     hour_angle.to_radians().cos())
        .asin()
        .to_degrees()
}

/// Angle de déclinaison en fonction du jour de l'année.
pub fn declination_angle(day_of_year: u32) -> f64 {
    assert!(1 <= day_of_year && day_of_year <= 366); // leap years

    (23.45f64.to_radians().sin() * ((360.0 / 365.0) * (day_of_year - 81) as f64).to_radians().sin())
        .asin()
        .to_degrees()
}

/// Angle horaire, en degrés, en fonction de l'heure solaire.
pub fn hour_angle(solar_time: f64) -> f64 {
    assert!(0.0 <= solar_time && solar_time <= 24.0);
    15.0 * (solar_time - 12.0)
}

/// Heure solaire en fonction de l'heure locale et du facteur de correction de l'heure.
pub fn solar_time(local_time: f64, time_correction_factor: f64) -> f64 {
    local_time + time_correction_factor / 60.0
}

/// Facteur de correction de l'heure, en minutes, en fonction de la longitude du point étudié,
/// de la longitude du méridien standard local et de l'équation du temps.
pub fn time_correction_factor(longitude: f64,
                              local_standard_meridian_longitude: f64,
                              equation_of_time: f64)
                              -> f64 {
    assert!(-15.0 <= equation_of_time && equation_of_time <= 20.0);
    4.0 * (longitude - local_standard_meridian_longitude) + equation_of_time
}

/// Longitude du méridien standard local en fonction du décalage horaire par rapport
/// au fuseau horaire GMT.
pub fn local_standard_meridian_longitude(gmt_offset: f64) -> f64 {
    15.0 * gmt_offset
}

/// Équation du temps en fonction du jour de l'année, en minutes.
pub fn equation_of_time(day_of_year: u32) -> f64 {
    let b = (360.0 / 365.0) * (day_of_year - 81) as f64;
    9.87 * (2.0 * b).to_radians().sin() - 7.53 * b.to_radians().cos() - 1.5 * b.to_radians().sin()
}
<commit_msg>remove temperature code<commit_after>use chrono::NaiveTime;

/// Irradiance d'un point, en Watts par mètre carré, en fonction de la masse d'air
/// devant être traversée par les rayons du Soleil.
pub fn irradiance(air_mass: f64) -> f64 {
    1.353 * 0.7f64.powf(air_mass.powf(0.678)) * 1000.0
}

/// Masse d'air devant être traversée par les rayons du Soleil en fonction de l'angle
/// zénithal.
pub fn air_mass(zenith_angle: f64) -> f64 {
    assert!(0.0 <= zenith_angle && zenith_angle <= 90.0);
    1.0 / zenith_angle.to_radians().cos()
}

/// Angle zénithal en fonction de l'angle d'élévation.
pub fn zenith_angle(elevation_angle: f64) -> f64 {
    assert!(0.0 <= elevation_angle && elevation_angle <= 90.0);
    90.0 - elevation_angle
}

/// Angle d'élévation en fonction de l'angle de déclinaison, de la latitude et de l'angle horaire.
pub fn elevation_angle(declination_angle: f64, latitude: f64, hour_angle: f64) -> f64 {
    assert!(-23.45 <= declination_angle && declination_angle <= 23.45);
    assert!(-90.0 <= latitude && latitude <= 90.0);
    assert!(-180.0 <= hour_angle && hour_angle <= 180.0);
    (declination_angle.to_radians().sin() * latitude.to_radians().sin() +
     declination_angle.to_radians().cos() * latitude.to_radians().cos() *
     hour_angle.to_radians().cos())
        .asin()
        .to_degrees()
}

/// Angle de déclinaison en fonction du jour de l'année.
pub fn declination_angle(day_of_year: u32) -> f64 {
    assert!(1 <= day_of_year && day_of_year <= 366); // leap years

    (23.45f64.to_radians().sin() * ((360.0 / 365.0) * (day_of_year - 81) as f64).to_radians().sin())
        .asin()
        .to_degrees()
}

/// Angle horaire, en degrés, en fonction de l'heure solaire.
pub fn hour_angle(solar_time: f64) -> f64 {
    assert!(0.0 <= solar_time && solar_time <= 24.0);
    15.0 * (solar_time - 12.0)
}

/// Heure solaire en fonction de l'heure locale et du facteur de correction de l'heure.
pub fn solar_time(local_time: f64, time_correction_factor: f64) -> f64 {
    local_time + time_correction_factor / 60.0
}

/// Facteur de correction de l'heure, en minutes, en fonction de la longitude du point étudié,
/// de la longitude du méridien standard local et de l'équation du temps.
pub fn time_correction_factor(longitude: f64,
                              local_standard_meridian_longitude: f64,
                              equation_of_time: f64)
                              -> f64 {
    assert!(-15.0 <= equation_of_time && equation_of_time <= 20.0);
    4.0 * (longitude - local_standard_meridian_longitude) + equation_of_time
}

/// Longitude du méridien standard local en fonction du décalage horaire par rapport
/// au fuseau horaire GMT.
pub fn local_standard_meridian_longitude(gmt_offset: f64) -> f64 {
    15.0 * gmt_offset
}

/// Équation du temps en fonction du jour de l'année, en minutes.
pub fn equation_of_time(day_of_year: u32) -> f64 {
    let b = (360.0 / 365.0) * (day_of_year - 81) as f64;
    9.87 * (2.0 * b).to_radians().sin() - 7.53 * b.to_radians().cos() - 1.5 * b.to_radians().sin()
}
<|endoftext|>


<commit_before>use io::file::FileStatus;
use io::redraw::RedrawTask;
use state::editor::{Buffer, BufferManager, Editor};
use edit::buffer::{TextBuffer, SplitBuffer};

use std::process::exit;

impl Editor {
    /// Invoke a command in the prompt
    pub fn invoke(&mut self, cmd: String) {
        let mut split = cmd.split(' ');
        let base_cmd = split.nth(0).unwrap_or("");
        let sec_cmd = split.nth(0).unwrap_or("");

        match base_cmd {
            "set" => {
                self.status_bar.msg = match self.options.set(sec_cmd) {
                    Ok(()) => format!("Option set: {}", sec_cmd),
                    Err(()) => format!("Option does not exist: {}", sec_cmd),
                }
            },
            "unset" => {
                self.status_bar.msg = match self.options.unset(sec_cmd) {
                    Ok(()) => format!("Option unset: {}", sec_cmd),
                    Err(()) => format!("Option does not exist: {}", sec_cmd),
                }
            },
            "toggle" | "tog" => {
                self.status_bar.msg = match self.options.toggle(sec_cmd) {
                    Ok(()) => format!("Option toggled: {}", sec_cmd),
                    Err(()) => format!("Option does not exist: {}", sec_cmd),
                }
            },
            "get" => {
                self.status_bar.msg = match self.options.get(sec_cmd) {
                    Some(true) => format!("Option set: {}", sec_cmd),
                    Some(false) => format!("Option unset: {}", sec_cmd),
                    None => format!("Option does not exist: {}", sec_cmd),
                }
            },
            "o" | "open" => {
                self.status_bar.msg = match self.open(sec_cmd) {
                    FileStatus::NotFound => format!("File {} could not be opened", sec_cmd),
                    FileStatus::Ok => format!("File {} opened", sec_cmd),
                    _ => unreachable!(),
                }
            },
            "w" | "write" => {
                self.status_bar.msg = match self.write(sec_cmd) {
                    FileStatus::NotFound => format!("File {} could not be opened", sec_cmd),
                    FileStatus::Ok => format!("File {} written", sec_cmd),
                    FileStatus::Other => format!("Couldn't write {}", sec_cmd),
                }
            },
            "ls" => {
                let description = get_buffers_description(&self.buffers);
                let mut new_buffer: Buffer = SplitBuffer::from_str(&description).into();
                new_buffer.title = Some("<Buffers>".into());
                new_buffer.is_transient = true; // delete the buffer when the user switches away

                let new_buffer_index = self.buffers.new_buffer(new_buffer);
                self.buffers.switch_to(new_buffer_index);
                self.redraw_task = RedrawTask::Full;
            },
            "bd" => {
                let ix = self.buffers.current_buffer_index();
                self.buffers.delete_buffer(ix);
                self.redraw_task = RedrawTask::Full;
            },
            "help" => {
                self.open("/apps/sodium/help.txt");
            },
            "q" | "quit" => {
                exit(0);
            },
            c => {
                if c.starts_with("b") {
                    let rest: String = c.chars().skip(1).collect();

                    if let Ok(number) = rest.parse::<usize>() {
                        if !self.buffers.is_buffer_index_valid(number) {
                            self.status_bar.msg = format!("Invalid buffer #{}", number);
                        } else {
                            self.buffers.switch_to(number);
                            self.redraw_task = RedrawTask::Full;
                            self.status_bar.msg = format!("Switched to buffer #{}", number);
                        }
                    } else {
                        self.status_bar.msg = format!("Unknown command: {}", c);
                    }
                } else {
                    self.status_bar.msg = format!("Unknown command: {}", c);
                }
            }
        }

        self.hint();
    }
}

fn get_buffers_description(buffers: &BufferManager) -> String {
    fn print_buffer(i: usize, b: &Buffer) -> String {
        let title = b.title.as_ref().map(|s| s.as_str()).unwrap_or("<No Title>");

        format!("b{}\t\t\t{}", i, title)
    }

    let descriptions =
        buffers
            .iter()
            // don't include transient buffers like the one
            // this is going to be shown in
            .filter(|b| !b.is_transient)
            .enumerate()
            .map(|(i, b)| print_buffer(i, b))
            .collect::<Vec<_>>()
            .join("\n");

    format!("Buffers\n=====================================\n\n{}", descriptions)
}
<commit_msg>Add  command. Fixes #25<commit_after>use io::file::FileStatus;
use io::redraw::RedrawTask;
use state::editor::{Buffer, BufferManager, Editor};
use edit::buffer::{TextBuffer, SplitBuffer};

use std::process::exit;

impl Editor {
    /// Invoke a command in the prompt
    pub fn invoke(&mut self, cmd: String) {
        let mut split = cmd.split(' ');
        let base_cmd = split.nth(0).unwrap_or("");
        let sec_cmd = split.nth(0).unwrap_or("");

        match base_cmd {
            "set" => {
                self.status_bar.msg = match self.options.set(sec_cmd) {
                    Ok(()) => format!("Option set: {}", sec_cmd),
                    Err(()) => format!("Option does not exist: {}", sec_cmd),
                }
            },
            "unset" => {
                self.status_bar.msg = match self.options.unset(sec_cmd) {
                    Ok(()) => format!("Option unset: {}", sec_cmd),
                    Err(()) => format!("Option does not exist: {}", sec_cmd),
                }
            },
            "toggle" | "tog" => {
                self.status_bar.msg = match self.options.toggle(sec_cmd) {
                    Ok(()) => format!("Option toggled: {}", sec_cmd),
                    Err(()) => format!("Option does not exist: {}", sec_cmd),
                }
            },
            "get" => {
                self.status_bar.msg = match self.options.get(sec_cmd) {
                    Some(true) => format!("Option set: {}", sec_cmd),
                    Some(false) => format!("Option unset: {}", sec_cmd),
                    None => format!("Option does not exist: {}", sec_cmd),
                }
            },
            "o" | "open" => {
                self.status_bar.msg = match self.open(sec_cmd) {
                    FileStatus::NotFound => format!("File {} could not be opened", sec_cmd),
                    FileStatus::Ok => format!("File {} opened", sec_cmd),
                    _ => unreachable!(),
                }
            },
            "w" | "write" => {
                self.status_bar.msg = match self.write(sec_cmd) {
                    FileStatus::NotFound => format!("File {} could not be opened", sec_cmd),
                    FileStatus::Ok => format!("File {} written", sec_cmd),
                    FileStatus::Other => format!("Couldn't write {}", sec_cmd),
                }
            },
            "ls" => {
                let description = get_buffers_description(&self.buffers);
                let mut new_buffer: Buffer = SplitBuffer::from_str(&description).into();
                new_buffer.title = Some("<Buffers>".into());
                new_buffer.is_transient = true; // delete the buffer when the user switches away

                let new_buffer_index = self.buffers.new_buffer(new_buffer);
                self.buffers.switch_to(new_buffer_index);
                self.redraw_task = RedrawTask::Full;
            },
            "bd" => {
                let ix = self.buffers.current_buffer_index();
                self.buffers.delete_buffer(ix);
                self.redraw_task = RedrawTask::Full;
            },
            "h" | "help" => {
                self.open("/apps/sodium/help.txt");
            },
            "q" | "quit" => {
                exit(0);
            },
            c => {
                if c.starts_with("b") {
                    let rest: String = c.chars().skip(1).collect();

                    if let Ok(number) = rest.parse::<usize>() {
                        if !self.buffers.is_buffer_index_valid(number) {
                            self.status_bar.msg = format!("Invalid buffer #{}", number);
                        } else {
                            self.buffers.switch_to(number);
                            self.redraw_task = RedrawTask::Full;
                            self.status_bar.msg = format!("Switched to buffer #{}", number);
                        }
                    } else {
                        self.status_bar.msg = format!("Unknown command: {}", c);
                    }
                } else {
                    self.status_bar.msg = format!("Unknown command: {}", c);
                }
            }
        }

        self.hint();
    }
}

fn get_buffers_description(buffers: &BufferManager) -> String {
    fn print_buffer(i: usize, b: &Buffer) -> String {
        let title = b.title.as_ref().map(|s| s.as_str()).unwrap_or("<No Title>");

        format!("b{}\t\t\t{}", i, title)
    }

    let descriptions =
        buffers
            .iter()
            // don't include transient buffers like the one
            // this is going to be shown in
            .filter(|b| !b.is_transient)
            .enumerate()
            .map(|(i, b)| print_buffer(i, b))
            .collect::<Vec<_>>()
            .join("\n");

    format!("Buffers\n=====================================\n\n{}", descriptions)
}
<|endoftext|>


<commit_before>// run-pass
// compile-flags: -O

#![feature(thread_local)]

#[thread_local]
static S: u32 = 222;

fn main() {
    let local = &S as *const u32 as usize;
    let foreign = std::thread::spawn(|| &S as *const u32 as usize).join().unwrap();
    assert_ne!(local, foreign);
}
<commit_msg>Don't run test on emscripten which doesn't have threads<commit_after>// run-pass
// ignore-emscripten no threads support
// compile-flags: -O

#![feature(thread_local)]

#[thread_local]
static S: u32 = 222;

fn main() {
    let local = &S as *const u32 as usize;
    let foreign = std::thread::spawn(|| &S as *const u32 as usize).join().unwrap();
    assert_ne!(local, foreign);
}
<|endoftext|>


<commit_before>
use std::collections::HashMap;
use std::io::{self, Read};
use std::ops;

use value::{Value};
use eval::{FuncError, FuncResult};

macro_rules! math {
    ($name:ident, $op:path) => {
        pub fn $name(mut items: Vec<Value>) -> FuncResult {
            let mut total = match items.remove(0) {
                Value::Number(n) => n,
                _ => return Err(FuncError::InvalidArguments),
            };

            for item in items {
                match item {
                    Value::Number(next) => {
                        total = $op(total, next);
                    },
                    _ => return Err(FuncError::InvalidArguments),
                }
            }

            Ok(Value::Number(total))
        }
    }
}

pub fn print(vals: Vec<Value>) -> FuncResult {
    for val in vals {
        print!("{:?} ", val);
    }

    println!("");

    Ok(Value::Void)
}

pub fn read(vals: Vec<Value>) -> FuncResult {
    if vals.len() != 0 {
        return Err(FuncError::InvalidArguments);
    }

    let mut stdin = io::stdin();

    let mut input = String::new();
    match stdin.read_line(&mut input) {
        Ok(_) => {
            match input.pop() {
                None | Some('\n') => (),
                Some(ch) => {
                    input.push(ch);
                },
            }

            Ok(Value::Str(input))
        }
        Err(err) => Err(FuncError::IoError(err)),
    }
}

pub fn str_fn(vals: Vec<Value>) -> FuncResult {
    let mut result = String::new();

    for val in vals {
        let string = match val {
            Value::Str(str) => str,
            other => format!("{:?}", other),
        };

        result.push_str(&string);
    }

    Ok(Value::Str(result))
}

pub fn eq(vals: Vec<Value>) -> FuncResult {
    for i in (0 .. vals.len() - 1) {
        if vals[i] != vals[i + 1] {
            return Ok(Value::Bool(false));
        }
    }

    Ok(Value::Bool(true))
}

pub fn and(vals: Vec<Value>) -> FuncResult {
    for val in vals {
        match val {
            Value::Bool(val) => {
                if !val {
                    return Ok(Value::Bool(false));
                }
            },
            _ => return Err(FuncError::InvalidArguments),
        }
    }

    Ok(Value::Bool(true))
}

pub fn or(vals: Vec<Value>) -> FuncResult {
    for val in vals {
        match val {
            Value::Bool(val) => {
                if val {
                    return Ok(Value::Bool(true));
                }
            },
            _ => return Err(FuncError::InvalidArguments),
        }
    }

    Ok(Value::Bool(false))
}

math!(add, ops::Add::add);
math!(sub, ops::Sub::sub);
math!(mul, ops::Mul::mul);
math!(div, ops::Div::div);
<commit_msg>Reverted change, when is EOF ever in userinput?<commit_after>
use std::collections::HashMap;
use std::io::{self, Read};
use std::ops;

use value::{Value};
use eval::{FuncError, FuncResult};

macro_rules! math {
    ($name:ident, $op:path) => {
        pub fn $name(mut items: Vec<Value>) -> FuncResult {
            let mut total = match items.remove(0) {
                Value::Number(n) => n,
                _ => return Err(FuncError::InvalidArguments),
            };

            for item in items {
                match item {
                    Value::Number(next) => {
                        total = $op(total, next);
                    },
                    _ => return Err(FuncError::InvalidArguments),
                }
            }

            Ok(Value::Number(total))
        }
    }
}

pub fn print(vals: Vec<Value>) -> FuncResult {
    for val in vals {
        print!("{:?} ", val);
    }

    println!("");

    Ok(Value::Void)
}

pub fn read(vals: Vec<Value>) -> FuncResult {
    if vals.len() != 0 {
        return Err(FuncError::InvalidArguments);
    }

    let mut stdin = io::stdin();

    let mut input = String::new();
    match stdin.read_line(&mut input) {

        Ok(_) => {
            input.pop();
            Ok(Value::Str(input))
        }
        Err(err) => Err(FuncError::IoError(err)),
    }
}

pub fn str_fn(vals: Vec<Value>) -> FuncResult {
    let mut result = String::new();

    for val in vals {
        let string = match val {
            Value::Str(str) => str,
            other => format!("{:?}", other),
        };

        result.push_str(&string);
    }

    Ok(Value::Str(result))
}

pub fn eq(vals: Vec<Value>) -> FuncResult {
    for i in (0 .. vals.len() - 1) {
        if vals[i] != vals[i + 1] {
            return Ok(Value::Bool(false));
        }
    }

    Ok(Value::Bool(true))
}

pub fn and(vals: Vec<Value>) -> FuncResult {
    for val in vals {
        match val {
            Value::Bool(val) => {
                if !val {
                    return Ok(Value::Bool(false));
                }
            },
            _ => return Err(FuncError::InvalidArguments),
        }
    }

    Ok(Value::Bool(true))
}

pub fn or(vals: Vec<Value>) -> FuncResult {
    for val in vals {
        match val {
            Value::Bool(val) => {
                if val {
                    return Ok(Value::Bool(true));
                }
            },
            _ => return Err(FuncError::InvalidArguments),
        }
    }

    Ok(Value::Bool(false))
}

math!(add, ops::Add::add);
math!(sub, ops::Sub::sub);
math!(mul, ops::Mul::mul);
math!(div, ops::Div::div);
<|endoftext|>


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

//! Utilities used by `zerocopy-derive`.
//!
//! These are defined in `zerocopy` rather than in code generated by
//! `zerocopy-derive` so that they can be compiled once rather than recompiled
//! for every pair of type and trait (in other words, if they were defined in
//! generated code, then deriving `AsBytes` and `FromBytes` on three different
//! types would result in the code in question being emitted and compiled six
//! different times).

#![allow(missing_debug_implementations)]

use core::marker::PhantomData;

/// A compile-time check that should be one particular value.
pub trait ShouldBe<const VALUE: bool> {}

/// A struct for checking whether `T` contains padding.
pub struct HasPadding<T: ?Sized, const VALUE: bool>(PhantomData<T>);

impl<T: ?Sized, const VALUE: bool> ShouldBe<VALUE> for HasPadding<T, VALUE> {}

/// Does the struct type `$t` have padding?
///
/// `$ts` is the list of the type of every field in `$t`. `$t` must be a
/// struct type, or else `struct_has_padding!`'s result may be meaningless.
///
/// Note that `struct_has_padding!`'s results are independent of `repr` since
/// they only consider the size of the type and the sizes of the fields.
/// Whatever the repr, the size of the type already takes into account any
/// padding that the compiler has decided to add. Structs with well-defined
/// representations (such as `repr(C)`) can use this macro to check for padding.
/// Note that while this may yield some consistent value for some `repr(Rust)`
/// structs, it is not guaranteed across platforms or compilations.
#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
#[macro_export]
macro_rules! struct_has_padding {
    ($t:ty, $($ts:ty),*) => {
        core::mem::size_of::<$t>() > 0 $(+ core::mem::size_of::<$ts>())*
    };
}

/// Does the union type `$t` have padding?
///
/// `$ts` is the list of the type of every field in `$t`. `$t` must be a
/// union type, or else `union_has_padding!`'s result may be meaningless.
///
/// Note that `union_has_padding!`'s results are independent of `repr` since
/// they only consider the size of the type and the sizes of the fields.
/// Whatever the repr, the size of the type already takes into account any
/// padding that the compiler has decided to add. Unions with well-defined
/// representations (such as `repr(C)`) can use this macro to check for padding.
/// Note that while this may yield some consistent value for some `repr(Rust)`
/// unions, it is not guaranteed across platforms or compilations.
#[macro_export]
macro_rules! union_has_padding {
    ($t:ty, $($ts:ty),*) => {
        false $(|| core::mem::size_of::<$t>() != core::mem::size_of::<$ts>())*
    };
}
<commit_msg>Mark zerocopy-derive utility macros as doc(hidden) (#139)<commit_after>// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Utilities used by `zerocopy-derive`.
//!
//! These are defined in `zerocopy` rather than in code generated by
//! `zerocopy-derive` so that they can be compiled once rather than recompiled
//! for every pair of type and trait (in other words, if they were defined in
//! generated code, then deriving `AsBytes` and `FromBytes` on three different
//! types would result in the code in question being emitted and compiled six
//! different times).

#![allow(missing_debug_implementations)]

use core::marker::PhantomData;

/// A compile-time check that should be one particular value.
pub trait ShouldBe<const VALUE: bool> {}

/// A struct for checking whether `T` contains padding.
pub struct HasPadding<T: ?Sized, const VALUE: bool>(PhantomData<T>);

impl<T: ?Sized, const VALUE: bool> ShouldBe<VALUE> for HasPadding<T, VALUE> {}

/// Does the struct type `$t` have padding?
///
/// `$ts` is the list of the type of every field in `$t`. `$t` must be a
/// struct type, or else `struct_has_padding!`'s result may be meaningless.
///
/// Note that `struct_has_padding!`'s results are independent of `repr` since
/// they only consider the size of the type and the sizes of the fields.
/// Whatever the repr, the size of the type already takes into account any
/// padding that the compiler has decided to add. Structs with well-defined
/// representations (such as `repr(C)`) can use this macro to check for padding.
/// Note that while this may yield some consistent value for some `repr(Rust)`
/// structs, it is not guaranteed across platforms or compilations.
#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
#[macro_export]
macro_rules! struct_has_padding {
    ($t:ty, $($ts:ty),*) => {
        core::mem::size_of::<$t>() > 0 $(+ core::mem::size_of::<$ts>())*
    };
}

/// Does the union type `$t` have padding?
///
/// `$ts` is the list of the type of every field in `$t`. `$t` must be a
/// union type, or else `union_has_padding!`'s result may be meaningless.
///
/// Note that `union_has_padding!`'s results are independent of `repr` since
/// they only consider the size of the type and the sizes of the fields.
/// Whatever the repr, the size of the type already takes into account any
/// padding that the compiler has decided to add. Unions with well-defined
/// representations (such as `repr(C)`) can use this macro to check for padding.
/// Note that while this may yield some consistent value for some `repr(Rust)`
/// unions, it is not guaranteed across platforms or compilations.
#[doc(hidden)] // `#[macro_export]` bypasses this module's `#[doc(hidden)]`.
#[macro_export]
macro_rules! union_has_padding {
    ($t:ty, $($ts:ty),*) => {
        false $(|| core::mem::size_of::<$t>() != core::mem::size_of::<$ts>())*
    };
}
<|endoftext|>


<commit_before>//! This module implements several error types and traits.
//!
//! The suggested usage in returned results is as follows:
//!
//! * The concrete `util::concrete::Error` type (re-exported as `util::Error`) is great for code
//!   that is not part of the request/response lifecycle.  It avoids pulling in the unnecessary
//!   infrastructure to convert errors into a user facing JSON responses (relative to `AppError`).
//! * `diesel::QueryResult` - There is a lot of code that only deals with query errors.  If only
//!   one type of error is possible in a function, using that specific error is preferable to the
//!   more general `util::Error`.  This is especially common in model code.
//! * `util::errors::AppResult` - Some failures should be converted into user facing JSON
//!   responses.  This error type is more dynamic and is box allocated.  Low-level errors are
//!   typically not converted to user facing errors and most usage is within the models,
//!   controllers, and middleware layers.

use std::any::{Any, TypeId};
use std::error::Error;
use std::fmt;

use chrono::NaiveDateTime;
use diesel::result::Error as DieselError;

use crate::util::AppResponse;

mod json;

pub use json::TOKEN_FORMAT_ERROR;
pub(crate) use json::{
    InsecurelyGeneratedTokenRevoked, MetricsDisabled, NotFound, OwnershipInvitationExpired,
    ReadOnlyMode, TooManyRequests,
};

/// Returns an error with status 200 and the provided description as JSON
///
/// This is for backwards compatibility with cargo endpoints.  For all other
/// endpoints, use helpers like `bad_request` or `server_error` which set a
/// correct status code.
pub fn cargo_err<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::Ok(error.to_string()))
}

// The following are intended to be used for errors being sent back to the Ember
// frontend, not to cargo as cargo does not handle non-200 response codes well
// (see <https://github.com/rust-lang/cargo/issues/3995>), but Ember requires
// non-200 response codes for its stores to work properly.

/// Return an error with status 400 and the provided description as JSON
pub fn bad_request<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::BadRequest(error.to_string()))
}

pub fn account_locked(reason: &str, until: Option<NaiveDateTime>) -> Box<dyn AppError> {
    Box::new(json::AccountLocked {
        reason: reason.to_string(),
        until,
    })
}

pub fn forbidden() -> Box<dyn AppError> {
    Box::new(json::Forbidden)
}

pub fn not_found() -> Box<dyn AppError> {
    Box::new(json::NotFound)
}

/// Returns an error with status 500 and the provided description as JSON
pub fn server_error<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::ServerError(error.to_string()))
}

// =============================================================================
// AppError trait

pub trait AppError: Send + fmt::Display + fmt::Debug + 'static {
    /// Generate an HTTP response for the error
    ///
    /// If none is returned, the error will bubble up the middleware stack
    /// where it is eventually logged and turned into a status 500 response.
    fn response(&self) -> Option<AppResponse>;

    /// The cause of an error response
    ///
    /// If present, an error provided to the `LogRequests` middleware.
    ///
    /// This is intended for use with the `ChainError` trait, where a user facing
    /// error may wrap an internal error we still want to log.
    fn cause(&self) -> Option<&dyn AppError> {
        None
    }

    fn get_type_id(&self) -> TypeId {
        TypeId::of::<Self>()
    }

    fn chain<E>(self, error: E) -> Box<dyn AppError>
    where
        Self: Sized,
        E: AppError,
    {
        Box::new(ChainedError {
            error,
            cause: Box::new(self),
        })
    }
}

impl dyn AppError {
    pub fn is<T: Any>(&self) -> bool {
        self.get_type_id() == TypeId::of::<T>()
    }

    fn try_convert(err: &(dyn Error + Send + 'static)) -> Option<Box<Self>> {
        match err.downcast_ref() {
            Some(DieselError::NotFound) => Some(not_found()),
            Some(DieselError::DatabaseError(_, info))
                if info.message().ends_with("read-only transaction") =>
            {
                Some(Box::new(ReadOnlyMode))
            }
            _ => None,
        }
    }
}

impl AppError for Box<dyn AppError> {
    fn response(&self) -> Option<AppResponse> {
        (**self).response()
    }

    fn cause(&self) -> Option<&dyn AppError> {
        (**self).cause()
    }

    fn get_type_id(&self) -> TypeId {
        (**self).get_type_id()
    }
}

pub type AppResult<T> = Result<T, Box<dyn AppError>>;

// =============================================================================
// Chaining errors

pub trait ChainError<T> {
    fn chain_error<E, F>(self, callback: F) -> AppResult<T>
    where
        E: AppError,
        F: FnOnce() -> E;
}

#[derive(Debug)]
struct ChainedError<E> {
    error: E,
    cause: Box<dyn AppError>,
}

impl<T, E: AppError> ChainError<T> for Result<T, E> {
    fn chain_error<E2, C>(self, callback: C) -> AppResult<T>
    where
        E2: AppError,
        C: FnOnce() -> E2,
    {
        self.map_err(move |err| err.chain(callback()))
    }
}

impl<T> ChainError<T> for Option<T> {
    fn chain_error<E, C>(self, callback: C) -> AppResult<T>
    where
        E: AppError,
        C: FnOnce() -> E,
    {
        match self {
            Some(t) => Ok(t),
            None => Err(Box::new(callback())),
        }
    }
}

impl<E: AppError> AppError for ChainedError<E> {
    fn response(&self) -> Option<AppResponse> {
        self.error.response()
    }

    fn cause(&self) -> Option<&dyn AppError> {
        Some(&*self.cause)
    }
}

impl<E: AppError> fmt::Display for ChainedError<E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} caused by {}", self.error, self.cause)
    }
}

// =============================================================================
// Error impls

impl<E: Error + Send + 'static> AppError for E {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

impl<E: Error + Send + 'static> From<E> for Box<dyn AppError> {
    fn from(err: E) -> Box<dyn AppError> {
        <dyn AppError>::try_convert(&err).unwrap_or_else(|| Box::new(err))
    }
}
// =============================================================================
// Internal error for use with `chain_error`

#[derive(Debug)]
struct InternalAppError {
    description: String,
}

impl fmt::Display for InternalAppError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.description)?;
        Ok(())
    }
}

impl AppError for InternalAppError {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

#[derive(Debug)]
struct InternalAppErrorStatic {
    description: &'static str,
}

impl fmt::Display for InternalAppErrorStatic {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.description)?;
        Ok(())
    }
}

impl AppError for InternalAppErrorStatic {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

pub fn internal<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(InternalAppError {
        description: error.to_string(),
    })
}

#[derive(Debug)]
struct AppErrToStdErr(pub Box<dyn AppError>);

impl Error for AppErrToStdErr {}

impl fmt::Display for AppErrToStdErr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

pub(crate) fn std_error(e: Box<dyn AppError>) -> Box<dyn Error + Send> {
    Box::new(AppErrToStdErr(e))
}

#[test]
fn chain_error_internal() {
    assert_eq!(
        None::<()>
            .chain_error(|| internal("inner"))
            .chain_error(|| internal("middle"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by middle caused by inner"
    );
    assert_eq!(
        Err::<(), _>(internal("inner"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner"
    );

    // Don't do this, the user will see a generic 500 error instead of the intended message
    assert_eq!(
        Err::<(), _>(cargo_err("inner"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner"
    );
    assert_eq!(
        Err::<(), _>(forbidden())
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by must be logged in to perform that action"
    );
}

#[test]
fn chain_error_user_facing() {
    // Do this rarely, the user will only see the outer error
    assert_eq!(
        Err::<(), _>(cargo_err("inner"))
            .chain_error(|| cargo_err("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner" // never logged
    );

    // The outer error is sent as a response to the client.
    // The inner error never bubbles up to the logging middleware
    assert_eq!(
        Err::<(), _>(std::io::Error::from(std::io::ErrorKind::PermissionDenied))
            .chain_error(|| cargo_err("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by permission denied" // never logged
    );
}
<commit_msg>errors: Derive `Error` (and `Display`) for `AppErrToStdErr`<commit_after>//! This module implements several error types and traits.
//!
//! The suggested usage in returned results is as follows:
//!
//! * The concrete `util::concrete::Error` type (re-exported as `util::Error`) is great for code
//!   that is not part of the request/response lifecycle.  It avoids pulling in the unnecessary
//!   infrastructure to convert errors into a user facing JSON responses (relative to `AppError`).
//! * `diesel::QueryResult` - There is a lot of code that only deals with query errors.  If only
//!   one type of error is possible in a function, using that specific error is preferable to the
//!   more general `util::Error`.  This is especially common in model code.
//! * `util::errors::AppResult` - Some failures should be converted into user facing JSON
//!   responses.  This error type is more dynamic and is box allocated.  Low-level errors are
//!   typically not converted to user facing errors and most usage is within the models,
//!   controllers, and middleware layers.

use std::any::{Any, TypeId};
use std::error::Error;
use std::fmt;

use chrono::NaiveDateTime;
use diesel::result::Error as DieselError;

use crate::util::AppResponse;

mod json;

pub use json::TOKEN_FORMAT_ERROR;
pub(crate) use json::{
    InsecurelyGeneratedTokenRevoked, MetricsDisabled, NotFound, OwnershipInvitationExpired,
    ReadOnlyMode, TooManyRequests,
};

/// Returns an error with status 200 and the provided description as JSON
///
/// This is for backwards compatibility with cargo endpoints.  For all other
/// endpoints, use helpers like `bad_request` or `server_error` which set a
/// correct status code.
pub fn cargo_err<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::Ok(error.to_string()))
}

// The following are intended to be used for errors being sent back to the Ember
// frontend, not to cargo as cargo does not handle non-200 response codes well
// (see <https://github.com/rust-lang/cargo/issues/3995>), but Ember requires
// non-200 response codes for its stores to work properly.

/// Return an error with status 400 and the provided description as JSON
pub fn bad_request<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::BadRequest(error.to_string()))
}

pub fn account_locked(reason: &str, until: Option<NaiveDateTime>) -> Box<dyn AppError> {
    Box::new(json::AccountLocked {
        reason: reason.to_string(),
        until,
    })
}

pub fn forbidden() -> Box<dyn AppError> {
    Box::new(json::Forbidden)
}

pub fn not_found() -> Box<dyn AppError> {
    Box::new(json::NotFound)
}

/// Returns an error with status 500 and the provided description as JSON
pub fn server_error<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(json::ServerError(error.to_string()))
}

// =============================================================================
// AppError trait

pub trait AppError: Send + fmt::Display + fmt::Debug + 'static {
    /// Generate an HTTP response for the error
    ///
    /// If none is returned, the error will bubble up the middleware stack
    /// where it is eventually logged and turned into a status 500 response.
    fn response(&self) -> Option<AppResponse>;

    /// The cause of an error response
    ///
    /// If present, an error provided to the `LogRequests` middleware.
    ///
    /// This is intended for use with the `ChainError` trait, where a user facing
    /// error may wrap an internal error we still want to log.
    fn cause(&self) -> Option<&dyn AppError> {
        None
    }

    fn get_type_id(&self) -> TypeId {
        TypeId::of::<Self>()
    }

    fn chain<E>(self, error: E) -> Box<dyn AppError>
    where
        Self: Sized,
        E: AppError,
    {
        Box::new(ChainedError {
            error,
            cause: Box::new(self),
        })
    }
}

impl dyn AppError {
    pub fn is<T: Any>(&self) -> bool {
        self.get_type_id() == TypeId::of::<T>()
    }

    fn try_convert(err: &(dyn Error + Send + 'static)) -> Option<Box<Self>> {
        match err.downcast_ref() {
            Some(DieselError::NotFound) => Some(not_found()),
            Some(DieselError::DatabaseError(_, info))
                if info.message().ends_with("read-only transaction") =>
            {
                Some(Box::new(ReadOnlyMode))
            }
            _ => None,
        }
    }
}

impl AppError for Box<dyn AppError> {
    fn response(&self) -> Option<AppResponse> {
        (**self).response()
    }

    fn cause(&self) -> Option<&dyn AppError> {
        (**self).cause()
    }

    fn get_type_id(&self) -> TypeId {
        (**self).get_type_id()
    }
}

pub type AppResult<T> = Result<T, Box<dyn AppError>>;

// =============================================================================
// Chaining errors

pub trait ChainError<T> {
    fn chain_error<E, F>(self, callback: F) -> AppResult<T>
    where
        E: AppError,
        F: FnOnce() -> E;
}

#[derive(Debug)]
struct ChainedError<E> {
    error: E,
    cause: Box<dyn AppError>,
}

impl<T, E: AppError> ChainError<T> for Result<T, E> {
    fn chain_error<E2, C>(self, callback: C) -> AppResult<T>
    where
        E2: AppError,
        C: FnOnce() -> E2,
    {
        self.map_err(move |err| err.chain(callback()))
    }
}

impl<T> ChainError<T> for Option<T> {
    fn chain_error<E, C>(self, callback: C) -> AppResult<T>
    where
        E: AppError,
        C: FnOnce() -> E,
    {
        match self {
            Some(t) => Ok(t),
            None => Err(Box::new(callback())),
        }
    }
}

impl<E: AppError> AppError for ChainedError<E> {
    fn response(&self) -> Option<AppResponse> {
        self.error.response()
    }

    fn cause(&self) -> Option<&dyn AppError> {
        Some(&*self.cause)
    }
}

impl<E: AppError> fmt::Display for ChainedError<E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} caused by {}", self.error, self.cause)
    }
}

// =============================================================================
// Error impls

impl<E: Error + Send + 'static> AppError for E {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

impl<E: Error + Send + 'static> From<E> for Box<dyn AppError> {
    fn from(err: E) -> Box<dyn AppError> {
        <dyn AppError>::try_convert(&err).unwrap_or_else(|| Box::new(err))
    }
}
// =============================================================================
// Internal error for use with `chain_error`

#[derive(Debug)]
struct InternalAppError {
    description: String,
}

impl fmt::Display for InternalAppError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.description)?;
        Ok(())
    }
}

impl AppError for InternalAppError {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

#[derive(Debug)]
struct InternalAppErrorStatic {
    description: &'static str,
}

impl fmt::Display for InternalAppErrorStatic {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.description)?;
        Ok(())
    }
}

impl AppError for InternalAppErrorStatic {
    fn response(&self) -> Option<AppResponse> {
        None
    }
}

pub fn internal<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
    Box::new(InternalAppError {
        description: error.to_string(),
    })
}

#[derive(Debug, thiserror::Error)]
#[error("{0}")]
struct AppErrToStdErr(pub Box<dyn AppError>);

pub(crate) fn std_error(e: Box<dyn AppError>) -> Box<dyn Error + Send> {
    Box::new(AppErrToStdErr(e))
}

#[test]
fn chain_error_internal() {
    assert_eq!(
        None::<()>
            .chain_error(|| internal("inner"))
            .chain_error(|| internal("middle"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by middle caused by inner"
    );
    assert_eq!(
        Err::<(), _>(internal("inner"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner"
    );

    // Don't do this, the user will see a generic 500 error instead of the intended message
    assert_eq!(
        Err::<(), _>(cargo_err("inner"))
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner"
    );
    assert_eq!(
        Err::<(), _>(forbidden())
            .chain_error(|| internal("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by must be logged in to perform that action"
    );
}

#[test]
fn chain_error_user_facing() {
    // Do this rarely, the user will only see the outer error
    assert_eq!(
        Err::<(), _>(cargo_err("inner"))
            .chain_error(|| cargo_err("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by inner" // never logged
    );

    // The outer error is sent as a response to the client.
    // The inner error never bubbles up to the logging middleware
    assert_eq!(
        Err::<(), _>(std::io::Error::from(std::io::ErrorKind::PermissionDenied))
            .chain_error(|| cargo_err("outer"))
            .unwrap_err()
            .to_string(),
        "outer caused by permission denied" // never logged
    );
}
<|endoftext|>


<commit_before>use std::mem;
use std::slice;
use buffer::ArrayBufferBinding;
use types::DataType;

pub unsafe trait VertexData: Copy {
    type Binder: VertexAttribBinder;

    fn build_attrib_binder() -> <Self::Binder as VertexAttribBinder>::Builder;
}

pub trait VertexAttribBinder {
    type Builder;

    fn bind(&self, gl_buffer: &ArrayBufferBinding);
}

pub unsafe trait VertexPrimitive {
    fn gl_type() -> DataType;
}

unsafe impl VertexPrimitive for i8 {
    fn gl_type() -> DataType { DataType::Byte }
}

unsafe impl VertexPrimitive for u8 {
    fn gl_type() -> DataType { DataType::UnsignedByte }
}

unsafe impl VertexPrimitive for i16 {
    fn gl_type() -> DataType { DataType::Short }
}

unsafe impl VertexPrimitive for u16 {
    fn gl_type() -> DataType { DataType::UnsignedShort }
}

unsafe impl VertexPrimitive for f32 {
    fn gl_type() -> DataType { DataType::Float }
}

pub unsafe trait VertexDatum {
    fn gl_type() -> DataType;
    fn components() -> i8;
    fn normalized() -> bool { false }
}

unsafe impl<T> VertexDatum for T where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 1 }
}

unsafe impl<T> VertexDatum for [T; 1] where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 1 }
}

unsafe impl<T> VertexDatum for [T; 2] where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 2 }
}

unsafe impl<T> VertexDatum for [T; 3] where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 3 }
}

unsafe impl<T> VertexDatum for [T; 4] where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 4 }
}

pub trait VertexBytes {
    fn vertex_bytes(&self) -> &[u8];
}

impl<T> VertexBytes for T where T: VertexData {
    fn vertex_bytes(&self) -> &[u8] {
        unsafe {
            slice::from_raw_parts(mem::transmute(self), mem::size_of::<Self>())
        }
    }
}

impl<T> VertexBytes for [T] where T: VertexData {
    fn vertex_bytes(&self) -> &[u8] {
        let size = mem::size_of::<T>() * self.len();
        unsafe {
            slice::from_raw_parts(mem::transmute(&self[0]), size)
        }
    }
}

// TODO: Use a proper compiler intrinsic/macro (when available)
// see: https://github.com/rust-lang/rust/issues/24111
#[macro_export]
macro_rules! offset_of {
    ($T:ty, $field:ident) => {
        unsafe {
            use std::mem::{uninitialized, transmute};

            let obj : $T = uninitialized();
            let obj_ptr : *const u8 = transmute(&obj);
            let member_ptr : *const u8 = transmute(&obj.$field);

            (member_ptr as usize) - (obj_ptr as usize)
        }
    }
}

#[macro_use(offset_of)]
#[macro_export]
macro_rules! vertex_data {
    ($(
        struct $name:ident {
            $($field_name:ident: $field_type:ty),*
        }
    )+) => {
        mod _glitter_vertex_data {$(
            #[allow(non_snake_case)]
            pub mod $name {
                #[repr(C)]
                #[derive(Debug, Clone, Copy)]
                pub struct $name {
                    $(pub $field_name: $field_type),*
                }

                unsafe impl $crate::VertexData for $name {
                    type Binder = Binder;

                    fn build_attrib_binder() -> BinderBuilder {
                        BinderBuilder::new()
                    }
                }

                #[allow(dead_code)]
                pub struct Binder {
                    $($field_name: $crate::ProgramAttrib),*
                }

                impl $crate::VertexAttribBinder for Binder {
                    type Builder = BinderBuilder;

                    fn bind(&self, gl_buffer: &$crate::ArrayBufferBinding) {
                        use std::mem;
                        use $crate::VertexDatum as Datum;

                        $({
                            let components =
                                <$field_type as Datum>::components();
                            let gl_type =
                              <$field_type as Datum>::gl_type();
                            let normalized =
                                <$field_type as Datum>::normalized();
                            let stride = mem::size_of::<$name>();
                            let offset = offset_of!($name, $field_name);

                            unsafe {
                                gl_buffer.vertex_attrib_pointer(
                                    self.$field_name,
                                    components,
                                    gl_type,
                                    normalized,
                                    stride,
                                    offset);
                            }
                        };)*
                    }
                }

                #[allow(dead_code)]
                pub struct BinderBuilder {
                    $($field_name: Option<$crate::ProgramAttrib>),*
                }

                #[allow(dead_code)]
                impl BinderBuilder {
                    pub fn new() -> Self {
                        BinderBuilder {
                            $($field_name: None),*
                        }
                    }

                    pub fn unwrap(self, gl: &$crate::Context) -> self::Binder {
                        let binder = self::Binder {
                            $($field_name: self.$field_name.expect(
                                concat!("No attribute provided for ",
                                        stringify!($field_name))
                            )),*
                        };

                        $(gl.enable_vertex_attrib_array(binder.$field_name);)*

                        binder
                    }

                    $(
                        pub fn $field_name(mut self,
                                           attrib: $crate::ProgramAttrib)
                        -> Self
                        {
                            self.$field_name = Some(attrib);
                            self
                        }
                    )*
                }
            })+
        }

        $(
            #[allow(unused_imports)]
            use self::_glitter_vertex_data::$name::$name;
        )+
    }
}
<commit_msg>Make `vertex_data!` more flexible<commit_after>use std::mem;
use std::slice;
use buffer::ArrayBufferBinding;
use types::DataType;

pub unsafe trait VertexData: Copy {
    type Binder: VertexAttribBinder;

    fn build_attrib_binder() -> <Self::Binder as VertexAttribBinder>::Builder;
}

pub trait VertexAttribBinder {
    type Builder;

    fn bind(&self, gl_buffer: &ArrayBufferBinding);
}

pub unsafe trait VertexPrimitive {
    fn gl_type() -> DataType;
}

unsafe impl VertexPrimitive for i8 {
    fn gl_type() -> DataType { DataType::Byte }
}

unsafe impl VertexPrimitive for u8 {
    fn gl_type() -> DataType { DataType::UnsignedByte }
}

unsafe impl VertexPrimitive for i16 {
    fn gl_type() -> DataType { DataType::Short }
}

unsafe impl VertexPrimitive for u16 {
    fn gl_type() -> DataType { DataType::UnsignedShort }
}

unsafe impl VertexPrimitive for f32 {
    fn gl_type() -> DataType { DataType::Float }
}

pub unsafe trait VertexDatum {
    fn gl_type() -> DataType;
    fn components() -> i8;
    fn normalized() -> bool { false }
}

unsafe impl<T> VertexDatum for T where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 1 }
}

unsafe impl<T> VertexDatum for [T; 1] where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 1 }
}

unsafe impl<T> VertexDatum for [T; 2] where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 2 }
}

unsafe impl<T> VertexDatum for [T; 3] where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 3 }
}

unsafe impl<T> VertexDatum for [T; 4] where T: VertexPrimitive {
    fn gl_type() -> DataType { <T as VertexPrimitive>::gl_type() }
    fn components() -> i8 { 4 }
}

pub trait VertexBytes {
    fn vertex_bytes(&self) -> &[u8];
}

impl<T> VertexBytes for T where T: VertexData {
    fn vertex_bytes(&self) -> &[u8] {
        unsafe {
            slice::from_raw_parts(mem::transmute(self), mem::size_of::<Self>())
        }
    }
}

impl<T> VertexBytes for [T] where T: VertexData {
    fn vertex_bytes(&self) -> &[u8] {
        let size = mem::size_of::<T>() * self.len();
        unsafe {
            slice::from_raw_parts(mem::transmute(&self[0]), size)
        }
    }
}

// TODO: Use a proper compiler intrinsic/macro (when available)
// see: https://github.com/rust-lang/rust/issues/24111
#[macro_export]
macro_rules! offset_of {
    ($T:ty, $field:ident) => {
        unsafe {
            use std::mem::{uninitialized, transmute};

            let obj : $T = uninitialized();
            let obj_ptr : *const u8 = transmute(&obj);
            let member_ptr : *const u8 = transmute(&obj.$field);

            (member_ptr as usize) - (obj_ptr as usize)
        }
    }
}

#[macro_export]
macro_rules! _glitter_vertex_data_reexport {
    ({ }, $name:ident) => {
        #[allow(unused_imports)]
        use self::_glitter_vertex_data::$name::$name;
    };
    ({ pub }, $name:ident) => {
        #[allow(unused_imports)]
        pub use self::_glitter_vertex_data::$name::$name;
    }
}

#[macro_use(offset_of, _glitter_vertex_data_reexport)]
#[macro_export]
macro_rules! vertex_data {
    (
        $(
            $(#[$($attrs:tt)*])*
            struct $name:ident {
                $($field_name:ident: $field_type:ty),*
            }
        )+
    ) => {
        vertex_data! {
            $(
                $(#[$($attrs)*])*,
                { },
                @struct $name { $($field_name: $field_type),* }
            )+,
        }
    };
    (
        $(
            $(#[$($attrs:tt)*])*
            pub struct $name:ident {
                $($field_name:ident: $field_type:ty),*
            }
        )+
    ) => {
        vertex_data! {
            $(
                $(#[$($attrs)*])*,
                { pub },
                @struct $name { $($field_name: $field_type),* }
            )+,
        }
    };
    (
        $(
            $(#[$($attrs:tt)*])*,
            { $($modifiers:tt)* },
            @struct $name:ident {
                $($field_name:ident: $field_type:ty),*
            }
        )+,
    ) => {
        mod _glitter_vertex_data {$(
            #[allow(non_snake_case)]
            pub mod $name {
                #[repr(C)]
                #[derive(Debug, Clone, Copy)]
                $(#[$($attrs)*])*
                pub struct $name {
                    $(pub $field_name: $field_type),*
                }

                unsafe impl $crate::VertexData for $name {
                    type Binder = Binder;

                    fn build_attrib_binder() -> BinderBuilder {
                        BinderBuilder::new()
                    }
                }

                #[allow(dead_code)]
                pub struct Binder {
                    $($field_name: $crate::ProgramAttrib),*
                }

                impl $crate::VertexAttribBinder for Binder {
                    type Builder = BinderBuilder;

                    fn bind(&self, gl_buffer: &$crate::ArrayBufferBinding) {
                        use std::mem;
                        use $crate::VertexDatum as Datum;

                        $({
                            let components =
                                <$field_type as Datum>::components();
                            let gl_type =
                              <$field_type as Datum>::gl_type();
                            let normalized =
                                <$field_type as Datum>::normalized();
                            let stride = mem::size_of::<$name>();
                            let offset = offset_of!($name, $field_name);

                            unsafe {
                                gl_buffer.vertex_attrib_pointer(
                                    self.$field_name,
                                    components,
                                    gl_type,
                                    normalized,
                                    stride,
                                    offset);
                            }
                        };)*
                    }
                }

                #[allow(dead_code)]
                pub struct BinderBuilder {
                    $($field_name: Option<$crate::ProgramAttrib>),*
                }

                #[allow(dead_code)]
                impl BinderBuilder {
                    pub fn new() -> Self {
                        BinderBuilder {
                            $($field_name: None),*
                        }
                    }

                    pub fn unwrap(self, gl: &$crate::Context) -> self::Binder {
                        let binder = self::Binder {
                            $($field_name: self.$field_name.expect(
                                concat!("No attribute provided for ",
                                        stringify!($field_name))
                            )),*
                        };

                        $(gl.enable_vertex_attrib_array(binder.$field_name);)*

                        binder
                    }

                    $(
                        pub fn $field_name(mut self,
                                           attrib: $crate::ProgramAttrib)
                        -> Self
                        {
                            self.$field_name = Some(attrib);
                            self
                        }
                    )*
                }
            })+
        }

        $(
            _glitter_vertex_data_reexport!({ $($modifiers)* }, $name);
        )+
    }
}
<|endoftext|>