<commit_before>//! Support for sending and receiving data link layer packets using libpcap.
//! Also has support for reading pcap files.

extern crate pcap;

use std::marker::{Send, Sync};
use std::io;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::path::Path;

use self::pcap::{Active, Activated};

use {DataLinkReceiver, DataLinkSender, NetworkInterface};
use Channel::Ethernet;

/// Configuration for the pcap datalink backend.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Config {
    /// The size of buffer to use when reading packets. Must be at least
    /// 65516 with pcap.
    pub read_buffer_size: usize,

    /// The read timeout. Defaults to None.
    pub read_timeout: Option<Duration>,
}

impl<'a> From<&'a super::Config> for Config {
    fn from(config: &super::Config) -> Config {
        let mut c = Config{
            read_buffer_size: config.read_buffer_size,
            read_timeout: config.read_timeout,
        };
        // pcap is unique in that the buffer size must be greater or equal to
        // MAXIMUM_SNAPLEN, which is currently hard-coded to 65536
        // So, just reset it to the default.
        if c.read_buffer_size < 65536 {
            c.read_buffer_size = Config::default().read_buffer_size;
        }
        c
    }
}

impl Default for Config {
    fn default() -> Config {
        Config{
            // Just let pcap pick the default size
            read_buffer_size: 0,
            read_timeout: None,
        }
    }
}

/// Create a datalink channel from the provided pcap device.
#[inline]
pub fn channel(network_interface: &NetworkInterface,
               config: Config) -> io::Result<super::Channel> {
    let cap = match pcap::Capture::from_device(&*network_interface.name) {
        Ok(cap) => cap,
        Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
    }.buffer_size(config.read_buffer_size as i32);
    let cap = match config.read_timeout {
        Some(to) => cap.timeout(
            (to.as_secs() * 1000 + (to.subsec_nanos() / 1000) as u64) as i32
        ),
        None => cap
    };
    let cap = match cap.open() {
        Ok(cap) => cap,
        Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
    };
    let cap = Arc::new(Mutex::new(cap));
    Ok(Ethernet(
        Box::new(DataLinkSenderImpl {
            capture: cap.clone(),
        }),
        Box::new(DataLinkReceiverImpl {
            capture: cap.clone(),
            read_buffer: vec![0; config.read_buffer_size],
        })
    ))
}

/// Create a datalink channel from a pcap file.
#[inline]
pub fn from_file<P: AsRef<Path>>(path: P, config: Config) -> io::Result<super::Channel> {
    let cap = match pcap::Capture::from_file(path) {
        Ok(cap) => cap,
        Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
    };
    let cap = Arc::new(Mutex::new(cap));
    Ok(Ethernet(
        Box::new(InvalidDataLinkSenderImpl {}),
        Box::new(DataLinkReceiverImpl {
            capture: cap.clone(),
            read_buffer: vec![0; config.read_buffer_size],
        })
    ))
}

struct DataLinkSenderImpl {
    capture: Arc<Mutex<pcap::Capture<Active>>>,
}

impl DataLinkSender for DataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut FnMut(&mut [u8]))
                      -> Option<io::Result<()>> {
        for _ in 0..num_packets {
            let mut data = vec![0; packet_size];
            func(&mut data);
            let mut cap = self.capture.lock().unwrap();
            if let Err(e) = cap.sendpacket(data) {
                return Some(Err(io::Error::new(io::ErrorKind::Other, e)))
            }
        }
        Some(Ok(()))
    }

    #[inline]
    fn send_to(&mut self,
               packet: &[u8],
               _dst: Option<NetworkInterface>) -> Option<io::Result<()>> {
        let mut cap = self.capture.lock().unwrap();
        Some(match cap.sendpacket(packet) {
            Ok(()) => Ok(()),
            Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)),
        })
    }
}

struct InvalidDataLinkSenderImpl {}

impl DataLinkSender for InvalidDataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      _num_packets: usize,
                      _packet_size: usize,
                      _func: &mut FnMut(&mut [u8]))
                      -> Option<io::Result<()>> {
        None
    }

    #[inline]
    fn send_to(&mut self,
               _packet: &[u8],
               _dst: Option<NetworkInterface>) -> Option<io::Result<()>> {
        None
    }
}

struct DataLinkReceiverImpl<T: Activated + Send + Sync> {
    capture: Arc<Mutex<pcap::Capture<T>>>,
    read_buffer: Vec<u8>,
}

impl <T: Activated + Send + Sync> DataLinkReceiver for DataLinkReceiverImpl<T> {
    fn next(&mut self) -> io::Result<&[u8]> {
        let mut cap = self.capture.lock().unwrap();
        match cap.next() {
            Ok(pkt) => {
                self.read_buffer.truncate(0);
                self.read_buffer.extend(pkt.data);
            },
            Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
        };
        Ok(&self.read_buffer)
    }
}

/// Get a list of available network interfaces for the current machine.
pub fn interfaces() -> Vec<NetworkInterface> {
    if let Ok(devices) = pcap::Device::list() {
        devices.iter().enumerate().map(|(i, dev)| {
            NetworkInterface {
                name: dev.name.clone(),
                index: i as u32,
                mac: None,
                ips: Vec::new(),
                flags: 0,
            }
        }).collect()
    } else {
        vec![]
    }
}
<commit_msg>two more instances of dyn FnMut<commit_after>//! Support for sending and receiving data link layer packets using libpcap.
//! Also has support for reading pcap files.

extern crate pcap;

use std::marker::{Send, Sync};
use std::io;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::path::Path;

use self::pcap::{Active, Activated};

use {DataLinkReceiver, DataLinkSender, NetworkInterface};
use Channel::Ethernet;

/// Configuration for the pcap datalink backend.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Config {
    /// The size of buffer to use when reading packets. Must be at least
    /// 65516 with pcap.
    pub read_buffer_size: usize,

    /// The read timeout. Defaults to None.
    pub read_timeout: Option<Duration>,
}

impl<'a> From<&'a super::Config> for Config {
    fn from(config: &super::Config) -> Config {
        let mut c = Config{
            read_buffer_size: config.read_buffer_size,
            read_timeout: config.read_timeout,
        };
        // pcap is unique in that the buffer size must be greater or equal to
        // MAXIMUM_SNAPLEN, which is currently hard-coded to 65536
        // So, just reset it to the default.
        if c.read_buffer_size < 65536 {
            c.read_buffer_size = Config::default().read_buffer_size;
        }
        c
    }
}

impl Default for Config {
    fn default() -> Config {
        Config{
            // Just let pcap pick the default size
            read_buffer_size: 0,
            read_timeout: None,
        }
    }
}

/// Create a datalink channel from the provided pcap device.
#[inline]
pub fn channel(network_interface: &NetworkInterface,
               config: Config) -> io::Result<super::Channel> {
    let cap = match pcap::Capture::from_device(&*network_interface.name) {
        Ok(cap) => cap,
        Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
    }.buffer_size(config.read_buffer_size as i32);
    let cap = match config.read_timeout {
        Some(to) => cap.timeout(
            (to.as_secs() * 1000 + (to.subsec_nanos() / 1000) as u64) as i32
        ),
        None => cap
    };
    let cap = match cap.open() {
        Ok(cap) => cap,
        Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
    };
    let cap = Arc::new(Mutex::new(cap));
    Ok(Ethernet(
        Box::new(DataLinkSenderImpl {
            capture: cap.clone(),
        }),
        Box::new(DataLinkReceiverImpl {
            capture: cap.clone(),
            read_buffer: vec![0; config.read_buffer_size],
        })
    ))
}

/// Create a datalink channel from a pcap file.
#[inline]
pub fn from_file<P: AsRef<Path>>(path: P, config: Config) -> io::Result<super::Channel> {
    let cap = match pcap::Capture::from_file(path) {
        Ok(cap) => cap,
        Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
    };
    let cap = Arc::new(Mutex::new(cap));
    Ok(Ethernet(
        Box::new(InvalidDataLinkSenderImpl {}),
        Box::new(DataLinkReceiverImpl {
            capture: cap.clone(),
            read_buffer: vec![0; config.read_buffer_size],
        })
    ))
}

struct DataLinkSenderImpl {
    capture: Arc<Mutex<pcap::Capture<Active>>>,
}

impl DataLinkSender for DataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      num_packets: usize,
                      packet_size: usize,
                      func: &mut dyn FnMut(&mut [u8]))
                      -> Option<io::Result<()>> {
        for _ in 0..num_packets {
            let mut data = vec![0; packet_size];
            func(&mut data);
            let mut cap = self.capture.lock().unwrap();
            if let Err(e) = cap.sendpacket(data) {
                return Some(Err(io::Error::new(io::ErrorKind::Other, e)))
            }
        }
        Some(Ok(()))
    }

    #[inline]
    fn send_to(&mut self,
               packet: &[u8],
               _dst: Option<NetworkInterface>) -> Option<io::Result<()>> {
        let mut cap = self.capture.lock().unwrap();
        Some(match cap.sendpacket(packet) {
            Ok(()) => Ok(()),
            Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)),
        })
    }
}

struct InvalidDataLinkSenderImpl {}

impl DataLinkSender for InvalidDataLinkSenderImpl {
    #[inline]
    fn build_and_send(&mut self,
                      _num_packets: usize,
                      _packet_size: usize,
                      _func: &mut dyn FnMut(&mut [u8]))
                      -> Option<io::Result<()>> {
        None
    }

    #[inline]
    fn send_to(&mut self,
               _packet: &[u8],
               _dst: Option<NetworkInterface>) -> Option<io::Result<()>> {
        None
    }
}

struct DataLinkReceiverImpl<T: Activated + Send + Sync> {
    capture: Arc<Mutex<pcap::Capture<T>>>,
    read_buffer: Vec<u8>,
}

impl <T: Activated + Send + Sync> DataLinkReceiver for DataLinkReceiverImpl<T> {
    fn next(&mut self) -> io::Result<&[u8]> {
        let mut cap = self.capture.lock().unwrap();
        match cap.next() {
            Ok(pkt) => {
                self.read_buffer.truncate(0);
                self.read_buffer.extend(pkt.data);
            },
            Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
        };
        Ok(&self.read_buffer)
    }
}

/// Get a list of available network interfaces for the current machine.
pub fn interfaces() -> Vec<NetworkInterface> {
    if let Ok(devices) = pcap::Device::list() {
        devices.iter().enumerate().map(|(i, dev)| {
            NetworkInterface {
                name: dev.name.clone(),
                index: i as u32,
                mac: None,
                ips: Vec::new(),
                flags: 0,
            }
        }).collect()
    } else {
        vec![]
    }
}
<|endoftext|>


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

use std::ops::{Add, Div, Mul, Sub};
use util::CastF32;
use vec3f::Vec3f;

/// Vector with two f32 components
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Vec2f {
    pub x: f32,
    pub y: f32
}

impl Vec2f {
    /// Create a Vec2f from two components
    pub fn new(x: f32, y: f32) -> Vec2f {
        Vec2f { x: x,
                y: y }
    }

