<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#![allow(dead_code)]

use libc::{self, c_int, c_ulong, c_void, ioctl, read, ENOENT};
use std::ffi::CString;
use std::fmt;
use std::fs::{File, OpenOptions};
use std::io;
use std::mem::size_of;
use std::os::unix::io::AsRawFd;
use std::time::Duration;

use crate::gpio::{Error, Level, Result, Trigger};

#[cfg(target_env = "gnu")]
type IoctlLong = libc::c_ulong;
#[cfg(target_env = "musl")]
type IoctlLong = libc::c_long;

const CONSUMER_LABEL: &str = "RPPAL";
const DRIVER_NAME: &[u8] = b"pinctrl-bcm2835\0";

const NRBITS: u8 = 8;
const TYPEBITS: u8 = 8;
const SIZEBITS: u8 = 14;
const DIRBITS: u8 = 2;

const NRSHIFT: u8 = 0;
const TYPESHIFT: u8 = (NRSHIFT + NRBITS);
const SIZESHIFT: u8 = (TYPESHIFT + TYPEBITS);
const DIRSHIFT: u8 = (SIZESHIFT + SIZEBITS);

const NR_GET_CHIP_INFO: IoctlLong = 0x01 << NRSHIFT;
const NR_GET_LINE_INFO: IoctlLong = 0x02 << NRSHIFT;
const NR_GET_LINE_HANDLE: IoctlLong = 0x03 << NRSHIFT;
const NR_GET_LINE_EVENT: IoctlLong = 0x04 << NRSHIFT;
const NR_GET_LINE_VALUES: IoctlLong = 0x08 << NRSHIFT;
const NR_SET_LINE_VALUES: IoctlLong = 0x09 << NRSHIFT;

const TYPE_GPIO: IoctlLong = (0xB4 as IoctlLong) << TYPESHIFT;

const SIZE_CHIP_INFO: IoctlLong = (size_of::<ChipInfo>() as IoctlLong) << SIZESHIFT;
const SIZE_LINE_INFO: IoctlLong = (size_of::<LineInfo>() as IoctlLong) << SIZESHIFT;
const SIZE_HANDLE_REQUEST: IoctlLong = (size_of::<HandleRequest>() as IoctlLong) << SIZESHIFT;
const SIZE_EVENT_REQUEST: IoctlLong = (size_of::<EventRequest>() as IoctlLong) << SIZESHIFT;
const SIZE_HANDLE_DATA: IoctlLong = (size_of::<HandleData>() as IoctlLong) << SIZESHIFT;

const DIR_NONE: c_ulong = 0;
const DIR_WRITE: IoctlLong = 1 << DIRSHIFT;
const DIR_READ: IoctlLong = 2 << DIRSHIFT;
const DIR_READ_WRITE: IoctlLong = DIR_READ | DIR_WRITE;

const REQ_GET_CHIP_INFO: IoctlLong = DIR_READ | TYPE_GPIO | NR_GET_CHIP_INFO | SIZE_CHIP_INFO;
const REQ_GET_LINE_INFO: IoctlLong = DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_INFO | SIZE_LINE_INFO;
const REQ_GET_LINE_HANDLE: IoctlLong =
    DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_HANDLE | SIZE_HANDLE_REQUEST;
const REQ_GET_LINE_EVENT: IoctlLong =
    DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_EVENT | SIZE_EVENT_REQUEST;
const REQ_GET_LINE_VALUES: IoctlLong =
    DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_VALUES | SIZE_HANDLE_DATA;
const REQ_SET_LINE_VALUES: IoctlLong =
    DIR_READ_WRITE | TYPE_GPIO | NR_SET_LINE_VALUES | SIZE_HANDLE_DATA;

const NAME_BUFSIZE: usize = 32;
const LABEL_BUFSIZE: usize = 32;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct ChipInfo {
    pub name: [u8; NAME_BUFSIZE],
    pub label: [u8; LABEL_BUFSIZE],
    pub lines: u32,
}

impl ChipInfo {
    pub fn new(cdev_fd: c_int) -> Result<ChipInfo> {
        let mut chip_info = ChipInfo {
            name: [0u8; NAME_BUFSIZE],
            label: [0u8; LABEL_BUFSIZE],
            lines: 0,
        };

        parse_retval!(unsafe { ioctl(cdev_fd, REQ_GET_CHIP_INFO, &mut chip_info) })?;

        Ok(chip_info)
    }
}

const LINE_FLAG_KERNEL: u32 = 0x01;
const LINE_FLAG_IS_OUT: u32 = 0x02;
const LINE_FLAG_ACTIVE_LOW: u32 = 0x04;
const LINE_FLAG_OPEN_DRAIN: u32 = 0x08;
const LINE_FLAG_OPEN_SOURCE: u32 = 0x10;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct LineInfo {
    pub line_offset: u32,
    pub flags: u32,
    pub name: [u8; NAME_BUFSIZE],
    pub consumer: [u8; LABEL_BUFSIZE],
}

impl LineInfo {
    pub fn new() -> LineInfo {
        LineInfo {
            line_offset: 0,
            flags: 0,
            name: [0u8; NAME_BUFSIZE],
            consumer: [0u8; LABEL_BUFSIZE],
        }
    }
}

impl fmt::Debug for LineInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("LineInfo")
            .field("line_offset", &self.line_offset)
            .field("flags", &self.flags)
            .field("name", &cbuf_to_cstring(&self.name))
            .field("consumer", &cbuf_to_cstring(&self.consumer))
            .finish()
    }
}

const HANDLES_MAX: usize = 64;
const HANDLE_FLAG_INPUT: u32 = 0x01;
const HANDLE_FLAG_OUTPUT: u32 = 0x02;
const HANDLE_FLAG_ACTIVE_LOW: u32 = 0x04;
const HANDLE_FLAG_OPEN_DRAIN: u32 = 0x08;
const HANDLE_FLAG_OPEN_SOURCE: u32 = 0x10;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct HandleRequest {
    pub line_offsets: [u32; HANDLES_MAX],
    pub flags: u32,
    pub default_values: [u8; HANDLES_MAX],
    pub consumer_label: [u8; LABEL_BUFSIZE],
    pub lines: u32,
    pub fd: c_int,
}

impl fmt::Debug for HandleRequest {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("HandleRequest")
            .field(
                "line_offsets",
                &format_args!("{:?}", &self.line_offsets[..self.lines as usize]),
            )
            .field("flags", &self.flags)
            .field(
                "default_values",
                &format_args!("{:?}", &self.default_values[..self.lines as usize]),
            )
            .field("consumer_label", &cbuf_to_cstring(&self.consumer_label))
            .field("lines", &self.lines)
            .field("fd", &self.fd)
            .finish()
    }
}

impl HandleRequest {
    pub fn new(cdev_fd: c_int, pins: &[u8]) -> Result<HandleRequest> {
        let mut handle_request = HandleRequest {
            line_offsets: [0u32; HANDLES_MAX],
            flags: 0,
            default_values: [0u8; HANDLES_MAX],
            consumer_label: [0u8; LABEL_BUFSIZE],
            lines: 0,
            fd: 0,
        };

        let pins: &[u8] = if pins.len() > HANDLES_MAX {
            handle_request.lines = HANDLES_MAX as u32;
            &pins[0..HANDLES_MAX]
        } else {
            handle_request.lines = pins.len() as u32;
            pins
        };

        for (idx, pin) in pins.iter().enumerate() {
            handle_request.line_offsets[idx] = u32::from(*pin);
        }

        // Set consumer label, so other processes know we're using this handle
        handle_request.consumer_label[0..CONSUMER_LABEL.len()]
            .copy_from_slice(CONSUMER_LABEL.as_bytes());

        parse_retval!(unsafe { ioctl(cdev_fd, REQ_GET_LINE_HANDLE, &mut handle_request) })?;

        Ok(handle_request)
    }

    pub fn levels(&self) -> Result<HandleData> {
        let mut handle_data = HandleData::new();

        parse_retval!(unsafe { ioctl(self.fd, REQ_GET_LINE_VALUES, &mut handle_data) })?;

        Ok(handle_data)
    }