    pub fn cross(self, other: Vec2f) -> f32 {
        self.x * other.y - self.y * other.x
    }

    pub fn lerp(self, other: Vec2f, t: f32) -> Vec2f {
        self * (1.0 - t) + other * t
    }

    pub fn dot(self, other: Vec2f) -> f32 {
        self.x * other.x + self.y * other.y
    }

    pub fn vec3f(self) -> Vec3f {
        Vec3f::new(self.x, self.y, 0.0)
    }

    pub fn magnitude_squared(self) -> f32 {
        self.dot(self)
    }

    pub fn magnitude(self) -> f32 {
        self.magnitude_squared().sqrt()
    }

    pub fn normalized(self) -> Option<Vec2f> {
        let m = self.magnitude();
        if m == 0.0 {
            None
        }
        else {
            Some(Vec2f::new(self.x / m, self.y / m))
        }
    }
}

impl Add for Vec2f {
    type Output = Vec2f;
    fn add(self, v: Vec2f) -> Vec2f {
        Vec2f::new(self.x + v.x, self.y + v.y)
    }
}

impl Sub for Vec2f {
    type Output = Vec2f;
    fn sub(self, v: Vec2f) -> Vec2f {
        Vec2f::new(self.x - v.x, self.y - v.y)
    }
}

impl Mul<f32> for Vec2f {
    type Output = Vec2f;
    fn mul(self, s: f32) -> Vec2f {
        Vec2f::new(self.x * s, self.y * s)
    }
}

impl Div<f32> for Vec2f {
    type Output = Vec2f;
    fn div(self, s: f32) -> Vec2f {
        Vec2f::new(self.x / s, self.y / s)
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Line2f {
    pub points: (Vec2f, Vec2f)
}

impl Line2f {
    pub fn new(a: Vec2f, b: Vec2f) -> Line2f {
        Line2f { points: (a, b) }
    }

    pub fn closest_parametric_point(self, point: Vec2f) -> f32 {
        let p0p = point - self.points.0;
        let p0p1 = self.points.1 - self.points.0;

        p0p.dot(p0p1) / p0p1.dot(p0p1)
    }

    pub fn cart_from_para(self, t: f32) -> Vec2f {
        self.points.0.lerp(self.points.1, t)
    }
}

/// Create a Vec2f from x and y inputs
///
/// This is a convenience function that provides a little more
/// flexibility than Vec2f::new in that it will happily take numbers
/// that aren't f32 (including a mix of different types for each
/// component). Vec2f is such a common type that it seems reasonable
/// to provide a little extra ease of use.
pub fn vec2f<X: CastF32, Y: CastF32>(x: X, y: Y) -> Vec2f {
    Vec2f { x: x.as_f32(), y: y.as_f32() }
}
<commit_msg>Add vec2f distance methods<commit_after>// Copyright 2015 Nicholas Bishop
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::ops::{Add, Div, Mul, Sub};
use util::CastF32;
use vec3f::Vec3f;

/// Vector with two f32 components
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Vec2f {
    pub x: f32,
    pub y: f32
}

impl Vec2f {
    /// Create a Vec2f from two components
    pub fn new(x: f32, y: f32) -> Vec2f {
        Vec2f { x: x,
                y: y }
    }

    pub fn cross(self, other: Vec2f) -> f32 {
        self.x * other.y - self.y * other.x
    }

    pub fn lerp(self, other: Vec2f, t: f32) -> Vec2f {
        self * (1.0 - t) + other * t
    }

    pub fn dot(self, other: Vec2f) -> f32 {
        self.x * other.x + self.y * other.y
    }

    pub fn vec3f(self) -> Vec3f {
        Vec3f::new(self.x, self.y, 0.0)
    }

    pub fn distance_squared(self, other: Vec2f) -> f32 {
        (self - other).magnitude_squared()
    }

    pub fn distance(self, other: Vec2f) -> f32 {
        self.distance_squared(other).sqrt()
    }

    pub fn magnitude_squared(self) -> f32 {
        self.dot(self)
    }

    pub fn magnitude(self) -> f32 {
        self.magnitude_squared().sqrt()
    }

    pub fn normalized(self) -> Option<Vec2f> {
        let m = self.magnitude();
        if m == 0.0 {
            None
        }
        else {
            Some(Vec2f::new(self.x / m, self.y / m))
        }
    }
}

impl Add for Vec2f {
    type Output = Vec2f;
    fn add(self, v: Vec2f) -> Vec2f {
        Vec2f::new(self.x + v.x, self.y + v.y)
    }
}

impl Sub for Vec2f {
    type Output = Vec2f;
    fn sub(self, v: Vec2f) -> Vec2f {
        Vec2f::new(self.x - v.x, self.y - v.y)
    }
}

impl Mul<f32> for Vec2f {
    type Output = Vec2f;
    fn mul(self, s: f32) -> Vec2f {
        Vec2f::new(self.x * s, self.y * s)
    }
}

impl Div<f32> for Vec2f {
    type Output = Vec2f;
    fn div(self, s: f32) -> Vec2f {
        Vec2f::new(self.x / s, self.y / s)
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Line2f {
    pub points: (Vec2f, Vec2f)
}

impl Line2f {
    pub fn new(a: Vec2f, b: Vec2f) -> Line2f {
        Line2f { points: (a, b) }
    }

    pub fn closest_parametric_point(self, point: Vec2f) -> f32 {
        let p0p = point - self.points.0;
        let p0p1 = self.points.1 - self.points.0;

        p0p.dot(p0p1) / p0p1.dot(p0p1)
    }

    pub fn cart_from_para(self, t: f32) -> Vec2f {
        self.points.0.lerp(self.points.1, t)
    }
}

/// Create a Vec2f from x and y inputs
///
/// This is a convenience function that provides a little more
/// flexibility than Vec2f::new in that it will happily take numbers
/// that aren't f32 (including a mix of different types for each
/// component). Vec2f is such a common type that it seems reasonable
/// to provide a little extra ease of use.
pub fn vec2f<X: CastF32, Y: CastF32>(x: X, y: Y) -> Vec2f {
    Vec2f { x: x.as_f32(), y: y.as_f32() }
}
<|endoftext|>


<commit_before>use core::hashmap::{ HashMap };

use common::prime::{ Prime };
use common::problem::{ Problem };

pub static problem: Problem<'static> = Problem {
    id: 77,
    answer: "71",
    solver: solve
};

fn count_way(
    sum: uint, map: &mut HashMap<(uint, uint), uint>, ps: &mut Prime
) -> uint {

    let cnt = count_sub(sum, 0, map, ps);
    if ps.is_prime(sum) {
        return cnt - 1;
    } else {
        return cnt;
    }

    fn count_sub(
        sum: uint, min_idx: uint, map: &mut HashMap<(uint, uint), uint>,
        ps: &mut Prime
    ) -> uint {
        let mut cnt = 0;
        let mut i = min_idx;
        loop {
            let mut p = ps.get_at(i);
            if p == sum {
                map.insert((p, i), 1);
                cnt += 1;
                break;
            }
            if sum < 2 * p { break; }

            cnt += match map.find(&(sum - p, i)).map(|v| **v) {
                Some(n) => n,
                None    => count_sub(sum - p, i, map, ps)
            };
            i += 1;
        }

        map.insert((sum, i), cnt);
        return cnt;
    }
}

fn solve() -> ~str {
    let mut ps = Prime::new();
    let mut map = HashMap::new();
    let mut n = 1;
    loop {
        let cnt = count_way(n, &mut map, &mut ps);
        if cnt > 5000 { return n.to_str(); }
        n += 1;
    }
}
<commit_msg>Modify problem #77<commit_after>use core::hashmap::{ HashMap };

use common::prime::{ Prime };
use common::problem::{ Problem };

pub static problem: Problem<'static> = Problem {
    id: 77,
    answer: "71",
    solver: solve
};

fn count_way(
    sum: uint, map: &mut HashMap<(uint, uint), uint>, ps: &mut Prime
) -> uint {

    let cnt = count_sub(sum, 0, map, ps);
    if ps.is_prime(sum) {
        return cnt - 1;
    } else {
        return cnt;
    }

    fn count_sub(
        sum: uint, min_idx: uint, map: &mut HashMap<(uint, uint), uint>,
        ps: &mut Prime
    ) -> uint {
        let mut cnt = 0;
        let mut i = min_idx;
        loop {
            let mut p = ps.get_at(i);
            if p == sum {
                map.insert((p, i), 1);
                cnt += 1;
                break;
            }
            if p > sum { break; }

            cnt += match map.find(&(sum - p, i)).map(|v| **v) {
                Some(n) => n,
                None    => count_sub(sum - p, i, map, ps)
            };
            i += 1;
        }

        map.insert((sum, i), cnt);
        return cnt;
    }
}

fn solve() -> ~str {
    let mut ps = Prime::new();
    let mut map = HashMap::new();
    let mut n = 1;
    loop {
        let cnt = count_way(n, &mut map, &mut ps);
        if cnt > 5000 { return n.to_str(); }
        n += 1;
    }
}
<|endoftext|>


<commit_before>use analysis::c_type::{implements_c_type, rustify_pointers};
use analysis::rust_type::{Result, TypeError};
use env::Env;
use library::*;
use traits::*;

pub fn used_ffi_type(env: &Env, type_id: TypeId, c_type: &str) -> Option<String> {
    let (_ptr, inner) = rustify_pointers(c_type);
    let type_ = ffi_inner(env, type_id, &inner);
    type_.ok()
}

pub fn ffi_type(env: &Env, tid: TypeId, c_type: &str) -> Result {
    let (ptr, inner) = rustify_pointers(c_type);
    let res = if ptr.is_empty() {
        if let Some(c_tid) = env.library.find_type(0, c_type) {
            // Fast track plain fundamental types avoiding some checks
            if env.library.type_(c_tid).maybe_ref_as::<Fundamental>().is_some() {
                match *env.library.type_(tid) {
                    Type::FixedArray(_, size) => {
                        ffi_inner(env, c_tid, c_type.into())
                            .map_any(|s| format!("[{}; {}]", s, size))
                    }
                    Type::Class(Class { c_type: ref expected, .. }) |
                            Type::Interface(Interface { c_type: ref expected, .. })
                            if c_type == "gpointer" => {
                        info!("[c:type `gpointer` instead of `*mut {}`, fixing]", expected);
                        ffi_inner(env, tid, expected)
                            .map_any(|s| format!("*mut {}", s))
                    }
                    _ => {
                        ffi_inner(env, c_tid, c_type.into())
                    }
                }
            }
            else { // c_type isn't fundamental
                ffi_inner(env, tid, &inner)
            }
        }
        else { // c_type doesn't match any type in the library by name
            ffi_inner(env, tid, &inner)
        }
    }
    else { // ptr not empty
        ffi_inner(env, tid, &inner)
            .map_any(|s| format!("{} {}", ptr, s))
    };
    trace!("ffi_type({:?}, {}) -> {:?}", tid, c_type, res);
    res
}

fn ffi_inner(env: &Env, tid: TypeId, inner: &str) -> Result {
    let typ = env.library.type_(tid);
    match *typ {
        Type::Fundamental(fund) => {
            use library::Fundamental::*;
            let inner = match fund {
                None => "libc::c_void",
                Boolean => "glib_ffi::gboolean", //TODO:check main namespace
                Int8 => "i8",
                UInt8 => "u8",
                Int16 => "i16",
                UInt16 => "u16",
                Int32 => "i32",
                UInt32 => "u32",
                Int64 => "i64",
                UInt64 => "u64",
                Char => "libc::c_char",
                UChar => "libc::c_uchar",
                Short => "libc::c_short",
                UShort => "libc::c_ushort",
                Int => "libc::c_int",
                UInt => "libc::c_uint",
                Long => "libc::c_long",
                ULong => "libc::c_ulong",
                Size => "libc::size_t",
                SSize => "libc::ssize_t",
                Float => "libc::c_float",
                Double => "libc::c_double",
                UniChar => "u32",
                Utf8 => "libc::c_char",
                Filename => "libc::c_char",
                Type => "glib_ffi::GType",
                _ => return Err(TypeError::Unimplemented(inner.into())),
            };
            Ok(inner.into())
        }
        Type::Record(..) | Type::Alias(..) | Type::Function(..) => {
            if let Some(declared_c_type) = typ.get_glib_name() {
                if declared_c_type != inner {
                    let msg = format!("[c:type mismatch `{}` != `{}` of `{}`]",
                                      inner, declared_c_type, typ.get_name());
                    warn!("{}", msg);
                    return Err(TypeError::Mismatch(msg));
                }
            }
            else {
                warn!("Type `{}` missing c_type", typ.get_name());
            }
            fix_name(env, tid, &inner)
        }
        Type::CArray(inner_tid) => ffi_inner(env, inner_tid, inner),
        Type::FixedArray(inner_tid, size) => {
            ffi_inner(env, inner_tid, inner)
                .map_any(|s| format!("[{}; {}]", s, size))
        }
        Type::Array(..) | Type::PtrArray(..)
                | Type::List(..) | Type::SList(..) | Type::HashTable(..) => {
            fix_name(env, tid, &inner)
        }
        _ => {
            if let Some(glib_name) = env.library.type_(tid).get_glib_name() {
                if inner != glib_name {
                    if implements_c_type(env, tid, &inner) {
                        info!("[c:type {} of {} <: {}, fixing]", glib_name,
                            env.library.type_(tid).get_name(), inner);
                        fix_name(env, tid, &glib_name)
                    }
                    else {
                        let msg = format!("[c:type mismatch {} != {} of {}]", inner, glib_name,
                            env.library.type_(tid).get_name());
                        warn!("{}", msg);
                        Err(TypeError::Mismatch(msg))
                    }
                }
                else {
                    fix_name(env, tid, &inner)
                }
            }
            else {
                let msg = format!("[Missing glib_name of {}, can't match != {}]",
                                  env.library.type_(tid).get_name(), inner);
                warn!("{}", msg);
                Err(TypeError::Mismatch(msg))
            }
        }
    }
}

fn fix_name(env: &Env, type_id: TypeId, name: &str) -> Result {
    if type_id.ns_id == INTERNAL_NAMESPACE {
        match *env.library.type_(type_id) {
            Type::Array(..) | Type::PtrArray(..) |
            Type::List(..) | Type::SList(..) | Type::HashTable(..) =>
                Ok(format!("{}::{}", &env.namespaces[env.namespaces.glib_ns_id].ffi_crate_name, name)),
            _ => Ok(name.into()),
        }
    } else {
        let name_with_prefix = format!("{}::{}", &env.namespaces[type_id.ns_id].ffi_crate_name, name);
        if env.type_status_sys(&type_id.full_name(&env.library)).ignored() {
            Err(TypeError::Ignored(name_with_prefix))
        } else {
            Ok(name_with_prefix)
        }
    }
}
<commit_msg>Don't return from used_ffi_type basic types<commit_after>use analysis::c_type::{implements_c_type, rustify_pointers};
use analysis::rust_type::{Result, TypeError};
use env::Env;
use library::*;
use traits::*;

pub fn used_ffi_type(env: &Env, type_id: TypeId, c_type: &str) -> Option<String> {
    let (_ptr, inner) = rustify_pointers(c_type);
    let type_ = ffi_inner(env, type_id, &inner);
    type_.ok().and_then(|type_name| {
        if type_name.find(':').is_some() {
            Some(type_name)
        } else {
            None
        }
    })
}

pub fn ffi_type(env: &Env, tid: TypeId, c_type: &str) -> Result {
    let (ptr, inner) = rustify_pointers(c_type);
    let res = if ptr.is_empty() {
        if let Some(c_tid) = env.library.find_type(0, c_type) {
            // Fast track plain fundamental types avoiding some checks
            if env.library.type_(c_tid).maybe_ref_as::<Fundamental>().is_some() {
                match *env.library.type_(tid) {
                    Type::FixedArray(_, size) => {
                        ffi_inner(env, c_tid, c_type.into())
                            .map_any(|s| format!("[{}; {}]", s, size))
                    }
                    Type::Class(Class { c_type: ref expected, .. }) |
                            Type::Interface(Interface { c_type: ref expected, .. })
                            if c_type == "gpointer" => {
                        info!("[c:type `gpointer` instead of `*mut {}`, fixing]", expected);
                        ffi_inner(env, tid, expected)
                            .map_any(|s| format!("*mut {}", s))
                    }
                    _ => {
                        ffi_inner(env, c_tid, c_type.into())
                    }
                }
            }
            else { // c_type isn't fundamental
                ffi_inner(env, tid, &inner)
            }
        }
        else { // c_type doesn't match any type in the library by name
            ffi_inner(env, tid, &inner)
        }
    }
    else { // ptr not empty
        ffi_inner(env, tid, &inner)
            .map_any(|s| format!("{} {}", ptr, s))
    };
    trace!("ffi_type({:?}, {}) -> {:?}", tid, c_type, res);
    res
}

fn ffi_inner(env: &Env, tid: TypeId, inner: &str) -> Result {
    let typ = env.library.type_(tid);
    match *typ {
        Type::Fundamental(fund) => {
            use library::Fundamental::*;
            let inner = match fund {
                None => "libc::c_void",
                Boolean => "glib_ffi::gboolean", //TODO:check main namespace
                Int8 => "i8",
                UInt8 => "u8",
                Int16 => "i16",
                UInt16 => "u16",
                Int32 => "i32",
                UInt32 => "u32",
                Int64 => "i64",
                UInt64 => "u64",
                Char => "libc::c_char",
                UChar => "libc::c_uchar",
                Short => "libc::c_short",
                UShort => "libc::c_ushort",
                Int => "libc::c_int",
                UInt => "libc::c_uint",
                Long => "libc::c_long",
                ULong => "libc::c_ulong",
                Size => "libc::size_t",
                SSize => "libc::ssize_t",
                Float => "libc::c_float",
                Double => "libc::c_double",
                UniChar => "u32",
                Utf8 => "libc::c_char",
                Filename => "libc::c_char",
                Type => "glib_ffi::GType",
                _ => return Err(TypeError::Unimplemented(inner.into())),
            };
            Ok(inner.into())
        }
        Type::Record(..) | Type::Alias(..) | Type::Function(..) => {
            if let Some(declared_c_type) = typ.get_glib_name() {
                if declared_c_type != inner {
                    let msg = format!("[c:type mismatch `{}` != `{}` of `{}`]",
                                      inner, declared_c_type, typ.get_name());
                    warn!("{}", msg);
                    return Err(TypeError::Mismatch(msg));
                }
            }
            else {
                warn!("Type `{}` missing c_type", typ.get_name());
            }
            fix_name(env, tid, &inner)
        }
        Type::CArray(inner_tid) => ffi_inner(env, inner_tid, inner),
        Type::FixedArray(inner_tid, size) => {
            ffi_inner(env, inner_tid, inner)
                .map_any(|s| format!("[{}; {}]", s, size))
        }
        Type::Array(..) | Type::PtrArray(..)
                | Type::List(..) | Type::SList(..) | Type::HashTable(..) => {
            fix_name(env, tid, &inner)
        }
        _ => {
            if let Some(glib_name) = env.library.type_(tid).get_glib_name() {
                if inner != glib_name {
                    if implements_c_type(env, tid, &inner) {
                        info!("[c:type {} of {} <: {}, fixing]", glib_name,
                            env.library.type_(tid).get_name(), inner);
                        fix_name(env, tid, &glib_name)
                    }
                    else {
                        let msg = format!("[c:type mismatch {} != {} of {}]", inner, glib_name,
                            env.library.type_(tid).get_name());
                        warn!("{}", msg);
                        Err(TypeError::Mismatch(msg))
                    }
                }
                else {
                    fix_name(env, tid, &inner)
                }
            }
            else {
                let msg = format!("[Missing glib_name of {}, can't match != {}]",
                                  env.library.type_(tid).get_name(), inner);
                warn!("{}", msg);
                Err(TypeError::Mismatch(msg))
            }
        }
    }
}

fn fix_name(env: &Env, type_id: TypeId, name: &str) -> Result {
    if type_id.ns_id == INTERNAL_NAMESPACE {
        match *env.library.type_(type_id) {
            Type::Array(..) | Type::PtrArray(..) |
            Type::List(..) | Type::SList(..) | Type::HashTable(..) =>
                Ok(format!("{}::{}", &env.namespaces[env.namespaces.glib_ns_id].ffi_crate_name, name)),
            _ => Ok(name.into()),
        }
    } else {
        let name_with_prefix = format!("{}::{}", &env.namespaces[type_id.ns_id].ffi_crate_name, name);
        if env.type_status_sys(&type_id.full_name(&env.library)).ignored() {
            Err(TypeError::Ignored(name_with_prefix))
        } else {
            Ok(name_with_prefix)
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;
use std::sync::Arc;
use std::os::raw::c_void;
use std::ptr;

use buffer::Buffer;
use buffer::BufferAccess;
use buffer::TypedBuffer;
use buffer::TypedBufferAccess;
use buffer::BufferInner;
use command_buffer::CommandAddError;
use command_buffer::cb::AddCommand;
use command_buffer::cb::UnsafeCommandBufferBuilder;
use command_buffer::pool::CommandPool;
use device::Device;
use device::DeviceOwned;
use VulkanObject;
use VulkanPointers;
use vk;

/// Command that sets the content of a buffer to some data.
pub struct CmdUpdateBuffer {
    // The buffer to update.
    buffer: B,
    // Raw buffer handle.
    buffer_handle: vk::Buffer,
    // Offset of the update.
    offset: vk::DeviceSize,
    // Size of the update.
    size: vk::DeviceSize,
    // If null, contains a pointer to the raw data to write. If `None`, the data is the `data`
    // field.
    data_ptr: *const c_void,
    // The data to write to the buffer or a reference to it.
    data: D,
}

impl CmdUpdateBuffer {
    /// Builds a command that writes data to a buffer.
    ///
    /// If the size of the data and the size of the buffer mismatch, then only the intersection
    /// of both will be written.
    ///
    /// The size of the modification must not exceed 65536 bytes. The offset and size must be
    /// multiples of four.
    #[inline]
    pub fn new
(buffer: P, data: D) -> Result<CmdUpdateBuffer, CmdUpdateBufferError>
        where P: Buffer<Access = B> + TypedBuffer<Content = D>,
              B: BufferAccess,
              D: 'static
    {
        unsafe {
            CmdUpdateBuffer::unchecked_type(buffer.access(), data)
        }
    }

    /// Same as `new`, except that the parameter is a `BufferAccess` instead of a `Buffer`.
    #[inline]
    pub fn from_access(buffer: B, data: D) -> Result<CmdUpdateBuffer, CmdUpdateBufferError>
        where B: BufferAccess + TypedBufferAccess<Content = D>,
              D: 'static
    {
        unsafe {
            CmdUpdateBuffer::unchecked_type(buffer, data)
        }
    }

    /// Same as `from_access`, except that type safety is not enforced.
    pub unsafe fn unchecked_type(buffer: B, data: D)
                                 -> Result<CmdUpdateBuffer, CmdUpdateBufferError>
        where B: BufferAccess
    {
        let size = buffer.size();

        let (buffer_handle, offset) = {
            let BufferInner { buffer: buffer_inner, offset } = buffer.inner();
            if !buffer_inner.usage_transfer_dest() {
                return Err(CmdUpdateBufferError::BufferMissingUsage);
            }
            if offset % 4 != 0 {
                return Err(CmdUpdateBufferError::WrongAlignment);
            }
            (buffer_inner.internal_object(), offset)
        };

        if size % 4 != 0 {
            return Err(CmdUpdateBufferError::WrongAlignment);
        }

        if size > 65536 {
            return Err(CmdUpdateBufferError::DataTooLarge);
        }

        Ok(CmdUpdateBuffer {
            buffer: buffer,
            buffer_handle: buffer_handle,
            offset: offset as vk::DeviceSize,
            size: size as vk::DeviceSize,
            data_ptr: ptr::null(),
            data: data,
        })
    }

    /// Returns the buffer that is going to be written.
    #[inline]
    pub fn buffer(&self) -> &B {
        &self.buffer
    }
}

unsafe impl DeviceOwned for CmdUpdateBuffer
    where B: DeviceOwned
{
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.buffer.device()
    }
}

unsafe impl<'a, P, B, D> AddCommand<&'a CmdUpdateBuffer> for UnsafeCommandBufferBuilder

    where B: BufferAccess,
          P: CommandPool,
{
    type Out = UnsafeCommandBufferBuilder
;

    #[inline]
    fn add(self, command: &'a CmdUpdateBuffer) -> Result<Self::Out, CommandAddError> {
        unsafe {
            let data = if command.data_ptr.is_null() {
                &command.data as *const D as *const _
            } else {
                command.data_ptr as *const _
            };

            let vk = self.device().pointers();
            let cmd = self.internal_object();
            vk.CmdUpdateBuffer(cmd, command.buffer_handle, command.offset, command.size, data);
        }

        Ok(self)
    }
}

/// Error that can happen when creating a `CmdUpdateBuffer`.
#[derive(Debug, Copy, Clone)]
pub enum CmdUpdateBufferError {
    /// The "transfer destination" usage must be enabled on the buffer.
    BufferMissingUsage,
    /// The data or size must be 4-bytes aligned.
    WrongAlignment,
    /// The data must not be larger than 64k bytes.
    DataTooLarge,
}

impl error::Error for CmdUpdateBufferError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            CmdUpdateBufferError::BufferMissingUsage => {
                "the transfer destination usage must be enabled on the buffer"
            },
            CmdUpdateBufferError::WrongAlignment => {
                "the offset or size are not aligned to 4 bytes"
            },
            CmdUpdateBufferError::DataTooLarge => "data is too large",
        }
    }
}

impl fmt::Display for CmdUpdateBufferError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}
<commit_msg>Remove dead data causing update_buffer to be unusable<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::error;
use std::fmt;
use std::sync::Arc;