    pub fn set_levels(&mut self, levels: &[Level]) -> Result<()> {
        let mut handle_data = HandleData::new();
        let levels: &[Level] = if levels.len() > HANDLES_MAX {
            &levels[0..HANDLES_MAX]
        } else {
            levels
        };

        for (idx, level) in levels.iter().enumerate() {
            handle_data.values[idx] = *level as u8;
        }

        parse_retval!(unsafe { ioctl(self.fd, REQ_SET_LINE_VALUES, &mut handle_data) })?;

        Ok(())
    }
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct HandleData {
    pub values: [u8; HANDLES_MAX],
}

impl HandleData {
    pub fn new() -> HandleData {
        HandleData {
            values: [0u8; HANDLES_MAX],
        }
    }
}

const EVENT_FLAG_RISING_EDGE: u32 = 0x01;
const EVENT_FLAG_FALLING_EDGE: u32 = 0x02;
const EVENT_FLAG_BOTH_EDGES: u32 = EVENT_FLAG_RISING_EDGE | EVENT_FLAG_FALLING_EDGE;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct EventRequest {
    pub line_offset: u32,
    pub handle_flags: u32,
    pub event_flags: u32,
    pub consumer_label: [u8; LABEL_BUFSIZE],
    pub fd: c_int,
}

impl EventRequest {
    pub fn new(cdev_fd: c_int, pin: u8, trigger: Trigger) -> Result<EventRequest> {
        let mut event_request = EventRequest {
            line_offset: u32::from(pin),
            handle_flags: HANDLE_FLAG_INPUT,
            event_flags: trigger as u32,
            consumer_label: [0u8; LABEL_BUFSIZE],
            fd: 0,
        };

        // Set consumer label, so other processes know we're using this event
        event_request.consumer_label[0..CONSUMER_LABEL.len()]
            .copy_from_slice(CONSUMER_LABEL.as_bytes());

        parse_retval!(unsafe { ioctl(cdev_fd, REQ_GET_LINE_EVENT, &mut event_request) })?;

        Ok(event_request)
    }
}

const EVENT_TYPE_RISING_EDGE: u32 = 0x01;
const EVENT_TYPE_FALLING_EDGE: u32 = 0x02;

#[derive(Copy, Clone, Default)]
#[repr(C)]
struct EventData {
    timestamp: u64,
    id: u32,
}

impl EventData {
    fn new(event_fd: c_int) -> Result<EventData> {
        let mut event_data = EventData {
            timestamp: 0,
            id: 0,
        };

        let bytes_read = parse_retval!(unsafe {
            read(
                event_fd,
                &mut event_data as *mut EventData as *mut c_void,
                size_of::<EventData>(),
            )
        })?;

        if bytes_read < size_of::<EventData>() as isize {
            Err(std::io::Error::new(
                std::io::ErrorKind::UnexpectedEof,
                "failed to fill whole buffer",
            )
            .into())
        } else {
            Ok(event_data)
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub struct Event {
    pub trigger: Trigger,
    pub timestamp: Duration,
}

impl Event {
    fn from_event_data(event_data: EventData) -> Event {
        Event {
            trigger: match event_data.id {
                EVENT_TYPE_RISING_EDGE => Trigger::RisingEdge,
                EVENT_TYPE_FALLING_EDGE => Trigger::FallingEdge,
                _ => unreachable!(),
            },
            timestamp: Duration::from_nanos(event_data.timestamp),
        }
    }
}

// Read interrupt event
pub fn get_event(event_fd: c_int) -> Result<Event> {
    let event_data = EventData::new(event_fd)?;
    Ok(Event::from_event_data(event_data))
}

// Find the correct gpiochip device based on its label
pub fn find_gpiochip() -> Result<File> {
    for id in 0..=255 {
        let gpiochip = OpenOptions::new()
            .read(true)
            .write(true)
            .open(format!("/dev/gpiochip{}", id))?;

        let chip_info = ChipInfo::new(gpiochip.as_raw_fd())?;
        if chip_info.label[0..DRIVER_NAME.len()] == DRIVER_NAME[..] {
            return Ok(gpiochip);
        }
    }

    // File Not Found IO error
    Err(Error::Io(io::Error::from_raw_os_error(ENOENT)))
}

pub fn get_level(cdev_fd: c_int, pin: u8) -> Result<Level> {
    match HandleRequest::new(cdev_fd, &[pin])?.levels()?.values[0] {
        0 => Ok(Level::Low),
        1 => Ok(Level::High),
        _ => unreachable!(),
    }
}

pub fn close(fd: c_int) {
    unsafe {
        libc::close(fd);
    }
}

// Create a CString from a C-style NUL-terminated char array. This workaround
// is needed for fixed-length buffers that fill the remaining bytes with NULs,
// because CString::new() interprets those as a NUL in the middle of the byte
// slice and returns a NulError.
fn cbuf_to_cstring(buf: &[u8]) -> CString {
    CString::new({
        let pos = buf
            .iter()
            .position(|&c| c == b'\0')
            .unwrap_or_else(|| buf.len());
        &buf[..pos]
    })
    .unwrap_or_default()
}
<commit_msg>Close handle fd on drop<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#![allow(dead_code)]

use libc::{self, c_int, c_ulong, c_void, ioctl, read, ENOENT};
use std::ffi::CString;
use std::fmt;
use std::fs::{File, OpenOptions};
use std::io;
use std::mem::size_of;
use std::os::unix::io::AsRawFd;
use std::time::Duration;

use crate::gpio::{Error, Level, Result, Trigger};

#[cfg(target_env = "gnu")]
type IoctlLong = libc::c_ulong;
#[cfg(target_env = "musl")]
type IoctlLong = libc::c_long;

const CONSUMER_LABEL: &str = "RPPAL";
const DRIVER_NAME: &[u8] = b"pinctrl-bcm2835\0";

const NRBITS: u8 = 8;
const TYPEBITS: u8 = 8;
const SIZEBITS: u8 = 14;
const DIRBITS: u8 = 2;

const NRSHIFT: u8 = 0;
const TYPESHIFT: u8 = (NRSHIFT + NRBITS);
const SIZESHIFT: u8 = (TYPESHIFT + TYPEBITS);
const DIRSHIFT: u8 = (SIZESHIFT + SIZEBITS);

const NR_GET_CHIP_INFO: IoctlLong = 0x01 << NRSHIFT;
const NR_GET_LINE_INFO: IoctlLong = 0x02 << NRSHIFT;
const NR_GET_LINE_HANDLE: IoctlLong = 0x03 << NRSHIFT;
const NR_GET_LINE_EVENT: IoctlLong = 0x04 << NRSHIFT;
const NR_GET_LINE_VALUES: IoctlLong = 0x08 << NRSHIFT;
const NR_SET_LINE_VALUES: IoctlLong = 0x09 << NRSHIFT;

const TYPE_GPIO: IoctlLong = (0xB4 as IoctlLong) << TYPESHIFT;

const SIZE_CHIP_INFO: IoctlLong = (size_of::<ChipInfo>() as IoctlLong) << SIZESHIFT;
const SIZE_LINE_INFO: IoctlLong = (size_of::<LineInfo>() as IoctlLong) << SIZESHIFT;
const SIZE_HANDLE_REQUEST: IoctlLong = (size_of::<HandleRequest>() as IoctlLong) << SIZESHIFT;
const SIZE_EVENT_REQUEST: IoctlLong = (size_of::<EventRequest>() as IoctlLong) << SIZESHIFT;
const SIZE_HANDLE_DATA: IoctlLong = (size_of::<HandleData>() as IoctlLong) << SIZESHIFT;

const DIR_NONE: c_ulong = 0;
const DIR_WRITE: IoctlLong = 1 << DIRSHIFT;
const DIR_READ: IoctlLong = 2 << DIRSHIFT;
const DIR_READ_WRITE: IoctlLong = DIR_READ | DIR_WRITE;

const REQ_GET_CHIP_INFO: IoctlLong = DIR_READ | TYPE_GPIO | NR_GET_CHIP_INFO | SIZE_CHIP_INFO;
const REQ_GET_LINE_INFO: IoctlLong = DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_INFO | SIZE_LINE_INFO;
const REQ_GET_LINE_HANDLE: IoctlLong =
    DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_HANDLE | SIZE_HANDLE_REQUEST;
const REQ_GET_LINE_EVENT: IoctlLong =
    DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_EVENT | SIZE_EVENT_REQUEST;
const REQ_GET_LINE_VALUES: IoctlLong =
    DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_VALUES | SIZE_HANDLE_DATA;
const REQ_SET_LINE_VALUES: IoctlLong =
    DIR_READ_WRITE | TYPE_GPIO | NR_SET_LINE_VALUES | SIZE_HANDLE_DATA;

const NAME_BUFSIZE: usize = 32;
const LABEL_BUFSIZE: usize = 32;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct ChipInfo {
    pub name: [u8; NAME_BUFSIZE],
    pub label: [u8; LABEL_BUFSIZE],
    pub lines: u32,
}

impl ChipInfo {
    pub fn new(cdev_fd: c_int) -> Result<ChipInfo> {
        let mut chip_info = ChipInfo {
            name: [0u8; NAME_BUFSIZE],
            label: [0u8; LABEL_BUFSIZE],
            lines: 0,
        };

        parse_retval!(unsafe { ioctl(cdev_fd, REQ_GET_CHIP_INFO, &mut chip_info) })?;

        Ok(chip_info)
    }
}

const LINE_FLAG_KERNEL: u32 = 0x01;
const LINE_FLAG_IS_OUT: u32 = 0x02;
const LINE_FLAG_ACTIVE_LOW: u32 = 0x04;
const LINE_FLAG_OPEN_DRAIN: u32 = 0x08;
const LINE_FLAG_OPEN_SOURCE: u32 = 0x10;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct LineInfo {
    pub line_offset: u32,
    pub flags: u32,
    pub name: [u8; NAME_BUFSIZE],
    pub consumer: [u8; LABEL_BUFSIZE],
}

impl LineInfo {
    pub fn new() -> LineInfo {
        LineInfo {
            line_offset: 0,
            flags: 0,
            name: [0u8; NAME_BUFSIZE],
            consumer: [0u8; LABEL_BUFSIZE],
        }
    }
}

impl fmt::Debug for LineInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("LineInfo")
            .field("line_offset", &self.line_offset)
            .field("flags", &self.flags)
            .field("name", &cbuf_to_cstring(&self.name))
            .field("consumer", &cbuf_to_cstring(&self.consumer))
            .finish()
    }
}

const HANDLES_MAX: usize = 64;
const HANDLE_FLAG_INPUT: u32 = 0x01;
const HANDLE_FLAG_OUTPUT: u32 = 0x02;
const HANDLE_FLAG_ACTIVE_LOW: u32 = 0x04;
const HANDLE_FLAG_OPEN_DRAIN: u32 = 0x08;
const HANDLE_FLAG_OPEN_SOURCE: u32 = 0x10;

#[repr(C)]
pub struct HandleRequest {
    pub line_offsets: [u32; HANDLES_MAX],
    pub flags: u32,
    pub default_values: [u8; HANDLES_MAX],
    pub consumer_label: [u8; LABEL_BUFSIZE],
    pub lines: u32,
    pub fd: c_int,
}

impl fmt::Debug for HandleRequest {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("HandleRequest")
            .field(
                "line_offsets",
                &format_args!("{:?}", &self.line_offsets[..self.lines as usize]),
            )
            .field("flags", &self.flags)
            .field(
                "default_values",
                &format_args!("{:?}", &self.default_values[..self.lines as usize]),
            )
            .field("consumer_label", &cbuf_to_cstring(&self.consumer_label))
            .field("lines", &self.lines)
            .field("fd", &self.fd)
            .finish()
    }
}

impl HandleRequest {
    pub fn new(cdev_fd: c_int, pins: &[u8]) -> Result<HandleRequest> {
        let mut handle_request = HandleRequest {
            line_offsets: [0u32; HANDLES_MAX],
            flags: 0,
            default_values: [0u8; HANDLES_MAX],
            consumer_label: [0u8; LABEL_BUFSIZE],
            lines: 0,
            fd: 0,
        };

        let pins: &[u8] = if pins.len() > HANDLES_MAX {
            handle_request.lines = HANDLES_MAX as u32;
            &pins[0..HANDLES_MAX]
        } else {
            handle_request.lines = pins.len() as u32;
            pins
        };

        for (idx, pin) in pins.iter().enumerate() {
            handle_request.line_offsets[idx] = u32::from(*pin);
        }

        // Set consumer label, so other processes know we're using this handle
        handle_request.consumer_label[0..CONSUMER_LABEL.len()]
            .copy_from_slice(CONSUMER_LABEL.as_bytes());

        parse_retval!(unsafe { ioctl(cdev_fd, REQ_GET_LINE_HANDLE, &mut handle_request) })?;

        Ok(handle_request)
    }

    pub fn levels(&self) -> Result<HandleData> {
        let mut handle_data = HandleData::new();

        parse_retval!(unsafe { ioctl(self.fd, REQ_GET_LINE_VALUES, &mut handle_data) })?;

        Ok(handle_data)
    }

    pub fn set_levels(&mut self, levels: &[Level]) -> Result<()> {
        let mut handle_data = HandleData::new();
        let levels: &[Level] = if levels.len() > HANDLES_MAX {
            &levels[0..HANDLES_MAX]
        } else {
            levels
        };

        for (idx, level) in levels.iter().enumerate() {
            handle_data.values[idx] = *level as u8;
        }

        parse_retval!(unsafe { ioctl(self.fd, REQ_SET_LINE_VALUES, &mut handle_data) })?;

        Ok(())
    }
}

impl Drop for HandleRequest {
    fn drop(&mut self) {
        close(self.fd);
    }
}

#[derive(Copy, Clone)]
#[repr(C)]
pub struct HandleData {
    pub values: [u8; HANDLES_MAX],
}

impl HandleData {
    pub fn new() -> HandleData {
        HandleData {
            values: [0u8; HANDLES_MAX],
        }
    }
}

const EVENT_FLAG_RISING_EDGE: u32 = 0x01;
const EVENT_FLAG_FALLING_EDGE: u32 = 0x02;
const EVENT_FLAG_BOTH_EDGES: u32 = EVENT_FLAG_RISING_EDGE | EVENT_FLAG_FALLING_EDGE;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct EventRequest {
    pub line_offset: u32,
    pub handle_flags: u32,
    pub event_flags: u32,
    pub consumer_label: [u8; LABEL_BUFSIZE],
    pub fd: c_int,
}

impl EventRequest {
    pub fn new(cdev_fd: c_int, pin: u8, trigger: Trigger) -> Result<EventRequest> {
        let mut event_request = EventRequest {
            line_offset: u32::from(pin),
            handle_flags: HANDLE_FLAG_INPUT,
            event_flags: trigger as u32,
            consumer_label: [0u8; LABEL_BUFSIZE],
            fd: 0,
        };

        // Set consumer label, so other processes know we're using this event
        event_request.consumer_label[0..CONSUMER_LABEL.len()]
            .copy_from_slice(CONSUMER_LABEL.as_bytes());

        parse_retval!(unsafe { ioctl(cdev_fd, REQ_GET_LINE_EVENT, &mut event_request) })?;

        Ok(event_request)
    }
}

const EVENT_TYPE_RISING_EDGE: u32 = 0x01;
const EVENT_TYPE_FALLING_EDGE: u32 = 0x02;

#[derive(Copy, Clone, Default)]
#[repr(C)]
struct EventData {
    timestamp: u64,
    id: u32,
}

impl EventData {
    fn new(event_fd: c_int) -> Result<EventData> {
        let mut event_data = EventData {
            timestamp: 0,
            id: 0,
        };

        let bytes_read = parse_retval!(unsafe {
            read(
                event_fd,
                &mut event_data as *mut EventData as *mut c_void,
                size_of::<EventData>(),
            )
        })?;

        if bytes_read < size_of::<EventData>() as isize {
            Err(std::io::Error::new(
                std::io::ErrorKind::UnexpectedEof,
                "failed to fill whole buffer",
            )
            .into())
        } else {
            Ok(event_data)
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub struct Event {
    pub trigger: Trigger,
    pub timestamp: Duration,
}

impl Event {
    fn from_event_data(event_data: EventData) -> Event {
        Event {
            trigger: match event_data.id {
                EVENT_TYPE_RISING_EDGE => Trigger::RisingEdge,
                EVENT_TYPE_FALLING_EDGE => Trigger::FallingEdge,
                _ => unreachable!(),
            },
            timestamp: Duration::from_nanos(event_data.timestamp),
        }
    }
}

// Read interrupt event
pub fn get_event(event_fd: c_int) -> Result<Event> {
    let event_data = EventData::new(event_fd)?;
    Ok(Event::from_event_data(event_data))
}

// Find the correct gpiochip device based on its label
pub fn find_gpiochip() -> Result<File> {
    for id in 0..=255 {
        let gpiochip = OpenOptions::new()
            .read(true)
            .write(true)
            .open(format!("/dev/gpiochip{}", id))?;

        let chip_info = ChipInfo::new(gpiochip.as_raw_fd())?;
        if chip_info.label[0..DRIVER_NAME.len()] == DRIVER_NAME[..] {
            return Ok(gpiochip);
        }
    }

    // File Not Found IO error
    Err(Error::Io(io::Error::from_raw_os_error(ENOENT)))
}

pub fn get_level(cdev_fd: c_int, pin: u8) -> Result<Level> {
    match HandleRequest::new(cdev_fd, &[pin])?.levels()?.values[0] {
        0 => Ok(Level::Low),
        1 => Ok(Level::High),
        _ => unreachable!(),
    }
}

pub fn close(fd: c_int) {
    unsafe {
        libc::close(fd);
    }
}

// Create a CString from a C-style NUL-terminated char array. This workaround
// is needed for fixed-length buffers that fill the remaining bytes with NULs,
// because CString::new() interprets those as a NUL in the middle of the byte
// slice and returns a NulError.
fn cbuf_to_cstring(buf: &[u8]) -> CString {
    CString::new({
        let pos = buf
            .iter()
            .position(|&c| c == b'\0')
            .unwrap_or_else(|| buf.len());
        &buf[..pos]
    })
    .unwrap_or_default()
}
<|endoftext|>


<commit_before>pub use std::mem;
pub use std::slice;

pub enum IndexDatumType {
    UnsignedByte,
    UnsignedShort
}

pub trait IndexData {
    fn index_datum_type() -> IndexDatumType;
    fn index_bytes(&self) -> &[u8];
    fn index_elements(&self) -> usize;
}

pub trait IndexDatum {
    fn index_datum_type() -> IndexDatumType;
}

impl IndexDatum for u8 {
    fn index_datum_type() -> IndexDatumType { IndexDatumType::UnsignedByte }
}

impl IndexDatum for u16 {
    fn index_datum_type() -> IndexDatumType { IndexDatumType::UnsignedShort }
}
<commit_msg>Add impl of `IndexData` for arrays of `IndexDatum`s<commit_after>pub use std::mem;
pub use std::slice;

pub enum IndexDatumType {
    UnsignedByte,
    UnsignedShort
}

pub trait IndexData {
    fn index_datum_type() -> IndexDatumType;
    fn index_bytes(&self) -> &[u8];
    fn index_elements(&self) -> usize;
}

pub trait IndexDatum {
    fn index_datum_type() -> IndexDatumType;
}

impl IndexDatum for u8 {
    fn index_datum_type() -> IndexDatumType { IndexDatumType::UnsignedByte }
}

impl IndexDatum for u16 {
    fn index_datum_type() -> IndexDatumType { IndexDatumType::UnsignedShort }
}

impl<T: IndexDatum> IndexData for [T] {
    fn index_datum_type() -> IndexDatumType {
        T::index_datum_type()
    }

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

    fn index_elements(&self) -> usize {
        self.len()
    }
}
<|endoftext|>


<commit_before>mod actions;
mod core;
pub mod commands;

pub use self::actions::movement::MovementError;

pub use self::core::action::{Action, ActionErr};
pub use self::core::container::{Container, ContainerType, Handle, Layout};
pub use self::core::tree::{Direction, TreeError};
use self::core::InnerTree;

use petgraph::graph::NodeIndex;
use rustc_serialize::json::{Json, ToJson};

use std::sync::{Mutex, MutexGuard, TryLockError};

/// A wrapper around tree, to hide its methods
pub struct Tree(TreeGuard);
/// Mutex guard around the tree
pub type TreeGuard = MutexGuard<'static, LayoutTree>;
/// Error for trying to lock the tree
pub type TreeErr = TryLockError<TreeGuard>;
/// Result for locking the tree
pub type TreeResult = Result<MutexGuard<'static, LayoutTree>, TreeErr>;

#[derive(Debug)]
pub struct LayoutTree {
    tree: InnerTree,
    active_container: Option<NodeIndex>
}

lazy_static! {
    static ref TREE: Mutex<LayoutTree> = {
        Mutex::new(LayoutTree {
            tree: InnerTree::new(),
            active_container: None
        })
    };
    static ref PREV_ACTION: Mutex<Option<Action>> = Mutex::new(None);
}

impl ToJson for LayoutTree {
    fn to_json(&self) -> Json {
        use std::collections::BTreeMap;
        fn node_to_json(node_ix: NodeIndex, tree: &LayoutTree) -> Json {
            match &tree.tree[node_ix] {
                &Container::Workspace { ref name, .. } => {
                    let mut inner_map = BTreeMap::new();
                    let children = tree.tree.children_of(node_ix).iter()
                        .map(|node| node_to_json(*node, tree)).collect();
                    inner_map.insert(format!("Workspace {}", name), Json::Array(children));
                    return Json::Object(inner_map);
                }
                &Container::Container { ref layout, .. } => {
                    let mut inner_map = BTreeMap::new();
                    let children = tree.tree.children_of(node_ix).iter()
                        .map(|node| node_to_json(*node, tree)).collect();
                    inner_map.insert(format!("Container w/ layout {:?}", layout), Json::Array(children));
                    return Json::Object(inner_map);
                }
                &Container::View { ref handle, .. } => {
                    return Json::String(handle.get_title());
                },
                ref container => {
                    let mut inner_map = BTreeMap::new();
                    let children = tree.tree.children_of(node_ix).iter()
                        .map(|node| node_to_json(*node, tree)).collect();
                    inner_map.insert(format!("{:?}", container.get_type()),
                                     Json::Array(children));
                    return Json::Object(inner_map)
                }
            }
        }
        return node_to_json(self.tree.root_ix(), self);
    }
}

/// Attempts to lock the tree. If the Result is Err, then the lock could
/// not be returned at this time, already locked.
pub fn try_lock_tree() -> Result<Tree, TreeErr> {
    let tree = try!(TREE.try_lock());
    Ok(Tree(tree))
}

/// Attempts to lock the action mutex. If the Result is Err, then the lock could
/// not be returned at this time, already locked.
pub fn try_lock_action() -> Result<MutexGuard<'static, Option<Action>>,
                                 TryLockError<MutexGuard<'static,
                                                         Option<Action>>>> {
    PREV_ACTION.try_lock()
}
<commit_msg>Debug tree command now returns Uuid of containers<commit_after>mod actions;
mod core;
pub mod commands;

pub use self::actions::movement::MovementError;

pub use self::core::action::{Action, ActionErr};
pub use self::core::container::{Container, ContainerType, Handle, Layout};
pub use self::core::tree::{Direction, TreeError};
use self::core::InnerTree;

use petgraph::graph::NodeIndex;
use rustc_serialize::json::{Json, ToJson};

use std::sync::{Mutex, MutexGuard, TryLockError};

/// A wrapper around tree, to hide its methods
pub struct Tree(TreeGuard);
/// Mutex guard around the tree
pub type TreeGuard = MutexGuard<'static, LayoutTree>;
/// Error for trying to lock the tree
pub type TreeErr = TryLockError<TreeGuard>;
/// Result for locking the tree
pub type TreeResult = Result<MutexGuard<'static, LayoutTree>, TreeErr>;

#[derive(Debug)]
pub struct LayoutTree {
    tree: InnerTree,
    active_container: Option<NodeIndex>
}

lazy_static! {
    static ref TREE: Mutex<LayoutTree> = {
        Mutex::new(LayoutTree {
            tree: InnerTree::new(),
            active_container: None
        })
    };
    static ref PREV_ACTION: Mutex<Option<Action>> = Mutex::new(None);
}

impl ToJson for LayoutTree {
    fn to_json(&self) -> Json {
        use std::collections::BTreeMap;
        fn node_to_json(node_ix: NodeIndex, tree: &LayoutTree) -> Json {
            match &tree.tree[node_ix] {
                &Container::Workspace { ref name, .. } => {
                    let mut inner_map = BTreeMap::new();
                    let children = tree.tree.children_of(node_ix).iter()
                        .map(|node| node_to_json(*node, tree)).collect();
                    inner_map.insert(format!("Workspace {}", name), Json::Array(children));
                    return Json::Object(inner_map);
                }
                &Container::Container { ref layout, id, .. } => {
                    let mut inner_map = BTreeMap::new();
                    let children = tree.tree.children_of(node_ix).iter()
                        .map(|node| node_to_json(*node, tree)).collect();
                    inner_map.insert(format!("Container w/ layout {:?} and id {:?}", layout, id),
                                     Json::Array(children));
                    return Json::Object(inner_map);
                }
                &Container::View { ref handle, id, .. } => {
                    return Json::String(format!("View: title: \"{:?}\", class: \"{:?}\", id: {}",
                                                handle.get_title(), handle.get_class(), id));
                },
                ref container => {
                    let mut inner_map = BTreeMap::new();
                    let children = tree.tree.children_of(node_ix).iter()
                        .map(|node| node_to_json(*node, tree)).collect();
                    inner_map.insert(format!("{:?}", container.get_type()),
                                     Json::Array(children));
                    return Json::Object(inner_map)
                }
            }
        }
        return node_to_json(self.tree.root_ix(), self);
    }
}

/// Attempts to lock the tree. If the Result is Err, then the lock could
/// not be returned at this time, already locked.
pub fn try_lock_tree() -> Result<Tree, TreeErr> {
    let tree = try!(TREE.try_lock());
    Ok(Tree(tree))
}

/// Attempts to lock the action mutex. If the Result is Err, then the lock could
/// not be returned at this time, already locked.
pub fn try_lock_action() -> Result<MutexGuard<'static, Option<Action>>,
                                 TryLockError<MutexGuard<'static,
                                                         Option<Action>>>> {
    PREV_ACTION.try_lock()
}
<|endoftext|>


<commit_before>// (c) 2016-2017 Productize SPRL <joost@productize.be>

// extension: .kicad_pcb
// format: new-style

use std::fmt;
use std::result;

// from parent
use Sexp;
use symbolic_expressions::IntoSexp;
use layout::data::*;

impl IntoSexp for Layout {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("kicad_pcb");

        v.push(("version", &self.version));

        let mut v2 = Sexp::start("host");
        v2.push(&self.host.tool);
        v2.push(&self.host.build);
        v.push(v2);

        v.push(self.general.into_sexp());

        v.push(("page", &self.page));

        let mut v2 = Sexp::start("layers");
        for layer in &self.layers {
            v2.push(layer.into_sexp());
        }
        v.push(v2);

        v.push(self.setup.into_sexp());

        for element in &self.elements {
            v.push(element.into_sexp());
        }
        v
    }
}

impl IntoSexp for General {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("general");
        v.push(("links", &self.links));
        v.push(("no_connects", &self.no_connects));
        v.push(self.area.into_sexp());
        v.push(("thickness", &self.thickness));
        v.push(("drawings", &self.drawings));
        v.push(("tracks", &self.tracks));
        v.push(("zones", &self.zones));
        v.push(("modules", &self.modules));
        v.push(("nets", &self.nets));
        v
    }
}

impl IntoSexp for Area {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("area");
        v.push(self.x1);
        v.push(self.y1);
        v.push(self.x2);
        v.push(self.y2);
        v
    }
}

impl IntoSexp for Element {
    fn into_sexp(&self) -> Sexp {
        match *self {
            Element::Other(ref s) => s.clone(),
            Element::Module(ref s) => s.into_sexp(),
            Element::Net(ref s) => s.into_sexp(),
            Element::NetClass(ref s) => s.into_sexp(),
            Element::GrText(ref s) => s.into_sexp(),
            Element::GrLine(ref s) => s.into_sexp(),
            Element::GrArc(ref s) => s.into_sexp(),
            Element::GrCircle(ref s) => s.into_sexp(),
            Element::Dimension(ref s) => s.into_sexp(),
            Element::Zone(ref s) => s.into_sexp(),
            Element::Segment(ref s) => s.into_sexp(),
            Element::Via(ref s) => s.into_sexp(),
        }
    }
}

impl IntoSexp for Zone {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("zone");
        v.push(("net", &self.net));
        v.push(("net_name", &self.net_name));
        v.push(("layer", &self.layer));
        v.push(("tstamp", &self.tstamp));
        v.push(self.hatch.into_sexp());
        if self.priority > 0 {
            v.push(("priority", &self.priority));
        }
        v.push(self.connect_pads.into_sexp());
        v.push(("min_thickness", &self.min_thickness));
        if let Some(ref keepout) = self.keepout {
            v.push(keepout.into_sexp());
        }
        v.push(self.fill.into_sexp());
        for p in &self.polygons {
            v.push(("polygon", p.into_sexp()))
        }
        for p in &self.filled_polygons {
            v.push(("filled_polygon", p.into_sexp()))
        }
        if let Some(ref s) = self.fill_segments {
            v.push(("fill_segments", s.into_sexp()))
        }
        for o in &self.other {
            v.push(o.clone());
        }
        v
    }
}