use buffer::Buffer;
use buffer::BufferAccess;
use buffer::TypedBuffer;
use buffer::TypedBufferAccess;
use buffer::BufferInner;
use command_buffer::CommandAddError;
use command_buffer::cb::AddCommand;
use command_buffer::cb::UnsafeCommandBufferBuilder;
use command_buffer::pool::CommandPool;
use device::Device;
use device::DeviceOwned;
use VulkanObject;
use VulkanPointers;
use vk;

/// Command that sets the content of a buffer to some data.
pub struct CmdUpdateBuffer {
    // The buffer to update.
    buffer: B,
    // Raw buffer handle.
    buffer_handle: vk::Buffer,
    // Offset of the update.
    offset: vk::DeviceSize,
    // Size of the update.
    size: vk::DeviceSize,
    // The data to write to the buffer or a reference to it.
    data: D,
}

impl CmdUpdateBuffer {
    /// Builds a command that writes data to a buffer.
    ///
    /// If the size of the data and the size of the buffer mismatch, then only the intersection
    /// of both will be written.
    ///
    /// The size of the modification must not exceed 65536 bytes. The offset and size must be
    /// multiples of four.
    #[inline]
    pub fn new
(buffer: P, data: D) -> Result<CmdUpdateBuffer, CmdUpdateBufferError>
        where P: Buffer<Access = B> + TypedBuffer<Content = D>,
              B: BufferAccess,
              D: 'static
    {
        unsafe {
            CmdUpdateBuffer::unchecked_type(buffer.access(), data)
        }
    }

    /// Same as `new`, except that the parameter is a `BufferAccess` instead of a `Buffer`.
    #[inline]
    pub fn from_access(buffer: B, data: D) -> Result<CmdUpdateBuffer, CmdUpdateBufferError>
        where B: BufferAccess + TypedBufferAccess<Content = D>,
              D: 'static
    {
        unsafe {
            CmdUpdateBuffer::unchecked_type(buffer, data)
        }
    }

    /// Same as `from_access`, except that type safety is not enforced.
    pub unsafe fn unchecked_type(buffer: B, data: D)
                                 -> Result<CmdUpdateBuffer, CmdUpdateBufferError>
        where B: BufferAccess
    {
        let size = buffer.size();

        let (buffer_handle, offset) = {
            let BufferInner { buffer: buffer_inner, offset } = buffer.inner();
            if !buffer_inner.usage_transfer_dest() {
                return Err(CmdUpdateBufferError::BufferMissingUsage);
            }
            if offset % 4 != 0 {
                return Err(CmdUpdateBufferError::WrongAlignment);
            }
            (buffer_inner.internal_object(), offset)
        };

        if size % 4 != 0 {
            return Err(CmdUpdateBufferError::WrongAlignment);
        }

        if size > 65536 {
            return Err(CmdUpdateBufferError::DataTooLarge);
        }

        Ok(CmdUpdateBuffer {
            buffer: buffer,
            buffer_handle: buffer_handle,
            offset: offset as vk::DeviceSize,
            size: size as vk::DeviceSize,
            data: data,
        })
    }

    /// Returns the buffer that is going to be written.
    #[inline]
    pub fn buffer(&self) -> &B {
        &self.buffer
    }
}

unsafe impl DeviceOwned for CmdUpdateBuffer
    where B: DeviceOwned
{
    #[inline]
    fn device(&self) -> &Arc<Device> {
        self.buffer.device()
    }
}

unsafe impl<'a, P, B, D> AddCommand<&'a CmdUpdateBuffer> for UnsafeCommandBufferBuilder

    where B: BufferAccess,
          P: CommandPool,
{
    type Out = UnsafeCommandBufferBuilder
;

    #[inline]
    fn add(self, command: &'a CmdUpdateBuffer) -> Result<Self::Out, CommandAddError> {
        unsafe {
            let data = &command.data as *const D as *const _;
            let vk = self.device().pointers();
            let cmd = self.internal_object();
            vk.CmdUpdateBuffer(cmd, command.buffer_handle, command.offset, command.size, data);
        }

        Ok(self)
    }
}

/// Error that can happen when creating a `CmdUpdateBuffer`.
#[derive(Debug, Copy, Clone)]
pub enum CmdUpdateBufferError {
    /// The "transfer destination" usage must be enabled on the buffer.
    BufferMissingUsage,
    /// The data or size must be 4-bytes aligned.
    WrongAlignment,
    /// The data must not be larger than 64k bytes.
    DataTooLarge,
}

impl error::Error for CmdUpdateBufferError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            CmdUpdateBufferError::BufferMissingUsage => {
                "the transfer destination usage must be enabled on the buffer"
            },
            CmdUpdateBufferError::WrongAlignment => {
                "the offset or size are not aligned to 4 bytes"
            },
            CmdUpdateBufferError::DataTooLarge => "data is too large",
        }
    }
}

impl fmt::Display for CmdUpdateBufferError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}
<|endoftext|>


<commit_before>use quote::{ToTokens, Tokens};
use syn::punctuated::Punctuated;
use syn::synom::Synom;
use syn::{Field, FieldValue, Meta};

mod metadata;
mod request;
mod response;

use self::metadata::Metadata;
use self::request::Request;
use self::response::Response;

pub fn strip_serde_attrs(field: &Field) -> Field {
    let mut field = field.clone();

    field.attrs = field.attrs.into_iter().filter(|attr| {
        let meta = attr.interpret_meta()
            .expect("ruma_api! could not parse field attributes");

        let meta_list = match meta {
            Meta::List(meta_list) => meta_list,
            _ => panic!("expected Meta::List"),
        };

        if meta_list.ident.as_ref() != "serde" {
            return true;
        }

        false
    }).collect();

    field
}

pub struct Api {
    metadata: Metadata,
    request: Request,
    response: Response,
}

impl From<RawApi> for Api {
    fn from(raw_api: RawApi) -> Self {
        Api {
            metadata: raw_api.metadata.into(),
            request: raw_api.request.into(),
            response: raw_api.response.into(),
        }
    }
}