impl IntoSexp for Hatch {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("hatch");
        v.push(&self.style);
        v.push(self.pitch);
        v
    }
}

impl IntoSexp for ConnectPads {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("connect_pads");
        if let Some(ref connection) = self.connection {
            v.push(connection);
        }
        v.push(("clearance", &self.clearance));
        v
    }
}

fn allowed(a: bool) -> String {
    if a {
        "allowed".into()
    } else {
        "not_allowed".into()
    }
}

impl IntoSexp for Keepout {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("keepout");
        v.push(("tracks", &allowed(self.tracks)));
        v.push(("vias", &allowed(self.vias)));
        v.push(("copperpour", &allowed(self.copperpour)));
        v
    }
}
impl IntoSexp for Fill {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("fill");
        if self.filled {
            v.push("yes")
        }
        if self.segment {
            let s: String = "segment".into();
            v.push(("mode", &s))
        }
        v.push(("arc_segments", &self.arc_segments));
        v.push(("thermal_gap", &self.thermal_gap));
        v.push(("thermal_bridge_width", &self.thermal_bridge_width));
        if let Some(ref smoothing) = self.smoothing {
            v.push(("smoothing", smoothing))
        }
        if self.corner_radius != 0.0 {
            v.push(("radius", &self.corner_radius))
        }
        v
    }
}

impl IntoSexp for Net {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("net");
        v.push(self.num);
        v.push(&self.name.0);
        v
    }
}

impl IntoSexp for NetClass {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("net_class");
        v.push(&self.name);
        v.push(&self.desc);
        v.push(("clearance", &self.clearance));
        v.push(("trace_width", &self.trace_width));
        v.push(("via_dia", &self.via_dia));
        v.push(("via_drill", &self.via_drill));
        v.push(("uvia_dia", &self.uvia_dia));
        v.push(("uvia_drill", &self.uvia_drill));
        if let Some(diff_pair_gap) = self.diff_pair_gap {
            v.push(("diff_pair_gap", &diff_pair_gap));
        }
        if let Some(diff_pair_width) = self.diff_pair_width {
            v.push(("diff_pair_width", &diff_pair_width));
        }
        for net in &self.nets {
            v.push(("add_net", net));
        }
        v
    }
}

impl IntoSexp for Layer {
    fn into_sexp(&self) -> Sexp {
        let mut v = vec![];
        v.push(self.num.into());
        v.push(format!("{}", self.layer).into());
        v.push(format!("{}", self.layer_type).into());
        if self.hide {
            v.push("hide".into());
        }
        v.into()
    }
}

impl fmt::Display for LayerType {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        let s = match *self {
            LayerType::Signal => "signal",
            LayerType::Power => "power",
            LayerType::Mixed => "mixed",
            LayerType::Jumper => "jumper",
            LayerType::User => "user",
        };
        write!(f, "{}", s)
    }
}

impl IntoSexp for SetupElement {
    fn into_sexp(&self) -> Sexp {
        let mut v = vec![];
        v.push(self.name.clone().into());
        v.push(self.value1.clone().into());
        if let Some(ref x) = self.value2 {
            v.push(x.clone().into())
        }
        v.into()
    }
}

impl IntoSexp for Setup {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("setup");
        for k in &self.elements {
            v.push(k.into_sexp())
        }
        let mut v2 = Sexp::start("pcbplotparams");
        for k in &self.pcbplotparams {
            v2.push(k.into_sexp())
        }
        v.push(v2);
        v
    }
}

impl IntoSexp for GrText {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("gr_text");
        v.push(&self.value);
        v.push(self.at.into_sexp());
        v.push(("layer", &self.layer));
        v.push(self.effects.into_sexp());
        if let Some(ref tstamp) = self.tstamp {
            v.push(("tstamp", tstamp));
        }
        v
    }
}

impl IntoSexp for GrLine {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("gr_line");
        v.push(self.start.into_sexp());
        v.push(self.end.into_sexp());
        v.push(("angle", &self.angle));
        v.push(("layer", &self.layer));
        v.push(("width", &self.width));
        if let Some(ref tstamp) = self.tstamp {
            v.push(("tstamp", tstamp));
        }
        v
    }
}

impl IntoSexp for GrArc {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("gr_arc");
        v.push(self.start.into_sexp());
        v.push(self.end.into_sexp());
        v.push(("angle", &self.angle));
        v.push(("layer", &self.layer));
        v.push(("width", &self.width));
        if let Some(ref tstamp) = self.tstamp {
            v.push(("tstamp", tstamp));
        }
        v
    }
}

impl IntoSexp for GrCircle {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("gr_circle");
        v.push(self.center.into_sexp());
        v.push(self.end.into_sexp());
        v.push(("layer", &self.layer));
        v.push(("width", &self.width));
        if let Some(ref tstamp) = self.tstamp {
            v.push(("tstamp", tstamp));
        }
        v
    }
}

impl IntoSexp for Dimension {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("dimension");
        v.push(&self.name);
        v.push(("width", &self.width));
        v.push(("layer", &self.layer));
        if let Some(ref tstamp) = self.tstamp {
            v.push(("tstamp", tstamp));
        }
        v.push(self.text.into_sexp());
        v.push(("feature1", self.feature1.into_sexp()));
        v.push(("feature2", self.feature2.into_sexp()));
        v.push(("crossbar", self.crossbar.into_sexp()));
        v.push(("arrow1a", self.arrow1a.into_sexp()));
        v.push(("arrow1b", self.arrow1b.into_sexp()));
        v.push(("arrow2a", self.arrow2a.into_sexp()));
        v.push(("arrow2b", self.arrow2b.into_sexp()));
        v
    }
}

// (segment (start 117.5548 123.4602) (end 118.3848 122.6302) (width 0.2032) (layer B.Cu) (net 0) (tstamp 55E99398))
impl IntoSexp for Segment {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("segment");
        v.push(self.start.into_sexp());
        v.push(self.end.into_sexp());
        v.push(("width", &self.width));
        v.push(("layer", &self.layer));
        v.push(("net", &self.net));
        if let Some(ref tstamp) = self.tstamp {
            v.push(("tstamp", tstamp))
        }
        if let Some(ref status) = self.status {
            v.push(("status", status))
        }
        v
    }
}

// (via (at 132.1948 121.2202) (size 0.675) (drill 0.25) (layers F.Cu B.Cu) (net 19))

impl IntoSexp for Via {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("via");
        v.push(self.at.into_sexp());
        v.push(("size", &self.size));
        if self.drill != 0.0 {
            v.push(("drill", &self.drill));
        }
        v.push(self.layers.into_sexp());
        v.push(("net", &self.net));
        v
    }
}
<commit_msg>via: serialize blind and micro<commit_after>// (c) 2016-2017 Productize SPRL <joost@productize.be>

// extension: .kicad_pcb
// format: new-style

use std::fmt;
use std::result;

// from parent
use Sexp;
use symbolic_expressions::IntoSexp;
use layout::data::*;

impl IntoSexp for Layout {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("kicad_pcb");

        v.push(("version", &self.version));

        let mut v2 = Sexp::start("host");
        v2.push(&self.host.tool);
        v2.push(&self.host.build);
        v.push(v2);

        v.push(self.general.into_sexp());

        v.push(("page", &self.page));

        let mut v2 = Sexp::start("layers");
        for layer in &self.layers {
            v2.push(layer.into_sexp());
        }
        v.push(v2);

        v.push(self.setup.into_sexp());

        for element in &self.elements {
            v.push(element.into_sexp());
        }
        v
    }
}

impl IntoSexp for General {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("general");
        v.push(("links", &self.links));
        v.push(("no_connects", &self.no_connects));
        v.push(self.area.into_sexp());
        v.push(("thickness", &self.thickness));
        v.push(("drawings", &self.drawings));
        v.push(("tracks", &self.tracks));
        v.push(("zones", &self.zones));
        v.push(("modules", &self.modules));
        v.push(("nets", &self.nets));
        v
    }
}

impl IntoSexp for Area {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("area");
        v.push(self.x1);
        v.push(self.y1);
        v.push(self.x2);
        v.push(self.y2);
        v
    }
}

impl IntoSexp for Element {
    fn into_sexp(&self) -> Sexp {
        match *self {
            Element::Other(ref s) => s.clone(),
            Element::Module(ref s) => s.into_sexp(),
            Element::Net(ref s) => s.into_sexp(),
            Element::NetClass(ref s) => s.into_sexp(),
            Element::GrText(ref s) => s.into_sexp(),
            Element::GrLine(ref s) => s.into_sexp(),
            Element::GrArc(ref s) => s.into_sexp(),
            Element::GrCircle(ref s) => s.into_sexp(),
            Element::Dimension(ref s) => s.into_sexp(),
            Element::Zone(ref s) => s.into_sexp(),
            Element::Segment(ref s) => s.into_sexp(),
            Element::Via(ref s) => s.into_sexp(),
        }
    }
}

impl IntoSexp for Zone {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("zone");
        v.push(("net", &self.net));
        v.push(("net_name", &self.net_name));
        v.push(("layer", &self.layer));
        v.push(("tstamp", &self.tstamp));
        v.push(self.hatch.into_sexp());
        if self.priority > 0 {
            v.push(("priority", &self.priority));
        }
        v.push(self.connect_pads.into_sexp());
        v.push(("min_thickness", &self.min_thickness));
        if let Some(ref keepout) = self.keepout {
            v.push(keepout.into_sexp());
        }
        v.push(self.fill.into_sexp());
        for p in &self.polygons {
            v.push(("polygon", p.into_sexp()))
        }
        for p in &self.filled_polygons {
            v.push(("filled_polygon", p.into_sexp()))
        }
        if let Some(ref s) = self.fill_segments {
            v.push(("fill_segments", s.into_sexp()))
        }
        for o in &self.other {
            v.push(o.clone());
        }
        v
    }
}

impl IntoSexp for Hatch {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("hatch");
        v.push(&self.style);
        v.push(self.pitch);
        v
    }
}

impl IntoSexp for ConnectPads {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("connect_pads");
        if let Some(ref connection) = self.connection {
            v.push(connection);
        }
        v.push(("clearance", &self.clearance));
        v
    }
}

fn allowed(a: bool) -> String {
    if a {
        "allowed".into()
    } else {
        "not_allowed".into()
    }
}

impl IntoSexp for Keepout {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("keepout");
        v.push(("tracks", &allowed(self.tracks)));
        v.push(("vias", &allowed(self.vias)));
        v.push(("copperpour", &allowed(self.copperpour)));
        v
    }
}
impl IntoSexp for Fill {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("fill");
        if self.filled {
            v.push("yes")
        }
        if self.segment {
            let s: String = "segment".into();
            v.push(("mode", &s))
        }
        v.push(("arc_segments", &self.arc_segments));
        v.push(("thermal_gap", &self.thermal_gap));
        v.push(("thermal_bridge_width", &self.thermal_bridge_width));
        if let Some(ref smoothing) = self.smoothing {
            v.push(("smoothing", smoothing))
        }
        if self.corner_radius != 0.0 {
            v.push(("radius", &self.corner_radius))
        }
        v
    }
}

impl IntoSexp for Net {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("net");
        v.push(self.num);
        v.push(&self.name.0);
        v
    }
}

impl IntoSexp for NetClass {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("net_class");
        v.push(&self.name);
        v.push(&self.desc);
        v.push(("clearance", &self.clearance));
        v.push(("trace_width", &self.trace_width));
        v.push(("via_dia", &self.via_dia));
        v.push(("via_drill", &self.via_drill));
        v.push(("uvia_dia", &self.uvia_dia));
        v.push(("uvia_drill", &self.uvia_drill));
        if let Some(diff_pair_gap) = self.diff_pair_gap {
            v.push(("diff_pair_gap", &diff_pair_gap));
        }
        if let Some(diff_pair_width) = self.diff_pair_width {
            v.push(("diff_pair_width", &diff_pair_width));
        }
        for net in &self.nets {
            v.push(("add_net", net));
        }
        v
    }
}

impl IntoSexp for Layer {
    fn into_sexp(&self) -> Sexp {
        let mut v = vec![];
        v.push(self.num.into());
        v.push(format!("{}", self.layer).into());
        v.push(format!("{}", self.layer_type).into());
        if self.hide {
            v.push("hide".into());
        }
        v.into()
    }
}

impl fmt::Display for LayerType {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        let s = match *self {
            LayerType::Signal => "signal",
            LayerType::Power => "power",
            LayerType::Mixed => "mixed",
            LayerType::Jumper => "jumper",
            LayerType::User => "user",
        };
        write!(f, "{}", s)
    }
}

impl IntoSexp for SetupElement {
    fn into_sexp(&self) -> Sexp {
        let mut v = vec![];
        v.push(self.name.clone().into());
        v.push(self.value1.clone().into());
        if let Some(ref x) = self.value2 {
            v.push(x.clone().into())
        }
        v.into()
    }
}

impl IntoSexp for Setup {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("setup");
        for k in &self.elements {
            v.push(k.into_sexp())
        }
        let mut v2 = Sexp::start("pcbplotparams");
        for k in &self.pcbplotparams {
            v2.push(k.into_sexp())
        }
        v.push(v2);
        v
    }
}

impl IntoSexp for GrText {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("gr_text");
        v.push(&self.value);
        v.push(self.at.into_sexp());
        v.push(("layer", &self.layer));
        v.push(self.effects.into_sexp());
        if let Some(ref tstamp) = self.tstamp {
            v.push(("tstamp", tstamp));
        }
        v
    }
}

impl IntoSexp for GrLine {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("gr_line");
        v.push(self.start.into_sexp());
        v.push(self.end.into_sexp());
        v.push(("angle", &self.angle));
        v.push(("layer", &self.layer));
        v.push(("width", &self.width));
        if let Some(ref tstamp) = self.tstamp {
            v.push(("tstamp", tstamp));
        }
        v
    }
}

impl IntoSexp for GrArc {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("gr_arc");
        v.push(self.start.into_sexp());
        v.push(self.end.into_sexp());
        v.push(("angle", &self.angle));
        v.push(("layer", &self.layer));
        v.push(("width", &self.width));
        if let Some(ref tstamp) = self.tstamp {
            v.push(("tstamp", tstamp));
        }
        v
    }
}

impl IntoSexp for GrCircle {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("gr_circle");
        v.push(self.center.into_sexp());
        v.push(self.end.into_sexp());
        v.push(("layer", &self.layer));
        v.push(("width", &self.width));
        if let Some(ref tstamp) = self.tstamp {
            v.push(("tstamp", tstamp));
        }
        v
    }
}

impl IntoSexp for Dimension {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("dimension");
        v.push(&self.name);
        v.push(("width", &self.width));
        v.push(("layer", &self.layer));
        if let Some(ref tstamp) = self.tstamp {
            v.push(("tstamp", tstamp));
        }
        v.push(self.text.into_sexp());
        v.push(("feature1", self.feature1.into_sexp()));
        v.push(("feature2", self.feature2.into_sexp()));
        v.push(("crossbar", self.crossbar.into_sexp()));
        v.push(("arrow1a", self.arrow1a.into_sexp()));
        v.push(("arrow1b", self.arrow1b.into_sexp()));
        v.push(("arrow2a", self.arrow2a.into_sexp()));
        v.push(("arrow2b", self.arrow2b.into_sexp()));
        v
    }
}

// (segment (start 117.5548 123.4602) (end 118.3848 122.6302) (width 0.2032) (layer B.Cu) (net 0) (tstamp 55E99398))
impl IntoSexp for Segment {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("segment");
        v.push(self.start.into_sexp());
        v.push(self.end.into_sexp());
        v.push(("width", &self.width));
        v.push(("layer", &self.layer));
        v.push(("net", &self.net));
        if let Some(ref tstamp) = self.tstamp {
            v.push(("tstamp", tstamp))
        }
        if let Some(ref status) = self.status {
            v.push(("status", status))
        }
        v
    }
}

// (via (at 132.1948 121.2202) (size 0.675) (drill 0.25) (layers F.Cu B.Cu) (net 19))

impl IntoSexp for Via {
    fn into_sexp(&self) -> Sexp {
        let mut v = Sexp::start("via");
        if self.blind {
            v.push("blind")
        }
        if self.micro {
            v.push("micro")
        }
        v.push(self.at.into_sexp());
        v.push(("size", &self.size));
        if self.drill != 0.0 {
            v.push(("drill", &self.drill));
        }
        v.push(self.layers.into_sexp());
        v.push(("net", &self.net));
        v
    }
}
<|endoftext|>


<commit_before>use libc::{c_char, c_void};

#[link(name = "dl")]
extern "C" {
    fn dlsym(handle: *const c_void, symbol: *const c_char) -> *const c_void;
}

const RTLD_NEXT: *const c_void = -1isize as *const c_void;

pub unsafe fn dlsym_next(symbol: &'static str) -> *const u8 {
    let ptr = dlsym(RTLD_NEXT, symbol.as_ptr() as *const c_char);
    if ptr.is_null() {
        panic!("redhook: Unable to find underlying function for {}", symbol);
    }
    ptr as *const u8
}

#[macro_export]
macro_rules! hook {
    (unsafe fn $real_fn:ident ( $($v:ident : $t:ty),* ) -> $r:ty => $hook_fn:ident $body:block) => {
        #[allow(non_camel_case_types)]
        pub struct $real_fn {__private_field: ()}
        #[allow(non_upper_case_globals)]
        static $real_fn: $real_fn = $real_fn {__private_field: ()};

        impl $real_fn {
            fn get(&self) -> unsafe extern fn ( $($v : $t),* ) -> $r {
                use ::std::sync::{Once, ONCE_INIT};

                static mut REAL: *const u8 = 0 as *const u8;
                static mut ONCE: Once = ONCE_INIT;

                unsafe {
                    ONCE.call_once(|| {
                        REAL = $crate::ld_preload::dlsym_next(concat!(stringify!($real_fn), "\0"));
                    });
                    ::std::mem::transmute(REAL)
                }
            }

            #[no_mangle]
            pub unsafe extern fn $real_fn ( $($v : $t),* ) -> $r {
                ::std::panic::catch_unwind(|| $hook_fn ( $($v),* )).unwrap_or_else(|_| $real_fn.get() ( $($v),* ))
            }
        }

        pub unsafe fn $hook_fn ( $($v : $t),* ) -> $r {
            $body
        }
    };

    (unsafe fn $real_fn:ident ( $($v:ident : $t:ty),* ) => $hook_fn:ident $body:block) => {
        $crate::hook! { unsafe fn $real_fn ( $($v : $t),* ) -> () => $hook_fn $body }
    };
}