impl ToTokens for Api {
    fn to_tokens(&self, tokens: &mut Tokens) {
        let description = &self.metadata.description;
        let method = &self.metadata.method;
        let name = &self.metadata.name;
        let path = &self.metadata.path;
        let rate_limited = &self.metadata.rate_limited;
        let requires_authentication = &self.metadata.requires_authentication;

        let request_types = {
            let mut tokens = Tokens::new();
            self.request.to_tokens(&mut tokens);
            tokens
        };
        let response_types = {
            let mut tokens = Tokens::new();
            self.response.to_tokens(&mut tokens);
            tokens
        };

        let set_request_path = if self.request.has_path_fields() {
            let path_str_quoted = path.as_str();
            assert!(
                path_str_quoted.starts_with('"') && path_str_quoted.ends_with('"'),
                "path needs to be a string literal"
            );

            let path_str = &path_str_quoted[1 .. path_str_quoted.len() - 1];

            assert!(path_str.starts_with('/'), "path needs to start with '/'");
            assert!(
                path_str.chars().filter(|c| *c == ':').count() == self.request.path_field_count(),
                "number of declared path parameters needs to match amount of placeholders in path"
            );

            let request_path_init_fields = self.request.request_path_init_fields();

            let mut tokens = quote! {
                let request_path = RequestPath {
                    #request_path_init_fields
                };

                // This `unwrap()` can only fail when the url is a
                // cannot-be-base url like `mailto:` or `data:`, which is not
                // the case for our placeholder url.
                let mut path_segments = url.path_segments_mut().unwrap();
            };

            for segment in path_str[1..].split('/') {
                tokens.append_all(quote! {
                    path_segments.push
                });

                if segment.starts_with(':') {
                    let what_is_this = &segment[1..];

                    tokens.append_all(quote! {
                        (&request_path.#what_is_this.to_string());
                    });
                } else {
                    tokens.append_all(quote! {
                        ("#segment");
                    });
                }
            }

            tokens
        } else {
            quote! {
                url.set_path(metadata.path);
            }
        };

        let set_request_query = if self.request.has_query_fields() {
            let request_query_init_fields = self.request.request_query_init_fields();

            quote! {
                let request_query = RequestQuery {
                    #request_query_init_fields
                };

                url.set_query(Some(&::serde_urlencoded::to_string(request_query)?));
            }
        } else {
            Tokens::new()
        };

        let add_body_to_request = if let Some(field) = self.request.newtype_body_field() {
            let field_name = field.ident.expect("expected field to have an identifier");

            quote! {
                let request_body = RequestBody(request.#field_name);

                hyper_request.set_body(::serde_json::to_vec(&request_body)?);
            }
        } else if self.request.has_body_fields() {
            let request_body_init_fields = self.request.request_body_init_fields();

            quote! {
                let request_body = RequestBody {
                    #request_body_init_fields
                };

                hyper_request.set_body(::serde_json::to_vec(&request_body)?);
            }
        } else {
            Tokens::new()
        };

        let deserialize_response_body = if let Some(field) = self.response.newtype_body_field() {
            let field_type = &field.ty;

            let mut tokens = Tokens::new();

            tokens.append_all(quote! {
                let future_response = hyper_response.body()
                    .fold::<_, _, Result<_, ::std::io::Error>>(Vec::new(), |mut bytes, chunk| {
                        bytes.write_all(&chunk)?;

                        Ok(bytes)
                    })
                    .map_err(::ruma_api::Error::from)
                    .and_then(|bytes| {
                        ::serde_json::from_slice::<#field_type>(bytes.as_slice())
                            .map_err(::ruma_api::Error::from)
                    })
            });

            tokens.append_all(".and_then(move |response_body| {".into_tokens());

            tokens
        } else if self.response.has_body_fields() {
            let mut tokens = Tokens::new();

            tokens.append_all(quote! {
                let future_response = hyper_response.body()
                    .fold::<_, _, Result<_, ::std::io::Error>>(Vec::new(), |mut bytes, chunk| {
                        bytes.write_all(&chunk)?;

                        Ok(bytes)
                    })
                    .map_err(::ruma_api::Error::from)
                    .and_then(|bytes| {
                        ::serde_json::from_slice::<ResponseBody>(bytes.as_slice())
                            .map_err(::ruma_api::Error::from)
                    })
            });

            tokens.append_all(".and_then(move |response_body| {".into_tokens());

            tokens
        } else {
            let mut tokens = Tokens::new();

            tokens.append_all(quote! {
                let future_response = ::futures::future::ok(())
            });

            tokens.append_all(".and_then(move |_| {".into_tokens());

            tokens
        };

        let mut closure_end = Tokens::new();
        closure_end.append_all("});".into_tokens());

        let extract_headers = if self.response.has_header_fields() {
            quote! {
                let mut headers = hyper_response.headers().clone();
            }
        } else {
            Tokens::new()
        };

        let response_init_fields = if self.response.has_fields() {
            self.response.init_fields()
        } else {
            Tokens::new()
        };

        tokens.append_all(quote! {
            #[allow(unused_imports)]
            use std::io::Write as _Write;

            #[allow(unused_imports)]
            use ::futures::{Future as _Future, Stream as _Stream};
            use ::ruma_api::Endpoint as _RumaApiEndpoint;

            /// The API endpoint.
            #[derive(Debug)]
            pub struct Endpoint;

            #request_types

            impl ::std::convert::TryFrom<Request> for ::hyper::Request {
                type Error = ::ruma_api::Error;

                #[allow(unused_mut, unused_variables)]
                fn try_from(request: Request) -> Result<Self, Self::Error> {
                    let metadata = Endpoint::METADATA;

                    // Use dummy homeserver url which has to be overwritten in
                    // the calling code. Previously (with hyper::Uri) this was
                    // not required, but Url::parse only accepts absolute urls.
                    let mut url = ::url::Url::parse("http://invalid-host-please-change/").unwrap();

                    { #set_request_path }
                    { #set_request_query }

                    let mut hyper_request = ::hyper::Request::new(
                        metadata.method,
                        // Every valid URL is a valid URI
                        url.into_string().parse().unwrap(),
                    );

                    { #add_body_to_request }

                    Ok(hyper_request)
                }
            }

            #response_types

            impl ::futures::future::FutureFrom<::hyper::Response> for Response {
                type Future = Box<_Future<Item = Self, Error = Self::Error>>;
                type Error = ::ruma_api::Error;

                #[allow(unused_variables)]
                fn future_from(hyper_response: ::hyper::Response)
                -> Box<_Future<Item = Self, Error = Self::Error>> {
                    #extract_headers

                    #deserialize_response_body

                    let response = Response {
                        #response_init_fields
                    };

                    Ok(response)
                    #closure_end

                    Box::new(future_response)
                }
            }

            impl ::ruma_api::Endpoint for Endpoint {
                type Request = Request;
                type Response = Response;

                const METADATA: ::ruma_api::Metadata = ::ruma_api::Metadata {
                    description: #description,
                    method: ::hyper::#method,
                    name: #name,
                    path: #path,
                    rate_limited: #rate_limited,
                    requires_authentication: #requires_authentication,
                };
            }
        });
    }
}

type ParseMetadata = Punctuated<FieldValue, Token![,]>;
type ParseFields = Punctuated<Field, Token![,]>;

pub struct RawApi {
    pub metadata: Vec<FieldValue>,
    pub request: Vec<Field>,
    pub response: Vec<Field>,
}

impl Synom for RawApi {
    named!(parse -> Self, do_parse!(
        custom_keyword!(metadata) >>
        metadata: braces!(ParseMetadata::parse_terminated) >>
        custom_keyword!(request) >>
        request: braces!(call!(ParseFields::parse_terminated_with, Field::parse_named)) >>
        custom_keyword!(response) >>
        response: braces!(call!(ParseFields::parse_terminated_with, Field::parse_named)) >>
        (RawApi {
            metadata: metadata.1.into_iter().collect(),
            request: request.1.into_iter().collect(),
            response: response.1.into_iter().collect(),
        })
    ));
}
<commit_msg>Fix another bug and use a more useful variable name for named path segments.<commit_after>use quote::{ToTokens, Tokens};
use syn::punctuated::Punctuated;
use syn::synom::Synom;
use syn::{Field, FieldValue, Meta};

mod metadata;
mod request;
mod response;

use self::metadata::Metadata;
use self::request::Request;
use self::response::Response;

pub fn strip_serde_attrs(field: &Field) -> Field {
    let mut field = field.clone();

    field.attrs = field.attrs.into_iter().filter(|attr| {
        let meta = attr.interpret_meta()
            .expect("ruma_api! could not parse field attributes");

        let meta_list = match meta {
            Meta::List(meta_list) => meta_list,
            _ => panic!("expected Meta::List"),
        };

        if meta_list.ident.as_ref() != "serde" {
            return true;
        }

        false
    }).collect();

    field
}

pub struct Api {
    metadata: Metadata,
    request: Request,
    response: Response,
}

impl From<RawApi> for Api {
    fn from(raw_api: RawApi) -> Self {
        Api {
            metadata: raw_api.metadata.into(),
            request: raw_api.request.into(),
            response: raw_api.response.into(),
        }
    }
}

impl ToTokens for Api {
    fn to_tokens(&self, tokens: &mut Tokens) {
        let description = &self.metadata.description;
        let method = &self.metadata.method;
        let name = &self.metadata.name;
        let path = &self.metadata.path;
        let rate_limited = &self.metadata.rate_limited;
        let requires_authentication = &self.metadata.requires_authentication;

        let request_types = {
            let mut tokens = Tokens::new();
            self.request.to_tokens(&mut tokens);
            tokens
        };
        let response_types = {
            let mut tokens = Tokens::new();
            self.response.to_tokens(&mut tokens);
            tokens
        };

        let set_request_path = if self.request.has_path_fields() {
            let path_str = path.as_str();

            assert!(path_str.starts_with('/'), "path needs to start with '/'");
            assert!(
                path_str.chars().filter(|c| *c == ':').count() == self.request.path_field_count(),
                "number of declared path parameters needs to match amount of placeholders in path"
            );

            let request_path_init_fields = self.request.request_path_init_fields();

            let mut tokens = quote! {
                let request_path = RequestPath {
                    #request_path_init_fields
                };

                // This `unwrap()` can only fail when the url is a
                // cannot-be-base url like `mailto:` or `data:`, which is not
                // the case for our placeholder url.
                let mut path_segments = url.path_segments_mut().unwrap();
            };

            for segment in path_str[1..].split('/') {
                tokens.append_all(quote! {
                    path_segments.push
                });

                if segment.starts_with(':') {
                    let path_var = &segment[1..];

                    tokens.append_all(quote! {
                        (&request_path.#path_var.to_string());
                    });
                } else {
                    tokens.append_all(quote! {
                        ("#segment");
                    });
                }
            }

            tokens
        } else {
            quote! {
                url.set_path(metadata.path);
            }
        };

        let set_request_query = if self.request.has_query_fields() {
            let request_query_init_fields = self.request.request_query_init_fields();

            quote! {
                let request_query = RequestQuery {
                    #request_query_init_fields
                };

                url.set_query(Some(&::serde_urlencoded::to_string(request_query)?));
            }
        } else {
            Tokens::new()
        };

        let add_body_to_request = if let Some(field) = self.request.newtype_body_field() {
            let field_name = field.ident.expect("expected field to have an identifier");

            quote! {
                let request_body = RequestBody(request.#field_name);

                hyper_request.set_body(::serde_json::to_vec(&request_body)?);
            }
        } else if self.request.has_body_fields() {
            let request_body_init_fields = self.request.request_body_init_fields();

            quote! {
                let request_body = RequestBody {
                    #request_body_init_fields
                };

                hyper_request.set_body(::serde_json::to_vec(&request_body)?);
            }
        } else {
            Tokens::new()
        };

        let deserialize_response_body = if let Some(field) = self.response.newtype_body_field() {
            let field_type = &field.ty;

            let mut tokens = Tokens::new();

            tokens.append_all(quote! {
                let future_response = hyper_response.body()
                    .fold::<_, _, Result<_, ::std::io::Error>>(Vec::new(), |mut bytes, chunk| {
                        bytes.write_all(&chunk)?;

                        Ok(bytes)
                    })
                    .map_err(::ruma_api::Error::from)
                    .and_then(|bytes| {
                        ::serde_json::from_slice::<#field_type>(bytes.as_slice())
                            .map_err(::ruma_api::Error::from)
                    })
            });

            tokens.append_all(".and_then(move |response_body| {".into_tokens());

            tokens
        } else if self.response.has_body_fields() {
            let mut tokens = Tokens::new();

            tokens.append_all(quote! {
                let future_response = hyper_response.body()
                    .fold::<_, _, Result<_, ::std::io::Error>>(Vec::new(), |mut bytes, chunk| {
                        bytes.write_all(&chunk)?;

                        Ok(bytes)
                    })
                    .map_err(::ruma_api::Error::from)
                    .and_then(|bytes| {
                        ::serde_json::from_slice::<ResponseBody>(bytes.as_slice())
                            .map_err(::ruma_api::Error::from)
                    })
            });

            tokens.append_all(".and_then(move |response_body| {".into_tokens());

            tokens
        } else {
            let mut tokens = Tokens::new();

            tokens.append_all(quote! {
                let future_response = ::futures::future::ok(())
            });

            tokens.append_all(".and_then(move |_| {".into_tokens());

            tokens
        };

        let mut closure_end = Tokens::new();
        closure_end.append_all("});".into_tokens());

        let extract_headers = if self.response.has_header_fields() {
            quote! {
                let mut headers = hyper_response.headers().clone();
            }
        } else {
            Tokens::new()
        };

        let response_init_fields = if self.response.has_fields() {
            self.response.init_fields()
        } else {
            Tokens::new()
        };

        tokens.append_all(quote! {
            #[allow(unused_imports)]
            use std::io::Write as _Write;

            #[allow(unused_imports)]
            use ::futures::{Future as _Future, Stream as _Stream};
            use ::ruma_api::Endpoint as _RumaApiEndpoint;

            /// The API endpoint.
            #[derive(Debug)]
            pub struct Endpoint;

            #request_types

            impl ::std::convert::TryFrom<Request> for ::hyper::Request {
                type Error = ::ruma_api::Error;

                #[allow(unused_mut, unused_variables)]
                fn try_from(request: Request) -> Result<Self, Self::Error> {
                    let metadata = Endpoint::METADATA;

                    // Use dummy homeserver url which has to be overwritten in
                    // the calling code. Previously (with hyper::Uri) this was
                    // not required, but Url::parse only accepts absolute urls.
                    let mut url = ::url::Url::parse("http://invalid-host-please-change/").unwrap();

                    { #set_request_path }
                    { #set_request_query }

                    let mut hyper_request = ::hyper::Request::new(
                        metadata.method,
                        // Every valid URL is a valid URI
                        url.into_string().parse().unwrap(),
                    );

                    { #add_body_to_request }

                    Ok(hyper_request)
                }
            }

            #response_types

            impl ::futures::future::FutureFrom<::hyper::Response> for Response {
                type Future = Box<_Future<Item = Self, Error = Self::Error>>;
                type Error = ::ruma_api::Error;

                #[allow(unused_variables)]
                fn future_from(hyper_response: ::hyper::Response)
                -> Box<_Future<Item = Self, Error = Self::Error>> {
                    #extract_headers

                    #deserialize_response_body

                    let response = Response {
                        #response_init_fields
                    };

                    Ok(response)
                    #closure_end

                    Box::new(future_response)
                }
            }

            impl ::ruma_api::Endpoint for Endpoint {
                type Request = Request;
                type Response = Response;

                const METADATA: ::ruma_api::Metadata = ::ruma_api::Metadata {
                    description: #description,
                    method: ::hyper::#method,
                    name: #name,
                    path: #path,
                    rate_limited: #rate_limited,
                    requires_authentication: #requires_authentication,
                };
            }
        });
    }
}

type ParseMetadata = Punctuated<FieldValue, Token![,]>;
type ParseFields = Punctuated<Field, Token![,]>;

pub struct RawApi {
    pub metadata: Vec<FieldValue>,
    pub request: Vec<Field>,
    pub response: Vec<Field>,
}

impl Synom for RawApi {
    named!(parse -> Self, do_parse!(
        custom_keyword!(metadata) >>
        metadata: braces!(ParseMetadata::parse_terminated) >>
        custom_keyword!(request) >>
        request: braces!(call!(ParseFields::parse_terminated_with, Field::parse_named)) >>
        custom_keyword!(response) >>
        response: braces!(call!(ParseFields::parse_terminated_with, Field::parse_named)) >>
        (RawApi {
            metadata: metadata.1.into_iter().collect(),
            request: request.1.into_iter().collect(),
            response: response.1.into_iter().collect(),
        })
    ));
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

use endianity::{Endianity, EndianBuf};
use lookup::{LookupParser, LookupEntryIter, DebugLookup};
use parser::{parse_address_size, parse_debug_info_offset, parse_unit_length, parse_u16,
             parse_address, Error, Format, DebugInfoOffset, ParseResult};
use std::cmp::Ordering;
use std::marker::PhantomData;
use std::rc::Rc;

#[derive(Debug, PartialEq, Eq)]
pub struct ArangeHeader {
    format: Format,
    length: u64,
    version: u16,
    offset: DebugInfoOffset,
    address_size: u8,
    segment_size: u8,
}

/// A single parsed arange.
#[derive(Debug, Clone, Eq)]
pub struct ArangeEntry {
    segment: u64,
    address: u64,
    length: u64,
    header: Rc<ArangeHeader>,
}

impl ArangeEntry {
    /// Return the segment selector of this arange.
    pub fn segment(&self) -> Option<u64> {
        if self.header.segment_size != 0 {
            Some(self.segment)
        } else {
            None
        }
    }

    /// Return the beginning address of this arange.
    pub fn address(&self) -> u64 {
        self.address
    }

    /// Return the length of this arange.
    pub fn length(&self) -> u64 {
        self.length
    }

    /// Return the offset into the .debug_info section for this arange.
    pub fn debug_info_offset(&self) -> DebugInfoOffset {
        self.header.offset
    }
}

impl PartialEq for ArangeEntry {
    fn eq(&self, other: &ArangeEntry) -> bool {
        // The expected comparison, but verify that header matches if everything else does.
        match (self.segment == other.segment,
               self.address == other.address,
               self.length == other.length) {
            (true, true, true) => {
                debug_assert!(self.header == other.header);
                true
            }
            _ => false,
        }
    }
}

impl PartialOrd for ArangeEntry {
    fn partial_cmp(&self, other: &ArangeEntry) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for ArangeEntry {
    fn cmp(&self, other: &ArangeEntry) -> Ordering {
        // The expected comparison, but ignore header.
        match (self.segment.cmp(&other.segment),
               self.address.cmp(&other.address),
               self.length.cmp(&other.length)) {
            (Ordering::Equal, Ordering::Equal, Ordering::Equal) => Ordering::Equal,
            (Ordering::Less, _, _) |
            (Ordering::Equal, Ordering::Less, _) |
            (Ordering::Equal, Ordering::Equal, Ordering::Less) => Ordering::Less,
            (Ordering::Greater, _, _) |
            (Ordering::Equal, Ordering::Greater, _) |
            (Ordering::Equal, Ordering::Equal, Ordering::Greater) => Ordering::Greater,
        }
    }
}

pub struct ArangeParser<'input, Endian>
    where Endian: 'input + Endianity
{
    // This struct is never instantiated.
    phantom: PhantomData<&'input Endian>,
}

impl<'input, Endian> LookupParser<'input, Endian> for ArangeParser<'input, Endian>
    where Endian: Endianity
{
    type Header = ArangeHeader;
    type Entry = ArangeEntry;

    /// Parse an arange set header. Returns a tuple of the remaining arange sets, the aranges to be
    /// parsed for this set, and the newly created ArangeHeader struct.
    fn parse_header(input: EndianBuf<Endian>)
                    -> ParseResult<(EndianBuf<Endian>, EndianBuf<Endian>, Rc<Self::Header>)> {
        let (rest, (length, format)) = try!(parse_unit_length(input));
        if length as usize > rest.len() {
            return Err(Error::UnexpectedEof);
        }
        let after_set = rest.range_from(length as usize..);
        let rest = rest.range_to(..length as usize);

        let (rest, version) = try!(parse_u16(rest));
        if version != 2 {
            return Err(Error::UnknownVersion);
        }

        let (rest, offset) = try!(parse_debug_info_offset(rest, format));
        let (rest, address_size) = try!(parse_address_size(rest));
        let (rest, segment_size) = try!(parse_address_size(rest));

        // unit_length + version + offset + address_size + segment_size
        let header_length = match format {
            Format::Dwarf32 => 4 + 2 + 4 + 1 + 1,
            Format::Dwarf64 => 12 + 2 + 8 + 1 + 1,
        };

        // The first tuple following the header in each set begins at an offset that is
        // a multiple of the size of a single tuple (that is, the size of a segment selector
        // plus twice the size of an address).
        let tuple_length = (2 * address_size + segment_size) as usize;
        let padding = if header_length % tuple_length == 0 {
            0
        } else {
            tuple_length - header_length % tuple_length
        };
        if padding > rest.len() {
            return Err(Error::UnexpectedEof);
        }
        let rest = rest.range_from(padding..);

        Ok((after_set,
            rest,
            Rc::new(ArangeHeader {
            format: format,
            length: length,
            version: version,
            offset: offset,
            address_size: address_size,
            segment_size: segment_size,
        })))
    }

    /// Parse a single arange. Return `None` for the null arange, `Some` for an actual arange.
    fn parse_entry(input: EndianBuf<'input, Endian>,
                   header: &Rc<Self::Header>)
                   -> ParseResult<(EndianBuf<'input, Endian>, Option<Self::Entry>)> {
        let address_size = header.address_size;
        let segment_size = header.segment_size; // May be zero!

        let (rest, segment) = if segment_size != 0 {
            try!(parse_address(input, segment_size))
        } else {
            (input, 0)
        };
        let (rest, address) = try!(parse_address(rest, address_size));
        let (rest, length) = try!(parse_address(rest, address_size));

        match (segment, address, length) {
            (0, 0, 0) => Ok((EndianBuf::new(&[]), None)),
            _ => {
                Ok((rest,
                    Some(ArangeEntry {
                    segment: segment,
                    address: address,
                    length: length,
                    header: header.clone(),
                })))
            }
        }
    }
}

/// The `DebugAranges` struct represents the DWARF address range information
/// found in the `.debug_aranges` section.
///
/// Provides:
///
/// * `new(input: EndianBuf<'input, Endian>) -> DebugAranges<'input, Endian>`
///
///   Construct a new `DebugAranges` instance from the data in the `.debug_aranges`
///   section.
///
///   It is the caller's responsibility to read the `.debug_aranges` section and
///   present it as a `&[u8]` slice. That means using some ELF loader on
///   Linux, a Mach-O loader on OSX, etc.
///
///   ```
///   use gimli::{DebugAranges, LittleEndian};
///
///   # let buf = [];
///   # let read_debug_aranges_section = || &buf;
///   let debug_aranges = DebugAranges::<LittleEndian>::new(read_debug_aranges_section());
///   ```
///
/// * `items(&self) -> ArangeEntryIter<'input, Endian>`
///
///   Iterate the aranges in the `.debug_aranges` section.
///
///   ```
///   use gimli::{DebugAranges, LittleEndian};
///
///   # let buf = [];
///   # let read_debug_aranges_section = || &buf;
///   let debug_aranges = DebugAranges::<LittleEndian>::new(read_debug_aranges_section());
///
///   let mut iter = debug_aranges.items();
///   while let Some(arange) = iter.next().unwrap() {
///       println!("arange starts at {}, has length {}", arange.address(), arange.length());
///   }
///   ```
pub type DebugAranges<'input, Endian> = DebugLookup<'input, Endian, ArangeParser<'input, Endian>>;

/// An iterator over the aranges from a .debug_aranges section.
///
/// Provides:
///
/// * `next(self: &mut) -> ParseResult<Option<ArangeEntry>>`
///
///   Advance the iterator and return the next arange.
///
///   Returns the newly parsed arange as `Ok(Some(arange))`. Returns `Ok(None)`
///   when iteration is complete and all aranges have already been parsed and
///   yielded. If an error occurs while parsing the next arange, then this error
///   is returned on all subsequent calls as `Err(e)`.
///
///   Can be [used with
///   `FallibleIterator`](./index.html#using-with-fallibleiterator).
pub type ArangeEntryIter<'input, Endian> = LookupEntryIter<'input,
                                                           Endian,
                                                           ArangeParser<'input, Endian>>;
<commit_msg>arange: add basic tests<commit_after>#![deny(missing_docs)]

use endianity::{Endianity, EndianBuf};
use lookup::{LookupParser, LookupEntryIter, DebugLookup};
use parser::{parse_address_size, parse_debug_info_offset, parse_unit_length, parse_u16,
             parse_address, Error, Format, DebugInfoOffset, ParseResult};
use std::cmp::Ordering;
use std::marker::PhantomData;
use std::rc::Rc;

#[derive(Debug, PartialEq, Eq)]
pub struct ArangeHeader {
    format: Format,
    length: u64,
    version: u16,
    offset: DebugInfoOffset,
    address_size: u8,
    segment_size: u8,
}

/// A single parsed arange.
#[derive(Debug, Clone, Eq)]
pub struct ArangeEntry {
    segment: u64,
    address: u64,
    length: u64,
    header: Rc<ArangeHeader>,
}

impl ArangeEntry {
    /// Return the segment selector of this arange.
    pub fn segment(&self) -> Option<u64> {
        if self.header.segment_size != 0 {
            Some(self.segment)
        } else {
            None
        }
    }

    /// Return the beginning address of this arange.
    pub fn address(&self) -> u64 {
        self.address
    }

    /// Return the length of this arange.
    pub fn length(&self) -> u64 {
        self.length
    }

    /// Return the offset into the .debug_info section for this arange.
    pub fn debug_info_offset(&self) -> DebugInfoOffset {
        self.header.offset
    }
}

impl PartialEq for ArangeEntry {
    fn eq(&self, other: &ArangeEntry) -> bool {
        // The expected comparison, but verify that header matches if everything else does.
        match (self.segment == other.segment,
               self.address == other.address,
               self.length == other.length) {
            (true, true, true) => {
                debug_assert!(self.header == other.header);
                true
            }
            _ => false,
        }
    }
}

impl PartialOrd for ArangeEntry {
    fn partial_cmp(&self, other: &ArangeEntry) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for ArangeEntry {
    fn cmp(&self, other: &ArangeEntry) -> Ordering {
        // The expected comparison, but ignore header.
        match (self.segment.cmp(&other.segment),
               self.address.cmp(&other.address),
               self.length.cmp(&other.length)) {
            (Ordering::Equal, Ordering::Equal, Ordering::Equal) => Ordering::Equal,
            (Ordering::Less, _, _) |
            (Ordering::Equal, Ordering::Less, _) |
            (Ordering::Equal, Ordering::Equal, Ordering::Less) => Ordering::Less,
            (Ordering::Greater, _, _) |
            (Ordering::Equal, Ordering::Greater, _) |
            (Ordering::Equal, Ordering::Equal, Ordering::Greater) => Ordering::Greater,
        }
    }
}

pub struct ArangeParser<'input, Endian>
    where Endian: 'input + Endianity
{
    // This struct is never instantiated.
    phantom: PhantomData<&'input Endian>,
}

impl<'input, Endian> LookupParser<'input, Endian> for ArangeParser<'input, Endian>
    where Endian: Endianity
{
    type Header = ArangeHeader;
    type Entry = ArangeEntry;

    /// Parse an arange set header. Returns a tuple of the remaining arange sets, the aranges to be
    /// parsed for this set, and the newly created ArangeHeader struct.
    fn parse_header(input: EndianBuf<Endian>)
                    -> ParseResult<(EndianBuf<Endian>, EndianBuf<Endian>, Rc<Self::Header>)> {
        let (rest, (length, format)) = try!(parse_unit_length(input));
        if length as usize > rest.len() {
            return Err(Error::UnexpectedEof);
        }
        let after_set = rest.range_from(length as usize..);
        let rest = rest.range_to(..length as usize);

        let (rest, version) = try!(parse_u16(rest));
        if version != 2 {
            return Err(Error::UnknownVersion);
        }

        let (rest, offset) = try!(parse_debug_info_offset(rest, format));
        let (rest, address_size) = try!(parse_address_size(rest));
        let (rest, segment_size) = try!(parse_address_size(rest));

        // unit_length + version + offset + address_size + segment_size
        let header_length = match format {
            Format::Dwarf32 => 4 + 2 + 4 + 1 + 1,
            Format::Dwarf64 => 12 + 2 + 8 + 1 + 1,
        };

        // The first tuple following the header in each set begins at an offset that is
        // a multiple of the size of a single tuple (that is, the size of a segment selector
        // plus twice the size of an address).
        let tuple_length = (2 * address_size + segment_size) as usize;
        let padding = if header_length % tuple_length == 0 {
            0
        } else {
            tuple_length - header_length % tuple_length
        };
        if padding > rest.len() {
            return Err(Error::UnexpectedEof);
        }
        let rest = rest.range_from(padding..);

        Ok((after_set,
            rest,
            Rc::new(ArangeHeader {
            format: format,
            length: length,
            version: version,
            offset: offset,
            address_size: address_size,
            segment_size: segment_size,
        })))
    }

    /// Parse a single arange. Return `None` for the null arange, `Some` for an actual arange.
    fn parse_entry(input: EndianBuf<'input, Endian>,
                   header: &Rc<Self::Header>)
                   -> ParseResult<(EndianBuf<'input, Endian>, Option<Self::Entry>)> {
        let address_size = header.address_size;
        let segment_size = header.segment_size; // May be zero!

        let (rest, segment) = if segment_size != 0 {
            try!(parse_address(input, segment_size))
        } else {
            (input, 0)
        };
        let (rest, address) = try!(parse_address(rest, address_size));
        let (rest, length) = try!(parse_address(rest, address_size));

        match (segment, address, length) {
            (0, 0, 0) => Ok((EndianBuf::new(&[]), None)),
            _ => {
                Ok((rest,
                    Some(ArangeEntry {
                    segment: segment,
                    address: address,
                    length: length,
                    header: header.clone(),
                })))
            }
        }
    }
}

/// The `DebugAranges` struct represents the DWARF address range information
/// found in the `.debug_aranges` section.
///
/// Provides:
///
/// * `new(input: EndianBuf<'input, Endian>) -> DebugAranges<'input, Endian>`
///
///   Construct a new `DebugAranges` instance from the data in the `.debug_aranges`
///   section.
///
///   It is the caller's responsibility to read the `.debug_aranges` section and
///   present it as a `&[u8]` slice. That means using some ELF loader on
///   Linux, a Mach-O loader on OSX, etc.
///
///   ```
///   use gimli::{DebugAranges, LittleEndian};
///
///   # let buf = [];
///   # let read_debug_aranges_section = || &buf;
///   let debug_aranges = DebugAranges::<LittleEndian>::new(read_debug_aranges_section());
///   ```
///
/// * `items(&self) -> ArangeEntryIter<'input, Endian>`
///
///   Iterate the aranges in the `.debug_aranges` section.
///
///   ```
///   use gimli::{DebugAranges, LittleEndian};
///
///   # let buf = [];
///   # let read_debug_aranges_section = || &buf;
///   let debug_aranges = DebugAranges::<LittleEndian>::new(read_debug_aranges_section());
///
///   let mut iter = debug_aranges.items();
///   while let Some(arange) = iter.next().unwrap() {
///       println!("arange starts at {}, has length {}", arange.address(), arange.length());
///   }
///   ```
pub type DebugAranges<'input, Endian> = DebugLookup<'input, Endian, ArangeParser<'input, Endian>>;

/// An iterator over the aranges from a .debug_aranges section.
///
/// Provides:
///
/// * `next(self: &mut) -> ParseResult<Option<ArangeEntry>>`
///
///   Advance the iterator and return the next arange.
///
///   Returns the newly parsed arange as `Ok(Some(arange))`. Returns `Ok(None)`
///   when iteration is complete and all aranges have already been parsed and
///   yielded. If an error occurs while parsing the next arange, then this error
///   is returned on all subsequent calls as `Err(e)`.
///
///   Can be [used with
///   `FallibleIterator`](./index.html#using-with-fallibleiterator).
pub type ArangeEntryIter<'input, Endian> = LookupEntryIter<'input,
                                                           Endian,
                                                           ArangeParser<'input, Endian>>;

#[cfg(test)]
mod tests {
    use super::*;
    use lookup::LookupParser;
    use endianity::{EndianBuf, LittleEndian};
    use parser::{Format, DebugInfoOffset};
    use std::rc::Rc;

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_parse_header_ok() {
        let buf = [
            // 32-bit length = 32.
            0x20, 0x00, 0x00, 0x00,
            // Version.
            0x02, 0x00,
            // Offset.
            0x01, 0x02, 0x03, 0x04,
            // Address size.
            0x08,
            // Segment size.
            0x04,
            // Length to here = 12, tuple length = 20.
            // Padding to tuple length multiple = 4.
            0x10, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,

            // Dummy arange tuple data.
            0x20, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,

            // Dummy next arange.
            0x30, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00,
        ];

        let input = EndianBuf::<LittleEndian>::new(&buf);

        let (rest, tuples, header) = ArangeParser::parse_header(input)
            .expect("should parse header ok");

        assert_eq!(rest, EndianBuf::new(&buf[buf.len() - 16..]));
        assert_eq!(tuples, EndianBuf::new(&buf[buf.len() - 32..buf.len() - 16]));
        assert_eq!(*header,
                   ArangeHeader {
                       format: Format::Dwarf32,
                       length: 0x20,
                       version: 2,
                       offset: DebugInfoOffset(0x04030201),
                       address_size: 8,
                       segment_size: 4,
                   });
    }

    #[test]
    fn test_parse_entry_ok() {
        let header = Rc::new(ArangeHeader {
            format: Format::Dwarf32,
            length: 0,
            version: 2,
            offset: DebugInfoOffset(0),
            address_size: 4,
            segment_size: 0,
        });
        let buf = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09];
        let input = EndianBuf::<LittleEndian>::new(&buf);
        let (rest, entry) = ArangeParser::parse_entry(input, &header)
            .expect("should parse entry ok");
        assert_eq!(rest, EndianBuf::new(&buf[buf.len() - 1..]));
        assert_eq!(entry,
                   Some(ArangeEntry {
                       segment: 0,
                       address: 0x04030201,
                       length: 0x08070605,
                       header: header.clone(),
                   }));
    }

    #[test]
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn test_parse_entry_segment() {
        let header = Rc::new(ArangeHeader {
            format: Format::Dwarf32,
            length: 0,
            version: 2,
            offset: DebugInfoOffset(0),
            address_size: 4,
            segment_size: 8,
        });
        let buf = [
            // Segment.
            0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
            // Address.
            0x01, 0x02, 0x03, 0x04,
            // Length.
            0x05, 0x06, 0x07, 0x08,
            // Next tuple.
            0x09
        ];
        let input = EndianBuf::<LittleEndian>::new(&buf);
        let (rest, entry) = ArangeParser::parse_entry(input, &header)
            .expect("should parse entry ok");
        assert_eq!(rest, EndianBuf::new(&buf[buf.len() - 1..]));
        assert_eq!(entry,
                   Some(ArangeEntry {
                       segment: 0x1817161514131211,
                       address: 0x04030201,
                       length: 0x08070605,
                       header: header.clone(),
                   }));
    }
}
<|endoftext|>


<commit_before>use crate::{generate::*, inner::*, norm::Norm, types::*};
use ndarray::*;

/// Iterative orthogonalizer using modified Gram-Schmit procedure
#[derive(Debug, Clone)]
pub struct MGS<A> {
    /// Dimension of base space
    dimension: usize,
    /// Basis of spanned space
    q: Vec<Array1<A>>,
}

/// Residual vector of orthogonalization
pub type Residual<S> = ArrayBase<S, Ix1>;
/// Residual vector of orthogonalization
pub type Coefficient<A> = Array1<A>;
/// Q-matrix (unitary matrix)
pub type Q<A> = Array2<A>;
/// R-matrix (upper triangle)
pub type R<A> = Array2<A>;

impl<A: Scalar> MGS<A> {
    /// Create empty linear space
    ///
    /// ```rust
    /// # use ndarray_linalg::*;
    /// const N: usize = 5;
    /// let mgs = arnoldi::MGS::<f32>::new(N);
    /// assert_eq!(mgs.dim(), N);
    /// assert_eq!(mgs.len(), 0);
    /// ```
    pub fn new(dimension: usize) -> Self {
        Self {
            dimension,
            q: Vec::new(),
        }
    }

    pub fn dim(&self) -> usize {
        self.dimension
    }

    pub fn len(&self) -> usize {
        self.q.len()
    }

    /// Orthogonalize given vector using current basis
    ///
    /// Panic
    /// -------
    /// - if the size of the input array mismaches to the dimension
    pub fn orthogonalize<S>(&self, mut a: ArrayBase<S, Ix1>) -> (Residual<S>, Coefficient<A>)
    where
        A: Lapack,
        S: DataMut<Elem = A>,
    {
        assert_eq!(a.len(), self.dim());
        let mut coef = Array1::zeros(self.len() + 1);
        for i in 0..self.len() {
            let q = &self.q[i];
            let c = q.inner(&a);
            azip!(mut a, q (q) in { *a = *a - c * q } );
            coef[i] = c;
        }
        let nrm = a.norm_l2();
        coef[self.len()] = A::from_real(nrm);
        (a, coef)
    }

    /// Add new vector if the residual is larger than relative tolerance
    ///
    /// Panic
    /// -------
    /// - if the size of the input array mismaches to the dimension
    ///
    /// ```rust
    /// # use ndarray::*;
    /// # use ndarray_linalg::*;
    /// let mut mgs = arnoldi::MGS::new(3);
    /// let coef = mgs.append(array![1.0, 0.0, 0.0], 1e-9).unwrap();
    /// close_l2(&coef, &array![1.0], 1e-9).unwrap();
    ///
    /// let coef = mgs.append(array![1.0, 1.0, 0.0], 1e-9).unwrap();
    /// close_l2(&coef, &array![1.0, 1.0], 1e-9).unwrap();
    ///
    /// assert!(mgs.append(array![1.0, 1.0, 0.0], 1e-9).is_none());  // Cannot append dependent vector
    /// ```
    pub fn append<S>(&mut self, a: ArrayBase<S, Ix1>, rtol: A::Real) -> Option<Coefficient<A>>
    where
        A: Lapack,
        S: Data<Elem = A>,
    {
        let a = a.into_owned();
        let (mut a, coef) = self.orthogonalize(a);
        let nrm = coef[coef.len() - 1].re();
        if nrm < rtol {
            // Linearly dependent
            return None;
        }
        azip!(mut a in { *a = *a / A::from_real(nrm) });
        self.q.push(a);
        Some(coef)
    }

    /// Get orthogonal basis as Q matrix
    pub fn get_q(&self) -> Q<A> {
        hstack(&self.q).unwrap()
    }
}

pub fn mgs<A, S>(iter: impl Iterator<Item = ArrayBase<S, Ix1>>, dim: usize, rtol: A::Real) -> (Q<A>, R<A>)
where
    A: Scalar + Lapack,
    S: Data<Elem = A>,
{
    let mut ortho = MGS::new(dim);
    let mut coefs = Vec::new();
    for a in iter {
        match ortho.append(a, rtol) {
            Some(coef) => coefs.push(coef),
            None => break,
        }
    }
    let m = coefs.len();
    let mut r = Array2::zeros((m, m));
    for i in 0..m {
        for j in 0..=i {
            r[(j, i)] = coefs[i][j];
        }
    }
    (ortho.get_q(), r)
}
<commit_msg>Fix test case<commit_after>use crate::{generate::*, inner::*, norm::Norm, types::*};
use ndarray::*;

/// Iterative orthogonalizer using modified Gram-Schmit procedure
#[derive(Debug, Clone)]
pub struct MGS<A> {
    /// Dimension of base space
    dimension: usize,
    /// Basis of spanned space
    q: Vec<Array1<A>>,
}

/// Residual vector of orthogonalization
pub type Residual<S> = ArrayBase<S, Ix1>;
/// Residual vector of orthogonalization
pub type Coefficient<A> = Array1<A>;
/// Q-matrix (unitary matrix)
pub type Q<A> = Array2<A>;
/// R-matrix (upper triangle)
pub type R<A> = Array2<A>;

impl<A: Scalar> MGS<A> {
    /// Create empty linear space
    ///
    /// ```rust
    /// # use ndarray_linalg::*;
    /// const N: usize = 5;
    /// let mgs = arnoldi::MGS::<f32>::new(N);
    /// assert_eq!(mgs.dim(), N);
    /// assert_eq!(mgs.len(), 0);
    /// ```
    pub fn new(dimension: usize) -> Self {
        Self {
            dimension,
            q: Vec::new(),
        }
    }

    pub fn dim(&self) -> usize {
        self.dimension
    }

    pub fn len(&self) -> usize {
        self.q.len()
    }

    /// Orthogonalize given vector using current basis
    ///
    /// Panic
    /// -------
    /// - if the size of the input array mismaches to the dimension
    pub fn orthogonalize<S>(&self, mut a: ArrayBase<S, Ix1>) -> (Residual<S>, Coefficient<A>)
    where
        A: Lapack,
        S: DataMut<Elem = A>,
    {
        assert_eq!(a.len(), self.dim());
        let mut coef = Array1::zeros(self.len() + 1);
        for i in 0..self.len() {
            let q = &self.q[i];
            let c = q.inner(&a);
            azip!(mut a, q (q) in { *a = *a - c * q } );
            coef[i] = c;
        }
        let nrm = a.norm_l2();
        coef[self.len()] = A::from_real(nrm);
        (a, coef)
    }

    /// Add new vector if the residual is larger than relative tolerance
    ///
    /// Panic
    /// -------
    /// - if the size of the input array mismaches to the dimension
    ///
    /// ```rust
    /// # use ndarray::*;
    /// # use ndarray_linalg::*;
    /// let mut mgs = arnoldi::MGS::new(3);
    /// let coef = mgs.append(array![1.0, 0.0, 0.0], 1e-9).unwrap();
    /// close_l2(&coef, &array![1.0], 1e-9).unwrap();
    ///
    /// let coef = mgs.append(array![1.0, 1.0, 0.0], 1e-9).unwrap();
    /// close_l2(&coef, &array![1.0, 1.0], 1e-9).unwrap();
    ///
    /// assert!(mgs.append(array![1.0, 2.0, 0.0], 1e-9).is_none());  // Cannot append dependent vector
    /// ```
    pub fn append<S>(&mut self, a: ArrayBase<S, Ix1>, rtol: A::Real) -> Option<Coefficient<A>>
    where
        A: Lapack,
        S: Data<Elem = A>,
    {
        let a = a.into_owned();
        let (mut a, coef) = self.orthogonalize(a);
        let nrm = coef[coef.len() - 1].re();
        if nrm < rtol {
            // Linearly dependent
            return None;
        }
        azip!(mut a in { *a = *a / A::from_real(nrm) });
        self.q.push(a);
        Some(coef)
    }

    /// Get orthogonal basis as Q matrix
    pub fn get_q(&self) -> Q<A> {
        hstack(&self.q).unwrap()
    }
}

pub fn mgs<A, S>(iter: impl Iterator<Item = ArrayBase<S, Ix1>>, dim: usize, rtol: A::Real) -> (Q<A>, R<A>)
where
    A: Scalar + Lapack,
    S: Data<Elem = A>,
{
    let mut ortho = MGS::new(dim);
    let mut coefs = Vec::new();
    for a in iter {
        match ortho.append(a, rtol) {
            Some(coef) => coefs.push(coef),
            None => break,
        }
    }
    let m = coefs.len();
    let mut r = Array2::zeros((m, m));
    for i in 0..m {
        for j in 0..=i {
            r[(j, i)] = coefs[i][j];
        }
    }
    (ortho.get_q(), r)
}
<|endoftext|>