#[macro_export]
macro_rules! real {
    ($real_fn:ident) => {
        $real_fn.get()
    };
}
<commit_msg>Use std::sync::Once::new() insted of ONCE_INIT (fixes #16)<commit_after>use libc::{c_char, c_void};

#[link(name = "dl")]
extern "C" {
    fn dlsym(handle: *const c_void, symbol: *const c_char) -> *const c_void;
}

const RTLD_NEXT: *const c_void = -1isize as *const c_void;

pub unsafe fn dlsym_next(symbol: &'static str) -> *const u8 {
    let ptr = dlsym(RTLD_NEXT, symbol.as_ptr() as *const c_char);
    if ptr.is_null() {
        panic!("redhook: Unable to find underlying function for {}", symbol);
    }
    ptr as *const u8
}

#[macro_export]
macro_rules! hook {
    (unsafe fn $real_fn:ident ( $($v:ident : $t:ty),* ) -> $r:ty => $hook_fn:ident $body:block) => {
        #[allow(non_camel_case_types)]
        pub struct $real_fn {__private_field: ()}
        #[allow(non_upper_case_globals)]
        static $real_fn: $real_fn = $real_fn {__private_field: ()};

        impl $real_fn {
            fn get(&self) -> unsafe extern fn ( $($v : $t),* ) -> $r {
                use ::std::sync::Once;

                static mut REAL: *const u8 = 0 as *const u8;
                static mut ONCE: Once = Once::new();

                unsafe {
                    ONCE.call_once(|| {
                        REAL = $crate::ld_preload::dlsym_next(concat!(stringify!($real_fn), "\0"));
                    });
                    ::std::mem::transmute(REAL)
                }
            }

            #[no_mangle]
            pub unsafe extern fn $real_fn ( $($v : $t),* ) -> $r {
                ::std::panic::catch_unwind(|| $hook_fn ( $($v),* )).unwrap_or_else(|_| $real_fn.get() ( $($v),* ))
            }
        }

        pub unsafe fn $hook_fn ( $($v : $t),* ) -> $r {
            $body
        }
    };

    (unsafe fn $real_fn:ident ( $($v:ident : $t:ty),* ) => $hook_fn:ident $body:block) => {
        $crate::hook! { unsafe fn $real_fn ( $($v : $t),* ) -> () => $hook_fn $body }
    };
}

#[macro_export]
macro_rules! real {
    ($real_fn:ident) => {
        $real_fn.get()
    };
}
<|endoftext|>


<commit_before>use bindings::*;
use context::Context;
use function::Function;
use libc::c_uint;
use util::NativeRef;
use std::fmt::Show;
use std::kinds::marker::ContravariantLifetime;
use std::iter::Iterator;
use std::str::raw::from_c_str;
use std::c_str::ToCStr;
/// An ELF dependency iterator
pub struct Needed<'a> {
    _reader: jit_readelf_t,
    index: c_uint,
    marker: ContravariantLifetime<'a>
}
impl<'a> Needed<'a> {
    #[inline]
    fn new(read:&ReadElf<'a>) -> Needed<'a> {
        unsafe {
            Needed {
                _reader: read.as_ptr(),
                index: 0 as c_uint,
                marker: ContravariantLifetime::<'a>
            }
        }
    }
}
impl<'a> Iterator<String> for Needed<'a> {
    fn next(&mut self) -> Option<String> {
        let index = self.index;
        self.index += 1;
        unsafe {
            if index < jit_readelf_num_needed(self._reader) {
                let c_name = jit_readelf_get_needed(self._reader, index);
                let name = from_c_str(c_name);
                Some(name)
            } else {
                None
            }
        }
    }
}
/// An ELF binary reader
native_ref!(ReadElf, _reader, jit_readelf_t, ContravariantLifetime)
impl<'a> ReadElf<'a> {
    /// Open a new ELF binary
    pub fn new<S:ToCStr+Show>(filename:S) -> ReadElf<'a> {
        unsafe {
            let mut this = RawPtr::null();
            let code = filename.with_c_str(|c_name|
                jit_readelf_open(&mut this, c_name, 0)
            );
            if this.is_null() {
                fail!("'{}' couldn't be opened due to {}", filename, code);
            } else {
                NativeRef::from_ptr(this)
            }
        }
    }
    #[inline]
    /// Get the name of this ELF binary
    pub fn get_name(&self) -> String {
        unsafe {
            from_c_str(jit_readelf_get_name(self.as_ptr()))
        }
    }
    #[inline]
    pub fn add_to_context(&self, ctx:&Context<'a>) {
        unsafe {
            jit_readelf_add_to_context(self.as_ptr(), ctx.as_ptr())
        }
    }
    #[inline]
    /// Get a symbol in the ELF binary
    pub unsafe fn get_symbol<T, S:ToCStr>(&self, symbol:S) -> *T {
        symbol.with_c_str(|c_symbol|
            jit_readelf_get_symbol(self.as_ptr(), c_symbol) as *T
        )
    }
    #[inline]
    /// Iterate over the needed libraries
    pub fn iter_needed<'a>(&'a self) -> Needed<'a> {
        Needed::new(self)
    }
}
#[unsafe_destructor]
impl<'a> Drop for ReadElf<'a> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            jit_readelf_close(self.as_ptr())
        }
    }
}

/// An ELF binary reader
native_ref!(WriteElf, _writer, jit_writeelf_t, ContravariantLifetime)
impl<'a> WriteElf<'a> {
    #[inline]
    /// Create a new ELF binary reader
    pub fn new<S:ToCStr>(lib_name:S) -> WriteElf<'a> {
        lib_name.with_c_str(|c_lib_name| unsafe {
            NativeRef::from_ptr(jit_writeelf_create(c_lib_name))
        })
    }
    #[inline]
    /// Write to the filename given (not implemented by LibJIT yet)
    pub fn write<S:ToCStr>(&self, filename:S) -> bool {
        filename.with_c_str(|c_filename| unsafe {
            jit_writeelf_write(self.as_ptr(), c_filename) != 0
        })
    }
    #[inline]
    /// Add a function to the ELF
    pub fn add_function<S:ToCStr>(&self, func:&Function<'a>, name:S) -> bool {
        name.with_c_str(|c_name| unsafe {
            jit_writeelf_add_function(self.as_ptr(), func.as_ptr(), c_name) != 0
        })
    }
    #[inline]
    /// Add a dependency to the ELF
    pub fn add_needed<S:ToCStr>(&self, lib_name:S) -> bool {
        lib_name.with_c_str(|c_lib_name| unsafe {
            jit_writeelf_add_needed(self.as_ptr(), c_lib_name) != 0
        })
    }
}
#[unsafe_destructor]
impl<'a> Drop for WriteElf<'a> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            jit_writeelf_destroy(self.as_ptr())
        }
    }
}<commit_msg>Implement some more Iterator methods on dependency iterator<commit_after>use bindings::*;
use context::Context;
use function::Function;
use libc::c_uint;
use util::NativeRef;
use std::fmt::Show;
use std::kinds::marker::ContravariantLifetime;
use std::iter::Iterator;
use std::str::raw::from_c_str;
use std::c_str::ToCStr;
/// An ELF dependency iterator
pub struct Needed<'a> {
    _reader: jit_readelf_t,
    index: c_uint,
    length: c_uint,
    marker: ContravariantLifetime<'a>
}
impl<'a> Needed<'a> {
    #[inline]
    fn new(read:&ReadElf<'a>) -> Needed<'a> {
        unsafe {
            Needed {
                _reader: read.as_ptr(),
                index: 0 as c_uint,
                length: jit_readelf_num_needed(read.as_ptr()),
                marker: ContravariantLifetime::<'a>
            }
        }
    }
}
impl<'a> Iterator<String> for Needed<'a> {
    fn next(&mut self) -> Option<String> {
        let index = self.index;
        self.index += 1;
        unsafe {
            if index < self.length {
                let c_name = jit_readelf_get_needed(self._reader, index);
                let name = from_c_str(c_name);
                Some(name)
            } else {
                None
            }
        }
    }
    #[inline]
    fn size_hint(&self) -> (uint, Option<uint>) {
        ((self.length - self.index) as uint, None)
    }
    #[inline]
    fn count(&mut self) -> uint {
        let count = self.length - self.index;
        self.index = self.length;
        count as uint
    }
    #[inline]
    fn nth(&mut self, n:uint) -> Option<String> {
        self.index += n as u32;
        self.next()
    }
}
/// An ELF binary reader
native_ref!(ReadElf, _reader, jit_readelf_t, ContravariantLifetime)
impl<'a> ReadElf<'a> {
    /// Open a new ELF binary
    pub fn new<S:ToCStr+Show>(filename:S) -> ReadElf<'a> {
        unsafe {
            let mut this = RawPtr::null();
            let code = filename.with_c_str(|c_name|
                jit_readelf_open(&mut this, c_name, 0)
            );
            if this.is_null() {
                fail!("'{}' couldn't be opened due to {}", filename, code);
            } else {
                NativeRef::from_ptr(this)
            }
        }
    }
    #[inline]
    /// Get the name of this ELF binary
    pub fn get_name(&self) -> String {
        unsafe {
            from_c_str(jit_readelf_get_name(self.as_ptr()))
        }
    }
    #[inline]
    pub fn add_to_context(&self, ctx:&Context<'a>) {
        unsafe {
            jit_readelf_add_to_context(self.as_ptr(), ctx.as_ptr())
        }
    }
    #[inline]
    /// Get a symbol in the ELF binary
    pub unsafe fn get_symbol<T, S:ToCStr>(&self, symbol:S) -> *T {
        symbol.with_c_str(|c_symbol|
            jit_readelf_get_symbol(self.as_ptr(), c_symbol) as *T
        )
    }
    #[inline]
    /// Iterate over the needed libraries
    pub fn iter_needed<'a>(&'a self) -> Needed<'a> {
        Needed::new(self)
    }
}
#[unsafe_destructor]
impl<'a> Drop for ReadElf<'a> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            jit_readelf_close(self.as_ptr())
        }
    }
}

/// An ELF binary reader
native_ref!(WriteElf, _writer, jit_writeelf_t, ContravariantLifetime)
impl<'a> WriteElf<'a> {
    #[inline]
    /// Create a new ELF binary reader
    pub fn new<S:ToCStr>(lib_name:S) -> WriteElf<'a> {
        lib_name.with_c_str(|c_lib_name| unsafe {
            NativeRef::from_ptr(jit_writeelf_create(c_lib_name))
        })
    }
    #[inline]
    /// Write to the filename given (not implemented by LibJIT yet)
    pub fn write<S:ToCStr>(&self, filename:S) -> bool {
        filename.with_c_str(|c_filename| unsafe {
            jit_writeelf_write(self.as_ptr(), c_filename) != 0
        })
    }
    #[inline]
    /// Add a function to the ELF
    pub fn add_function<S:ToCStr>(&self, func:&Function<'a>, name:S) -> bool {
        name.with_c_str(|c_name| unsafe {
            jit_writeelf_add_function(self.as_ptr(), func.as_ptr(), c_name) != 0
        })
    }
    #[inline]
    /// Add a dependency to the ELF
    pub fn add_needed<S:ToCStr>(&self, lib_name:S) -> bool {
        lib_name.with_c_str(|c_lib_name| unsafe {
            jit_writeelf_add_needed(self.as_ptr(), c_lib_name) != 0
        })
    }
}
#[unsafe_destructor]
impl<'a> Drop for WriteElf<'a> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            jit_writeelf_destroy(self.as_ptr())
        }
    }
}<|endoftext|>


<commit_before>//! Loaders for osci memory images.
pub mod rawloader;
pub mod hexloader;

use std::{error, fmt, io, num, result};
use std::string::String;

#[derive(Debug)]
/// Error type for all loaders.
///
/// `LoadError` is just a union-type over a couple of built-in errors with the `From` trait implemented for each of them. This makes implementing loaders more convenient due to the `try!` macro and the `?` operator.
pub enum LoadError {
    None,
    IoErr(io::Error),
    ParseIntErr(num::ParseIntError),
    FormatErr(fmt::Error),
    Message(String),
}

// TODO: Remove None?!!

impl LoadError {
    pub fn new() -> LoadError {
        LoadError::None
    }

    pub fn from_message(msg: String) -> LoadError {
        LoadError::Message(msg)
    }
}

impl fmt::Display for LoadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Loading failed")
    }
}

impl error::Error for LoadError {
    fn description(&self) -> &str {
        match self {
            &LoadError::None => &"Loading failed",
            &LoadError::Message(ref str) => str,
            &LoadError::IoErr(ref err) => err.description(),
            &LoadError::ParseIntErr(ref err) => err.description(),
            &LoadError::FormatErr(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self {
            &LoadError::IoErr(ref err) => Some(err),
            &LoadError::ParseIntErr(ref err) => Some(err),
            &LoadError::FormatErr(ref err) => Some(err),
            _ => None,
        }
    }
}

impl From<io::Error> for LoadError {
    fn from(err: io::Error) -> Self {
        LoadError::IoErr(err)
    }
}

impl From<num::ParseIntError> for LoadError {
    fn from(err: num::ParseIntError) -> Self {
        LoadError::ParseIntErr(err)
    }
}

impl From<fmt::Error> for LoadError {
    fn from(err: fmt::Error) -> Self {
        LoadError::FormatErr(err)
    }
}

pub type Result<T> = result::Result<T, LoadError>;
<commit_msg>feat(loader): We actually need None<commit_after>//! Loaders for osci memory images.
pub mod rawloader;
pub mod hexloader;

use std::{error, fmt, io, num, result};
use std::string::String;

#[derive(Debug)]
/// Error type for all loaders.
///
/// `LoadError` is just a union-type over a couple of built-in errors with the `From` trait implemented for each of them. This makes implementing loaders more convenient due to the `try!` macro and the `?` operator.
///
/// The `None` is mostly available to be used with `std::result::Result.ok_or()`.
pub enum LoadError {
    None,
    IoErr(io::Error),
    ParseIntErr(num::ParseIntError),
    FormatErr(fmt::Error),
    Message(String),
}

impl LoadError {
    pub fn new() -> LoadError {
        LoadError::None
    }

    pub fn from_message(msg: String) -> LoadError {
        LoadError::Message(msg)
    }
}

impl fmt::Display for LoadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Loading failed")
    }
}

impl error::Error for LoadError {
    fn description(&self) -> &str {
        match self {
            &LoadError::None => &"Loading failed",
            &LoadError::Message(ref str) => str,
            &LoadError::IoErr(ref err) => err.description(),
            &LoadError::ParseIntErr(ref err) => err.description(),
            &LoadError::FormatErr(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self {
            &LoadError::IoErr(ref err) => Some(err),
            &LoadError::ParseIntErr(ref err) => Some(err),
            &LoadError::FormatErr(ref err) => Some(err),
            _ => None,
        }
    }
}

impl From<io::Error> for LoadError {
    fn from(err: io::Error) -> Self {
        LoadError::IoErr(err)
    }
}

impl From<num::ParseIntError> for LoadError {
    fn from(err: num::ParseIntError) -> Self {
        LoadError::ParseIntErr(err)
    }
}

impl From<fmt::Error> for LoadError {
    fn from(err: fmt::Error) -> Self {
        LoadError::FormatErr(err)
    }
}

pub type Result<T> = result::Result<T, LoadError>;
<|endoftext|>


<commit_before>use core::marker::PhantomData;
use core::pin::Pin;
use futures::executor::block_on_stream;
use futures::future::{ok, err, TryFutureExt};
use futures::sink::Sink;
use futures::stream::{self, Stream, StreamExt};
use futures::task::{Context, Poll};

#[test]
fn successful_future() {
    let stream_items = vec![17, 19];
    let future_of_a_stream = ok::<_, bool>(stream::iter(stream_items).map(Ok));

    let stream = future_of_a_stream.try_flatten_stream();

    let mut iter = block_on_stream(stream);
    assert_eq!(Ok(17), iter.next().unwrap());
    assert_eq!(Ok(19), iter.next().unwrap());
    assert_eq!(None, iter.next());
}

struct PanickingStream<T, E> {
    _marker: PhantomData<(T, E)>
}

impl<T, E> Stream for PanickingStream<T, E> {
    type Item = Result<T, E>;

    fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        panic!()
    }
}

#[test]
fn failed_future() {
    let future_of_a_stream = err::<PanickingStream<bool, u32>, _>(10);
    let stream = future_of_a_stream.try_flatten_stream();
    let mut iter = block_on_stream(stream);
    assert_eq!(Err(10), iter.next().unwrap());
    assert_eq!(None, iter.next());
}

struct StreamSink<T, E, Item>(PhantomData<(T, E, Item)>);

impl<T, E, Item> Stream for StreamSink<T, E, Item> {
    type Item = Result<T, E>;
    fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        panic!()
    }
}

impl<T, E, Item> Sink<Item> for StreamSink<T, E, Item> {
    type Error = E;
    fn poll_ready(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        panic!()
    }
    fn start_send(self: Pin<&mut Self>, _: Item) -> Result<(), Self::Error> {
        panic!()
    }
    fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        panic!()
    }
    fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        panic!()
    }
}

fn assert_stream<S: Stream>(_: &S) {}
fn assert_sink<S: Sink<Item>, Item>(_: &S) {}
fn assert_stream_sink<S: Stream + Sink<Item>, Item>(_: &S) {}

#[test]
fn assert_impls() {
    let s = ok(StreamSink::<(), (), ()>(PhantomData)).try_flatten_stream();
    assert_stream(&s);
    assert_sink(&s);
    assert_stream_sink(&s);
    let s = ok(StreamSink::<(), (), ()>(PhantomData)).flatten_sink();
    assert_stream(&s);
    assert_sink(&s);
    assert_stream_sink(&s);
}
<commit_msg>futures: tests/future_try_flatten_stream.rs: Avoid compile failures<commit_after>#[cfg(feature = "executor")]
#[test]
fn successful_future() {
    use futures::executor::block_on_stream;
    use futures::future::{ok, TryFutureExt};
    use futures::stream::{self, StreamExt};

    let stream_items = vec![17, 19];
    let future_of_a_stream = ok::<_, bool>(stream::iter(stream_items).map(Ok));

    let stream = future_of_a_stream.try_flatten_stream();

    let mut iter = block_on_stream(stream);
    assert_eq!(Ok(17), iter.next().unwrap());
    assert_eq!(Ok(19), iter.next().unwrap());
    assert_eq!(None, iter.next());
}

#[cfg(feature = "executor")]
#[test]
fn failed_future() {
    use core::marker::PhantomData;
    use core::pin::Pin;
    use futures::executor::block_on_stream;
    use futures::future::{err, TryFutureExt};
    use futures::stream::Stream;
    use futures::task::{Context, Poll};

    struct PanickingStream<T, E> {
        _marker: PhantomData<(T, E)>
    }

    impl<T, E> Stream for PanickingStream<T, E> {
        type Item = Result<T, E>;

        fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<Self::Item>> {
            panic!()
        }
    }

    let future_of_a_stream = err::<PanickingStream<bool, u32>, _>(10);
    let stream = future_of_a_stream.try_flatten_stream();
    let mut iter = block_on_stream(stream);
    assert_eq!(Err(10), iter.next().unwrap());
    assert_eq!(None, iter.next());
}

#[test]
fn assert_impls() {
    use core::marker::PhantomData;
    use core::pin::Pin;
    use futures::sink::Sink;
    use futures::stream::Stream;
    use futures::task::{Context, Poll};
    use futures::future::{ok, TryFutureExt};

    struct StreamSink<T, E, Item>(PhantomData<(T, E, Item)>);

    impl<T, E, Item> Stream for StreamSink<T, E, Item> {
        type Item = Result<T, E>;
        fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<Self::Item>> {
            panic!()
        }
    }

    impl<T, E, Item> Sink<Item> for StreamSink<T, E, Item> {
        type Error = E;
        fn poll_ready(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
            panic!()
        }
        fn start_send(self: Pin<&mut Self>, _: Item) -> Result<(), Self::Error> {
            panic!()
        }
        fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
            panic!()
        }
        fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
            panic!()
        }
    }

    fn assert_stream<S: Stream>(_: &S) {}
    fn assert_sink<S: Sink<Item>, Item>(_: &S) {}
    fn assert_stream_sink<S: Stream + Sink<Item>, Item>(_: &S) {}

    let s = ok(StreamSink::<(), (), ()>(PhantomData)).try_flatten_stream();
    assert_stream(&s);
    assert_sink(&s);
    assert_stream_sink(&s);
    let s = ok(StreamSink::<(), (), ()>(PhantomData)).flatten_sink();
    assert_stream(&s);
    assert_sink(&s);
    assert_stream_sink(&s);
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use uuid::Uuid;

use js_types::js_type::JsPtrEnum;

pub mod scope;

pub type Alloc<T> = Rc<RefCell<T>>;

pub struct AllocBox {
    black_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
    grey_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
    white_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
}

impl AllocBox {
    pub fn new() -> AllocBox {
        AllocBox {
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.black_set.len() + self.grey_set.len() + self.white_set.len()
    }

    pub fn alloc(&mut self, uuid: Uuid, ptr: JsPtrEnum) -> Uuid {
        // TODO validate that `uuid` isn't already in the map
        self.white_set.insert(uuid, Rc::new(RefCell::new(ptr)));
        uuid
    }

    pub fn mark_roots(&mut self, marks: HashSet<Uuid>) {
        for mark in marks {
            if let Some(ptr) = self.white_set.remove(&mark) {
                // Get all child references
                let child_ids = AllocBox::get_ptr_children(&ptr);
                // Mark current ref as black
                self.black_set.insert(mark, ptr);
                // Mark child references as grey
                self.grey_children(child_ids);
            } else if let Some(ptr) = self.grey_set.remove(&mark) {
                // Get all child references
                let child_ids = AllocBox::get_ptr_children(&ptr);
                // Mark current ref as black
                self.black_set.insert(mark, ptr);
                // Mark child references as grey
                self.grey_children(child_ids);
            }
        }
    }

    pub fn mark_ptrs(&mut self) {
        // Mark any grey object as black, and mark all white objs it refs as grey
        let mut new_grey_set = HashMap::new();
        for (uuid, var) in self.grey_set.drain() {
            let child_ids = AllocBox::get_ptr_children(&var);
            self.black_set.insert(uuid, var);
            for child_id in child_ids {
                if let Some(var) = self.white_set.remove(&child_id) {
                    new_grey_set.insert(child_id, var);
                }
            }
        }
        self.grey_set = new_grey_set;
    }

    pub fn sweep_ptrs(&mut self) {
        // Delete all white pointers and reset the GC state.
        self.white_set = self.black_set.clone();
        self.grey_set = HashMap::new();
        self.black_set = HashMap::new();
    }

    pub fn find_id(&self, uuid: &Uuid) -> Option<&Alloc<JsPtrEnum>> {
        self.white_set.get(uuid).or(
            self.grey_set.get(uuid).or(
                self.black_set.get(uuid)))
    }

    pub fn update_ptr(&mut self, uuid: &Uuid, ptr: JsPtrEnum) -> bool {
        if let Entry::Occupied(mut view) = self.find_id_mut(&uuid) {
            let inner = view.get_mut();
            *inner.borrow_mut() = ptr;
            true
        } else { false }
    }

    fn grey_children(&mut self, child_ids: HashSet<Uuid>) {
        for child_id in child_ids.iter() {
            if let Some(var) = self.white_set.remove(child_id) {
                self.grey_set.insert(*child_id, var);
            }
        }
    }

    fn get_ptr_children(ptr: &Alloc<JsPtrEnum>) -> HashSet<Uuid> {
        if let JsPtrEnum::JsObj(ref obj) = *ptr.borrow() {
            obj.get_children()
        } else { HashSet::new() }
    }

    fn find_id_mut(&mut self, uuid: &Uuid) -> Entry<Uuid, Alloc<JsPtrEnum>> {
        if let e @ Entry::Occupied(_) = self.white_set.entry(*uuid) {
            e
        } else if let e @ Entry::Occupied(_) = self.grey_set.entry(*uuid) {
            e
        } else { self.black_set.entry(*uuid) }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::hash_set::HashSet;
    use uuid::Uuid;
    use js_types::js_type::JsPtrEnum;
    use js_types::js_str::JsStrStruct;

    fn make_str(s: &str) -> JsPtrEnum {
        JsPtrEnum::JsStr(JsStrStruct::new(s))
    }

    #[test]
    fn test_len() {
        let mut ab = AllocBox::new();
        assert_eq!(ab.len(), 0);
        ab.alloc(Uuid::new_v4(), make_str(""));
        assert_eq!(ab.len(), 1);
    }

    fn test_alloc() {
        let mut ab = AllocBox::new();
        let id1 = Uuid::new_v4();
        let id2 = Uuid::new_v4();
        let id3 = Uuid::new_v4();
        let _id1 = ab.alloc(id1.clone(), make_str(""));
        let _id2 = ab.alloc(id2.clone(), make_str(""));
        let _id3 = ab.alloc(id3.clone(), make_str(""));

        assert_eq!(id1, _id1);
        assert_eq!(id2, _id2);
        assert_eq!(id3, _id3);
    }

    fn test_mark_roots() {
        let mut ab = AllocBox::new();
        let id1 = Uuid::new_v4();
        let id2 = Uuid::new_v4();
        let id3 = Uuid::new_v4();
        let id1 = ab.alloc(id1, make_str(""));
        let id2 = ab.alloc(id2, make_str(""));
        let id3 = ab.alloc(id3, make_str(""));

        let mut marks = HashSet::new();
        marks.insert(id1); marks.insert(id2);
        ab.mark_roots(marks);

    }
}
<commit_msg>Allocation now panics if the UUID allocated already existed<commit_after>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use uuid::Uuid;

use js_types::js_type::JsPtrEnum;

pub mod scope;

pub type Alloc<T> = Rc<RefCell<T>>;

pub struct AllocBox {
    black_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
    grey_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
    white_set: HashMap<Uuid, Alloc<JsPtrEnum>>,
}

impl AllocBox {
    pub fn new() -> AllocBox {
        AllocBox {
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
        }
    }

    pub fn len(&self) -> usize {
        self.black_set.len() + self.grey_set.len() + self.white_set.len()
    }

    pub fn alloc(&mut self, uuid: Uuid, ptr: JsPtrEnum) -> Uuid {
        // TODO validate that `uuid` isn't already in the map
        if let None = self.white_set.insert(uuid, Rc::new(RefCell::new(ptr))) {
            uuid
        } else {
            // If a UUID already exists and we try to allocate it, this should
            // be an unrecoverable error. In practice, this shouldn't happen
            // unless the UUID generator creates a collision.
            panic!("Allocation of UUID {} failed! UUID was already present in map!", uuid);
        }
    }

    pub fn mark_roots(&mut self, marks: HashSet<Uuid>) {
        for mark in marks {
            if let Some(ptr) = self.white_set.remove(&mark) {
                // Get all child references
                let child_ids = AllocBox::get_ptr_children(&ptr);
                // Mark current ref as black
                self.black_set.insert(mark, ptr);
                // Mark child references as grey
                self.grey_children(child_ids);
            } else if let Some(ptr) = self.grey_set.remove(&mark) {
                // Get all child references
                let child_ids = AllocBox::get_ptr_children(&ptr);
                // Mark current ref as black
                self.black_set.insert(mark, ptr);
                // Mark child references as grey
                self.grey_children(child_ids);
            }
        }
    }

    pub fn mark_ptrs(&mut self) {
        // Mark any grey object as black, and mark all white objs it refs as grey
        let mut new_grey_set = HashMap::new();
        for (uuid, var) in self.grey_set.drain() {
            let child_ids = AllocBox::get_ptr_children(&var);
            self.black_set.insert(uuid, var);
            for child_id in child_ids {
                if let Some(var) = self.white_set.remove(&child_id) {
                    new_grey_set.insert(child_id, var);
                }
            }
        }
        self.grey_set = new_grey_set;
    }

    pub fn sweep_ptrs(&mut self) {
        // Delete all white pointers and reset the GC state.
        self.white_set = self.black_set.clone();
        self.grey_set = HashMap::new();
        self.black_set = HashMap::new();
    }

    pub fn find_id(&self, uuid: &Uuid) -> Option<&Alloc<JsPtrEnum>> {
        self.white_set.get(uuid).or(
            self.grey_set.get(uuid).or(
                self.black_set.get(uuid)))
    }

    pub fn update_ptr(&mut self, uuid: &Uuid, ptr: JsPtrEnum) -> bool {
        if let Entry::Occupied(mut view) = self.find_id_mut(&uuid) {
            let inner = view.get_mut();
            *inner.borrow_mut() = ptr;
            true
        } else { false }
    }

    fn grey_children(&mut self, child_ids: HashSet<Uuid>) {
        for child_id in child_ids.iter() {
            if let Some(var) = self.white_set.remove(child_id) {
                self.grey_set.insert(*child_id, var);
            }
        }
    }

    fn get_ptr_children(ptr: &Alloc<JsPtrEnum>) -> HashSet<Uuid> {
        if let JsPtrEnum::JsObj(ref obj) = *ptr.borrow() {
            obj.get_children()
        } else { HashSet::new() }
    }

    fn find_id_mut(&mut self, uuid: &Uuid) -> Entry<Uuid, Alloc<JsPtrEnum>> {
        if let e @ Entry::Occupied(_) = self.white_set.entry(*uuid) {
            e
        } else if let e @ Entry::Occupied(_) = self.grey_set.entry(*uuid) {
            e
        } else { self.black_set.entry(*uuid) }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::hash_set::HashSet;
    use uuid::Uuid;
    use js_types::js_type::JsPtrEnum;
    use js_types::js_str::JsStrStruct;

    fn make_str(s: &str) -> JsPtrEnum {
        JsPtrEnum::JsStr(JsStrStruct::new(s))
    }

    #[test]
    fn test_len() {
        let mut ab = AllocBox::new();
        assert_eq!(ab.len(), 0);
        ab.alloc(Uuid::new_v4(), make_str(""));
        assert_eq!(ab.len(), 1);
    }

    fn test_alloc() {
        let mut ab = AllocBox::new();
        let id1 = Uuid::new_v4();
        let id2 = Uuid::new_v4();
        let id3 = Uuid::new_v4();
        let _id1 = ab.alloc(id1.clone(), make_str(""));
        let _id2 = ab.alloc(id2.clone(), make_str(""));
        let _id3 = ab.alloc(id3.clone(), make_str(""));

        assert_eq!(id1, _id1);
        assert_eq!(id2, _id2);
        assert_eq!(id3, _id3);
    }

    fn test_mark_roots() {
        let mut ab = AllocBox::new();
        let id1 = Uuid::new_v4();
        let id2 = Uuid::new_v4();
        let id3 = Uuid::new_v4();
        let id1 = ab.alloc(id1, make_str(""));
        let id2 = ab.alloc(id2, make_str(""));
        let id3 = ab.alloc(id3, make_str(""));

        let mut marks = HashSet::new();
        marks.insert(id1); marks.insert(id2);
        ab.mark_roots(marks);

    }
}
<|endoftext|>


<commit_before>#[macro_use]
mod macros;

use std::str::FromStr;

use proc_macro2::{Delimiter, Group, Punct, Spacing, TokenStream, TokenTree};
use quote::quote;
use std::iter::FromIterator;
use syn::{Expr, ExprRange};

#[test]
fn test_expr_parse() {
    let code = "..100u32";
    let tt = TokenStream::from_str(code).unwrap();
    let expr: Expr = syn::parse2(tt.clone()).unwrap();
    let expr_range: ExprRange = syn::parse2(tt).unwrap();
    assert_eq!(expr, Expr::Range(expr_range));
}

#[test]
fn test_await() {
    // Must not parse as Expr::Field.
    let expr = syn::parse_str::<Expr>("fut.await").unwrap();

    snapshot!(expr, @r###"
    Expr::Await {
        base: Expr::Path {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "fut",
                        arguments: None,
                    },
                ],
            },
        },
    }
    "###);
}

#[test]
fn test_macro_variable_func() {
    // mimics the token stream corresponding to `$fn()`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        func: Expr::Group {
            expr: Expr::Path {
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "f",
                            arguments: None,
                        },
                    ],
                },
            },
        },
    }
    "###);

    let tokens = TokenStream::from_iter(vec![
        TokenTree::Punct(Punct::new('#', Spacing::Alone)),
        TokenTree::Group(Group::new(Delimiter::Bracket, quote! { outside })),
        TokenTree::Group(Group::new(Delimiter::None, quote! { #[inside] f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        attrs: [
            Attribute {
                style: Outer,
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "outside",
                            arguments: None,
                        },
                    ],
                },
                tokens: TokenStream(``),
            },
        ],
        func: Expr::Group {
            expr: Expr::Path {
                attrs: [
                    Attribute {
                        style: Outer,
                        path: Path {
                            segments: [
                                PathSegment {
                                    ident: "inside",
                                    arguments: None,
                                },
                            ],
                        },
                        tokens: TokenStream(``),
                    },
                ],
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "f",
                            arguments: None,
                        },
                    ],
                },
            },
        },
    }
    "###);
}
<commit_msg>Add test for macro call expr with macro metavariable<commit_after>#[macro_use]
mod macros;

use std::str::FromStr;

use proc_macro2::{Delimiter, Group, Punct, Spacing, TokenStream, TokenTree};
use quote::quote;
use std::iter::FromIterator;
use syn::{Expr, ExprRange};

#[test]
fn test_expr_parse() {
    let code = "..100u32";
    let tt = TokenStream::from_str(code).unwrap();
    let expr: Expr = syn::parse2(tt.clone()).unwrap();
    let expr_range: ExprRange = syn::parse2(tt).unwrap();
    assert_eq!(expr, Expr::Range(expr_range));
}

#[test]
fn test_await() {
    // Must not parse as Expr::Field.
    let expr = syn::parse_str::<Expr>("fut.await").unwrap();

    snapshot!(expr, @r###"
    Expr::Await {
        base: Expr::Path {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "fut",
                        arguments: None,
                    },
                ],
            },
        },
    }
    "###);
}

#[test]
fn test_macro_variable_func() {
    // mimics the token stream corresponding to `$fn()`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        func: Expr::Group {
            expr: Expr::Path {
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "f",
                            arguments: None,
                        },
                    ],
                },
            },
        },
    }
    "###);

    let tokens = TokenStream::from_iter(vec![
        TokenTree::Punct(Punct::new('#', Spacing::Alone)),
        TokenTree::Group(Group::new(Delimiter::Bracket, quote! { outside })),
        TokenTree::Group(Group::new(Delimiter::None, quote! { #[inside] f })),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Call {
        attrs: [
            Attribute {
                style: Outer,
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "outside",
                            arguments: None,
                        },
                    ],
                },
                tokens: TokenStream(``),
            },
        ],
        func: Expr::Group {
            expr: Expr::Path {
                attrs: [
                    Attribute {
                        style: Outer,
                        path: Path {
                            segments: [
                                PathSegment {
                                    ident: "inside",
                                    arguments: None,
                                },
                            ],
                        },
                        tokens: TokenStream(``),
                    },
                ],
                path: Path {
                    segments: [
                        PathSegment {
                            ident: "f",
                            arguments: None,
                        },
                    ],
                },
            },
        },
    }
    "###);
}

#[test]
fn test_macro_variable_macro() {
    // mimics the token stream corresponding to `$macro!()`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { m })),
        TokenTree::Punct(Punct::new('!', Spacing::Alone)),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
    ]);

    snapshot!(tokens as Expr, @r###"
    Expr::Macro {
        mac: Macro {
            path: Path {
                segments: [
                    PathSegment {
                        ident: "m",
                        arguments: None,
                    },
                ],
            },
            delimiter: Paren,
            tokens: TokenStream(``),
        },
    }
    "###);
}
<|endoftext|>