<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 libc;
use std::cmp;
use std::mem;
use std::ptr;
use std::slice;

use super::buffer::*;
use super::memory::*;

#[cfg(windows)]
#[link(name = "msvcrt")]
extern "C" {
    fn _aligned_free(prt: *const u8);
}

/// Buffer builder with zero-copy build method
pub struct Builder<T> {
    data: *mut T,
    len: usize,
    capacity: usize,
}

impl<T> Builder<T> {
    /// Creates a builder with a default capacity
    pub fn new() -> Self {
        Builder::with_capacity(64)
    }

    /// Creates a builder with a fixed capacity
    pub fn with_capacity(capacity: usize) -> Self {
        let sz = mem::size_of::<T>();
        let buffer = allocate_aligned((capacity * sz) as i64).unwrap();
        Builder {
            len: 0,
            capacity,
            data: unsafe { mem::transmute::<*const u8, *mut T>(buffer) },
        }
    }

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

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

    /// Get the internal byte-aligned memory buffer as a mutable slice
    pub fn slice_mut(&self, start: usize, end: usize) -> &mut [T] {
        assert!(start <= end);
        assert!(start < self.len as usize);
        assert!(end <= self.len as usize);
        unsafe {
            slice::from_raw_parts_mut(self.data.offset(start as isize), (end - start) as usize)
        }
    }

    /// Override the length
    pub fn set_len(&mut self, len: usize) {
        self.len = len;
    }

    /// Push a value into the builder, growing the internal buffer as needed
    pub fn push(&mut self, v: T) {
        assert!(!self.data.is_null());
        if self.len == self.capacity {
            let new_capacity = self.capacity;
            self.grow(new_capacity * 2);
        }
        assert!(self.len < self.capacity);
        unsafe {
            *self.data.offset(self.len as isize) = v;
        }
        self.len += 1;
    }

    /// push a slice of type T, growing the internal buffer as needed
    pub fn push_slice(&mut self, slice: &[T]) {
        self.reserve(slice.len());
        let sz = mem::size_of::<T>();
        unsafe {
            libc::memcpy(
                mem::transmute::<*mut T, *mut libc::c_void>(self.data.offset(self.len() as isize)),
                mem::transmute::<*const T, *const libc::c_void>(slice.as_ptr()),
                slice.len() * sz,
            );
        }
        self.len += slice.len();
    }

    /// Reserve memory for n elements of type T
    pub fn reserve(&mut self, n: usize) {
        if self.len + n > self.capacity {
            let new_capacity = cmp::max(self.capacity * 2, n);
            self.grow(new_capacity);
        }
    }

    /// Grow the buffer to the new size n (number of elements of type T)
    fn grow(&mut self, new_capacity: usize) {
        let sz = mem::size_of::<T>();
        unsafe {
            let old_buffer = self.data;
            let new_buffer = allocate_aligned((new_capacity * sz) as i64).unwrap();
            libc::memcpy(
                mem::transmute::<*const u8, *mut libc::c_void>(new_buffer),
                mem::transmute::<*const T, *const libc::c_void>(old_buffer),
                self.len * sz,
            );
            self.capacity = new_capacity;
            self.data = mem::transmute::<*const u8, *mut T>(new_buffer);
            libc::free(mem::transmute::<*mut T, *mut libc::c_void>(old_buffer));
        }
    }

    /// Build a Buffer from the existing memory
    pub fn finish(&mut self) -> Buffer<T> {
        assert!(!self.data.is_null());
        let p = unsafe { mem::transmute::<*mut T, *const T>(self.data) };
        self.data = ptr::null_mut(); // ensure builder cannot be re-used
        Buffer::from_raw_parts(p, self.len as i32)
    }
}

impl<T> Drop for Builder<T> {
    #[cfg(windows)]
    fn drop(&mut self) {
        if !self.data.is_null() {
            unsafe {
                let p = mem::transmute::<*const T, *const u8>(self.data);
                _aligned_free(p);
            }
        }
    }

    #[cfg(not(windows))]
    fn drop(&mut self) {
        if !self.data.is_null() {
            unsafe {
                let p = mem::transmute::<*const T, *mut libc::c_void>(self.data);
                libc::free(p);
            }
        }
    }
}

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

    #[test]
    fn test_builder_i32_empty() {
        let mut b: Builder<i32> = Builder::with_capacity(5);
        let a = b.finish();
        assert_eq!(0, a.len());
    }

    #[test]
    fn test_builder_i32() {
        let mut b: Builder<i32> = Builder::with_capacity(5);
        for i in 0..5 {
            b.push(i);
        }
        let a = b.finish();
        assert_eq!(5, a.len());
        for i in 0..5 {
            assert_eq!(&i, a.get(i as usize));
        }
    }

    #[test]
    fn test_builder_i32_grow_buffer() {
        let mut b: Builder<i32> = Builder::with_capacity(2);
        for i in 0..5 {
            b.push(i);
        }
        let a = b.finish();
        assert_eq!(5, a.len());
        for i in 0..5 {
            assert_eq!(&i, a.get(i as usize));
        }
    }

    #[test]
    fn test_reserve() {
        let mut b: Builder<u8> = Builder::with_capacity(2);
        assert_eq!(2, b.capacity());
        b.reserve(2);
        assert_eq!(2, b.capacity());
        b.reserve(3);
        assert_eq!(4, b.capacity());
    }

    #[test]
    fn test_push_slice() {
        let mut b: Builder<u8> = Builder::new();
        b.push_slice("Hello, ".as_bytes());
        b.push_slice("World!".as_bytes());
        let buffer = b.finish();
        assert_eq!(13, buffer.len());

        let s = String::from_utf8(buffer.iter().collect::<Vec<u8>>()).unwrap();
        assert_eq!("Hello, World!", s);
    }

}
<commit_msg>ARROW-2441: [Rust] Builder<T>::slice_mut assertions are too strict<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 libc;
use std::cmp;
use std::mem;
use std::ptr;
use std::slice;

use super::buffer::*;
use super::memory::*;

#[cfg(windows)]
#[link(name = "msvcrt")]
extern "C" {
    fn _aligned_free(prt: *const u8);
}

/// Buffer builder with zero-copy build method
pub struct Builder<T> {
    data: *mut T,
    len: usize,
    capacity: usize,
}

impl<T> Builder<T> {
    /// Creates a builder with a default capacity
    pub fn new() -> Self {
        Builder::with_capacity(64)
    }

    /// Creates a builder with a fixed capacity
    pub fn with_capacity(capacity: usize) -> Self {
        let sz = mem::size_of::<T>();
        let buffer = allocate_aligned((capacity * sz) as i64).unwrap();
        Builder {
            len: 0,
            capacity,
            data: unsafe { mem::transmute::<*const u8, *mut T>(buffer) },
        }
    }

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

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

    /// Get the internal byte-aligned memory buffer as a mutable slice
    pub fn slice_mut(&self, start: usize, end: usize) -> &mut [T] {
        assert!(start <= end);
        assert!(start < self.capacity as usize);
        assert!(end <= self.capacity as usize);
        unsafe {
            slice::from_raw_parts_mut(self.data.offset(start as isize), (end - start) as usize)
        }
    }

    /// Override the length
    pub fn set_len(&mut self, len: usize) {
        self.len = len;
    }

    /// Push a value into the builder, growing the internal buffer as needed
    pub fn push(&mut self, v: T) {
        assert!(!self.data.is_null());
        if self.len == self.capacity {
            let new_capacity = self.capacity;
            self.grow(new_capacity * 2);
        }
        assert!(self.len < self.capacity);
        unsafe {
            *self.data.offset(self.len as isize) = v;
        }
        self.len += 1;
    }

    /// push a slice of type T, growing the internal buffer as needed
    pub fn push_slice(&mut self, slice: &[T]) {
        self.reserve(slice.len());
        let sz = mem::size_of::<T>();
        unsafe {
            libc::memcpy(
                mem::transmute::<*mut T, *mut libc::c_void>(self.data.offset(self.len() as isize)),
                mem::transmute::<*const T, *const libc::c_void>(slice.as_ptr()),
                slice.len() * sz,
            );
        }
        self.len += slice.len();
    }

    /// Reserve memory for n elements of type T
    pub fn reserve(&mut self, n: usize) {
        if self.len + n > self.capacity {
            let new_capacity = cmp::max(self.capacity * 2, n);
            self.grow(new_capacity);
        }
    }

    /// Grow the buffer to the new size n (number of elements of type T)
    fn grow(&mut self, new_capacity: usize) {
        let sz = mem::size_of::<T>();
        unsafe {
            let old_buffer = self.data;
            let new_buffer = allocate_aligned((new_capacity * sz) as i64).unwrap();
            libc::memcpy(
                mem::transmute::<*const u8, *mut libc::c_void>(new_buffer),
                mem::transmute::<*const T, *const libc::c_void>(old_buffer),
                self.len * sz,
            );
            self.capacity = new_capacity;
            self.data = mem::transmute::<*const u8, *mut T>(new_buffer);
            libc::free(mem::transmute::<*mut T, *mut libc::c_void>(old_buffer));
        }
    }

    /// Build a Buffer from the existing memory
    pub fn finish(&mut self) -> Buffer<T> {
        assert!(!self.data.is_null());
        let p = unsafe { mem::transmute::<*mut T, *const T>(self.data) };
        self.data = ptr::null_mut(); // ensure builder cannot be re-used
        Buffer::from_raw_parts(p, self.len as i32)
    }
}

impl<T> Drop for Builder<T> {
    #[cfg(windows)]
    fn drop(&mut self) {
        if !self.data.is_null() {
            unsafe {
                let p = mem::transmute::<*const T, *const u8>(self.data);
                _aligned_free(p);
            }
        }
    }

    #[cfg(not(windows))]
    fn drop(&mut self) {
        if !self.data.is_null() {
            unsafe {
                let p = mem::transmute::<*const T, *mut libc::c_void>(self.data);
                libc::free(p);
            }
        }
    }
}

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

    #[test]
    fn test_builder_i32_empty() {
        let mut b: Builder<i32> = Builder::with_capacity(5);
        let a = b.finish();
        assert_eq!(0, a.len());
    }

    #[test]
    fn test_builder_i32() {
        let mut b: Builder<i32> = Builder::with_capacity(5);
        for i in 0..5 {
            b.push(i);
        }
        let a = b.finish();
        assert_eq!(5, a.len());
        for i in 0..5 {
            assert_eq!(&i, a.get(i as usize));
        }
    }

    #[test]
    fn test_builder_i32_grow_buffer() {
        let mut b: Builder<i32> = Builder::with_capacity(2);
        for i in 0..5 {
            b.push(i);
        }
        let a = b.finish();
        assert_eq!(5, a.len());
        for i in 0..5 {
            assert_eq!(&i, a.get(i as usize));
        }
    }

    #[test]
    fn test_reserve() {
        let mut b: Builder<u8> = Builder::with_capacity(2);
        assert_eq!(2, b.capacity());
        b.reserve(2);
        assert_eq!(2, b.capacity());
        b.reserve(3);
        assert_eq!(4, b.capacity());
    }

    #[test]
    fn test_push_slice() {
        let mut b: Builder<u8> = Builder::new();
        b.push_slice("Hello, ".as_bytes());
        b.push_slice("World!".as_bytes());
        let buffer = b.finish();
        assert_eq!(13, buffer.len());

        let s = String::from_utf8(buffer.iter().collect::<Vec<u8>>()).unwrap();
        assert_eq!("Hello, World!", s);
    }

}
<|endoftext|>


<commit_before>use gtk::prelude::*;
use gtk::{TextTag, TextView};
use sounding_analysis::{partition_cape, Analysis};

use app::{AppContext, AppContextPointer};
use errors::SondeError;

macro_rules! make_default_tag {
    ($tb:ident) => {
        if let Some(tag_table) = $tb.get_tag_table() {
            let tag = TextTag::new("default");

            tag.set_property_font(Some("courier bold 12"));

            let success = tag_table.add(&tag);
            debug_assert!(success, "Failed to add tag to text tag table");
        }
    };
}

macro_rules! set_text {
    ($tb:ident, $txt:expr) => {
        $tb.set_text($txt);
        let start = $tb.get_start_iter();
        let end = $tb.get_end_iter();
        $tb.apply_tag_by_name("default", &start, &end);
    };
}

const TEXT_AREA_ID: &str = "indexes_text_area";

pub fn set_up_indexes_area(acp: &AppContextPointer) -> Result<(), SondeError> {
    let text_area: TextView = acp.fetch_widget(TEXT_AREA_ID)?;

    if let Some(tb) = text_area.get_buffer() {
        make_default_tag!(tb);
        set_text!(tb, "No data loaded");

        if let Some(tag_table) = tb.get_tag_table() {
            let red_tag = TextTag::new("red");
            let yellow_tag = TextTag::new("yellow");

            let mut success = tag_table.add(&red_tag);
            debug_assert!(success, "Failed to add red tag");
            success = tag_table.add(&yellow_tag);
            debug_assert!(success, "Failed to add yellow tag");
        }

        tb.create_mark("scroll_mark", &tb.get_start_iter(), true);

        Ok(())
    } else {
        Err(SondeError::TextBufferLoadError(TEXT_AREA_ID))
    }
}

pub fn update_indexes_area(ac: &AppContext) {
    let text_area: TextView = if let Ok(ta) = ac.fetch_widget(TEXT_AREA_ID) {
        ta
    } else {
        return;
    };

    if !text_area.is_visible() {
        return;
    }

    if let Some(tb) = text_area.get_buffer() {
        if let Some(ref anal) = ac.get_sounding_for_display() {
            let text = &mut String::with_capacity(4096);

            push_profile_indexes(text, anal);
            push_parcel_indexes(text, anal);
            push_fire_indexes(text, anal);

            set_text!(tb, &text);
        }
    }
}

macro_rules! push_profile_index {
    ($anal: expr, $buf:ident, $name:expr, $selector:expr, $format:expr, $empty_val:expr) => {
        $buf.push_str($name);
        $anal
            .get_profile_index($selector)
            .and_then(|val| {
                $buf.push_str(&format!($format, val));
                Some(())
            }).or_else(|| {
                $buf.push_str($empty_val);
                Some(())
            });
        $buf.push('\n');
    };
}

#[inline]
#[rustfmt::skip]
fn push_profile_indexes(buffer: &mut String, anal: &Analysis){
    use sounding_analysis::ProfileIndex::*;
    let empty_val = "    -    ";

    buffer.push('\n');

    push_profile_index!(anal, buffer, "SWeT        ", SWeT,        "{:>10.0}",          empty_val);
    push_profile_index!(anal, buffer, "K           ", K,           "{:>10.0}",          empty_val);
    push_profile_index!(anal, buffer, "Total Totals", TotalTotals, "{:>10.0}",          empty_val);
    push_profile_index!(anal, buffer, "DCAPE       ", DCAPE,       "{:>5.0} J/kg",      empty_val);
    push_profile_index!(anal, buffer, "PWAT        ", PWAT,        "{:>7.0} mm",        empty_val);
    push_profile_index!(anal, buffer, "Downrush T  ", DownrushT,   "{:>7.0} \u{00b0}C", empty_val);
    push_profile_index!(anal, buffer, "Convective T", ConvectiveT, "{:>7.0} \u{00b0}C", empty_val);
}

#[inline]
#[rustfmt::skip]
fn push_parcel_indexes(buffer: &mut String, anal: &Analysis) {
    use sounding_analysis::ParcelIndex::*;

    buffer.push('\n');

    macro_rules! push_var {
        ($buf:ident, $opt_anal:ident, $selector:ident, $fmt:expr,$empty:expr) => {
            $opt_anal.and_then(|anal| {
                anal.get_index($selector).and_then(|val|{
                    $buf.push_str(&format!($fmt, val));
                    Some(())
                }).or_else(||{
                    $buf.push_str($empty);
                    Some(())
                });
                Some(())
            });
        }
    }

    macro_rules! parcel_index_row {
        ($buf:ident, $pcl_name:expr, $opt_pcl_anal:ident, $empty:expr) => {
            $buf.push_str($pcl_name);

            push_var!($buf, $opt_pcl_anal, CAPE,        " {:>5.0}", $empty);
            push_var!($buf, $opt_pcl_anal, CIN,         " {:>5.0}", $empty);
            push_var!($buf, $opt_pcl_anal, NCAPE,       " {:>5.2}", $empty);
            push_var!($buf, $opt_pcl_anal, CAPEHail,    " {:>5.0}", $empty);
            push_var!($buf, $opt_pcl_anal, LI,          " {:>5.1}", $empty);

            $buf.push('\n');
        }
    }

    macro_rules! parcel_level_row {
        ($buf:ident, $pcl_name:expr, $opt_pcl_anal:ident, $empty:expr) => {
            $buf.push_str($pcl_name);

            push_var!($buf, $opt_pcl_anal, LCLPressure,   " {:>5.0}", $empty);
            push_var!($buf, $opt_pcl_anal, LCLHeightAGL,  " {:>6.0}", $empty);
            push_var!($buf, $opt_pcl_anal, LFC,           " {:>5.0}", $empty);
            push_var!($buf, $opt_pcl_anal, ELPressure,    " {:>5.0}", $empty);
            push_var!($buf, $opt_pcl_anal, ELHeightASL,   " {:>6.0}", $empty);
            push_var!($buf, $opt_pcl_anal, ELTemperature, " {:>5.0}", $empty);

            $buf.push('\n');
        }
    }

    let sfc = anal.get_surface_parcel_analysis();
    let ml = anal.get_mixed_layer_parcel_analysis();
    let mu = anal.get_most_unstable_parcel_analysis();
    let con = anal.get_convective_parcel_analysis();

    let empty = "     -";
    buffer.push_str("Parcel          CAPE   CIN NCAPE  Hail    LI\n");
    buffer.push_str("                J/Kg  J/Kg        CAPE     C\n");
    buffer.push_str("--------------------------------------------\n");
    parcel_index_row!(buffer, "Surface       ", sfc, empty);
    parcel_index_row!(buffer, "Mixed Layer   ", ml,  empty);
    parcel_index_row!(buffer, "Most Unstable ", mu,  empty);
    parcel_index_row!(buffer, "Convective    ", con, empty);
    buffer.push('\n');
    buffer.push_str("Parcel           LCL    LCL   LFC    EL     EL    EL\n");
    buffer.push_str("                 hPa  m AGL   hPa   hPa  m ASL     C\n");
    buffer.push_str("----------------------------------------------------\n");
    parcel_level_row!(buffer, "Surface       ", sfc, empty);
    parcel_level_row!(buffer, "Mixed Layer   ", ml,  empty);
    parcel_level_row!(buffer, "Most Unstable ", mu,  empty);
    parcel_level_row!(buffer, "Convective    ", con, empty);
}

#[inline]
#[rustfmt::skip]
fn push_fire_indexes(buffer: &mut String, anal: &Analysis) {
    use sounding_analysis::ProfileIndex::*;

    macro_rules! push_fire_index {
        ($buf:ident, $label:expr, $anal:ident, $selector:ident, $fmt:expr, $empty:expr) => {
            $buf.push_str($label);
            if let Some(val) = $anal.get_profile_index($selector) {
                $buf.push_str(&format!($fmt, val));
            } else {
                $buf.push_str($empty);
            }
        };
    }

    buffer.push('\n');

    buffer.push_str("Haines   Low   Mid  High\n");
    buffer.push_str("       ");

    let empty = "  -   ";
    for &hns in [HainesLow, HainesMid, HainesHigh].into_iter() {
        if let Some(val) = anal.get_profile_index(hns) {
            buffer.push_str(&format!("{:>5.0} ", val));
        } else {
            buffer.push_str(empty);
        }
    }
    buffer.push_str("\n\n");

    let empty = " - \n";

    push_fire_index!(buffer, "HDW         ", anal, Hdw,               "{:>7.0}\n", empty);
    push_fire_index!(buffer, "Conv. T def.", anal, ConvectiveDeficit, "{:>4.1} \u{00b0}C\n", empty);
    push_fire_index!(buffer, "CAPE ratio  ", anal, CapeRatio,         "{:>7.2}\n", empty);

    if let Some(parcel_anal) = anal.get_convective_parcel_analysis(){
        if let Ok((dry, wet)) = partition_cape(parcel_anal){
            buffer.push_str(&format!("\nDry cape: {:>7.2}  Wet cape: {:>7.2}\n", dry, wet));
        }
    }
}
<commit_msg>Cleaned up indexes display.<commit_after>use gtk::prelude::*;
use gtk::{TextTag, TextView};
use sounding_analysis::{partition_cape, Analysis};

use app::{AppContext, AppContextPointer};
use errors::SondeError;

macro_rules! make_default_tag {
    ($tb:ident) => {
        if let Some(tag_table) = $tb.get_tag_table() {
            let tag = TextTag::new("default");

            tag.set_property_font(Some("courier bold 12"));

            let success = tag_table.add(&tag);
            debug_assert!(success, "Failed to add tag to text tag table");
        }
    };
}

macro_rules! set_text {
    ($tb:ident, $txt:expr) => {
        $tb.set_text($txt);
        let start = $tb.get_start_iter();
        let end = $tb.get_end_iter();
        $tb.apply_tag_by_name("default", &start, &end);
    };
}

const TEXT_AREA_ID: &str = "indexes_text_area";

pub fn set_up_indexes_area(acp: &AppContextPointer) -> Result<(), SondeError> {
    let text_area: TextView = acp.fetch_widget(TEXT_AREA_ID)?;

    if let Some(tb) = text_area.get_buffer() {
        make_default_tag!(tb);
        set_text!(tb, "No data loaded");

        if let Some(tag_table) = tb.get_tag_table() {
            let red_tag = TextTag::new("red");
            let yellow_tag = TextTag::new("yellow");

            let mut success = tag_table.add(&red_tag);
            debug_assert!(success, "Failed to add red tag");
            success = tag_table.add(&yellow_tag);
            debug_assert!(success, "Failed to add yellow tag");
        }

        tb.create_mark("scroll_mark", &tb.get_start_iter(), true);

        Ok(())
    } else {
        Err(SondeError::TextBufferLoadError(TEXT_AREA_ID))
    }
}

pub fn update_indexes_area(ac: &AppContext) {
    let text_area: TextView = if let Ok(ta) = ac.fetch_widget(TEXT_AREA_ID) {
        ta
    } else {
        return;
    };

    if !text_area.is_visible() {
        return;
    }

    if let Some(tb) = text_area.get_buffer() {
        if let Some(ref anal) = ac.get_sounding_for_display() {
            let text = &mut String::with_capacity(4096);

            push_header(text, ac.get_source_description(), anal);
            push_profile_indexes(text, anal);
            push_parcel_indexes(text, anal);
            push_fire_indexes(text, anal);

            set_text!(tb, &text);
        }
    }
}

#[inline]
fn push_header(buffer: &mut String, source_desc: Option<String>, anal: &Analysis) {
    if let Some(desc) = source_desc {
        buffer.push_str(&desc);
        buffer.push('\n');
    }

    if let Some(vt) = anal.sounding().get_valid_time() {
        buffer.push_str(&format!("     Valid: {}Z\n", vt));
    }

    let station_info = anal.sounding().get_station_info();
    if let Some((lat, lon)) = station_info.location() {
        buffer.push_str(&format!("(lat, lon): ({:.6},{:.6})\n", lat, lon));
    }
    if let Some(elev_m) = station_info.elevation().into_option() {
        buffer.push_str(&format!(
            " Elevation: {:.0}m ({:.0}ft)\n",
            elev_m,
            elev_m * 3.28084
        ));
    }
}

macro_rules! push_profile_index {
    ($anal: expr, $buf:ident, $name:expr, $selector:expr, $format:expr, $empty_val:expr) => {
        $buf.push_str($name);
        $anal
            .get_profile_index($selector)
            .and_then(|val| {
                $buf.push_str(&format!($format, val));
                Some(())
            }).or_else(|| {
                $buf.push_str($empty_val);
                Some(())
            });
        $buf.push('\n');
    };
}

#[inline]
#[rustfmt::skip]
fn push_profile_indexes(buffer: &mut String, anal: &Analysis){
    use sounding_analysis::ProfileIndex::*;
    let empty_val = "    -    ";

    buffer.push('\n');
    buffer.push('\n');

    buffer.push_str("Index        Value\n");
    buffer.push_str("-----------------------\n");
    push_profile_index!(anal, buffer, "SWeT         ", SWeT,        "{:>10.0}",          empty_val);
    push_profile_index!(anal, buffer, "K            ", K,           "{:>7.0} \u{00b0}C", empty_val);
    push_profile_index!(anal, buffer, "Total Totals ", TotalTotals, "{:>10.0}",          empty_val);
    push_profile_index!(anal, buffer, "DCAPE        ", DCAPE,       "{:>5.0} J/kg",      empty_val);
    push_profile_index!(anal, buffer, "PWAT         ", PWAT,        "{:>7.0} mm",        empty_val);
    push_profile_index!(anal, buffer, "Downrush T   ", DownrushT,   "{:>7.0} \u{00b0}C", empty_val);
    push_profile_index!(anal, buffer, "Convective T ", ConvectiveT, "{:>7.0} \u{00b0}C", empty_val);
}

#[inline]
#[rustfmt::skip]
fn push_parcel_indexes(buffer: &mut String, anal: &Analysis) {
    use sounding_analysis::ParcelIndex::*;

    buffer.push('\n');
    buffer.push('\n');

    macro_rules! push_var {
        ($buf:ident, $opt_anal:ident, $selector:ident, $fmt:expr,$empty:expr) => {
            $opt_anal.and_then(|anal| {
                anal.get_index($selector).and_then(|val|{
                    $buf.push_str(&format!($fmt, val));
                    Some(())
                }).or_else(||{
                    $buf.push_str($empty);
                    Some(())
                });
                Some(())
            });
        }
    }

    macro_rules! parcel_index_row {
        ($buf:ident, $pcl_name:expr, $opt_pcl_anal:ident, $empty:expr) => {
            $buf.push_str($pcl_name);

            push_var!($buf, $opt_pcl_anal, CAPE,        " {:>5.0}", $empty);
            push_var!($buf, $opt_pcl_anal, CIN,         " {:>5.0}", $empty);
            push_var!($buf, $opt_pcl_anal, NCAPE,       " {:>5.2}", $empty);
            push_var!($buf, $opt_pcl_anal, CAPEHail,    " {:>5.0}", $empty);
            push_var!($buf, $opt_pcl_anal, LI,          " {:>5.1}", $empty);

            $buf.push('\n');
        }
    }

    macro_rules! parcel_level_row {
        ($buf:ident, $pcl_name:expr, $opt_pcl_anal:ident, $empty:expr) => {
            $buf.push_str($pcl_name);

            push_var!($buf, $opt_pcl_anal, LCLPressure,   " {:>5.0}", $empty);
            push_var!($buf, $opt_pcl_anal, LCLHeightAGL,  " {:>6.0}", $empty);
            push_var!($buf, $opt_pcl_anal, LFC,           " {:>5.0}", $empty);
            push_var!($buf, $opt_pcl_anal, ELPressure,    " {:>5.0}", $empty);
            push_var!($buf, $opt_pcl_anal, ELHeightASL,   " {:>6.0}", $empty);
            push_var!($buf, $opt_pcl_anal, ELTemperature, " {:>5.0}", $empty);

            $buf.push('\n');
        }
    }

    let sfc = anal.get_surface_parcel_analysis();
    let ml = anal.get_mixed_layer_parcel_analysis();
    let mu = anal.get_most_unstable_parcel_analysis();
    let con = anal.get_convective_parcel_analysis();

    let empty = "     -";
    buffer.push_str("Parcel          CAPE   CIN NCAPE  Hail    LI\n");
    buffer.push_str("                J/Kg  J/Kg        CAPE     C\n");
    buffer.push_str("--------------------------------------------\n");
    parcel_index_row!(buffer, "Surface       ", sfc, empty);
    parcel_index_row!(buffer, "Mixed Layer   ", ml,  empty);
    parcel_index_row!(buffer, "Most Unstable ", mu,  empty);
    parcel_index_row!(buffer, "Convective    ", con, empty);
    buffer.push('\n');
    buffer.push_str("Parcel           LCL    LCL   LFC    EL     EL    EL\n");
    buffer.push_str("                 hPa  m AGL   hPa   hPa  m ASL     C\n");
    buffer.push_str("----------------------------------------------------\n");
    parcel_level_row!(buffer, "Surface       ", sfc, empty);
    parcel_level_row!(buffer, "Mixed Layer   ", ml,  empty);
    parcel_level_row!(buffer, "Most Unstable ", mu,  empty);
    parcel_level_row!(buffer, "Convective    ", con, empty);
}

#[inline]
#[rustfmt::skip]
fn push_fire_indexes(buffer: &mut String, anal: &Analysis) {
    use sounding_analysis::ProfileIndex::*;

    macro_rules! push_fire_index {
        ($buf:ident, $label:expr, $anal:ident, $selector:ident, $fmt:expr, $empty:expr) => {
            $buf.push_str($label);
            if let Some(val) = $anal.get_profile_index($selector) {
                $buf.push_str(&format!($fmt, val));
            } else {
                $buf.push_str($empty);
            }
        };
    }

    buffer.push('\n');
    buffer.push('\n');
    buffer.push_str("Fire Weather\n");
    buffer.push_str("------------------------\n\n");

    buffer.push_str("Haines   Low   Mid  High\n");
    buffer.push_str("       ");

    let empty = "  -   ";
    for &hns in [HainesLow, HainesMid, HainesHigh].into_iter() {
        if let Some(val) = anal.get_profile_index(hns) {
            buffer.push_str(&format!("{:>5.0} ", val));
        } else {
            buffer.push_str(empty);
        }
    }
    buffer.push('\n');
    push_fire_index!(buffer, "HDW         ", anal, Hdw, "{:>12.0}\n\n", empty);

    let empty = " - \n";

    buffer.push_str("Experimental\n");
    buffer.push_str("------------------------\n\n");
    push_fire_index!(buffer, "Conv. T def.", anal, ConvectiveDeficit, "{:>9.1} \u{00b0}C\n", empty);
    push_fire_index!(buffer, "CAPE ratio  ", anal, CapeRatio,         "{:>12.2}\n", empty);

    if let Some(parcel_anal) = anal.get_convective_parcel_analysis(){
        if let Ok((dry, wet)) = partition_cape(parcel_anal){
            buffer.push_str(&format!("Dry cape    {:>7.0} J/kg\nWet cape    {:>7.0} J/kg\n", dry, wet));
        }
    }
}
<|endoftext|>


<commit_before>//! Power Management Unit (PMU)
//!
//! The Power Management Unit (PMU) controls the chip's power states and clock
//! power, as well as allows the chip to interface with peripherals at different
//! voltage levels.
//!
//! There are three types of power domains:
//!
//!   1. VDDIOMR:
//!
//!     * Always-on main I/O voltage supply domain necessary for the running the
//!       core.
//!     * Nominal 3.3V
//!
//!   2. VDDIOA & VDDIOB:
//!
//!     * I/O voltage supply domains for external peripherals.
//!
//!     * Can be shut down at any moment (not critical for core functions).
//!
//!     * Designed for 1.8-3.6V
//!
//!   3. VDDIOF:
//!
//!     * I/O voltage supply domain for flash memory.
//!
//!     * Designed for 1.8-3.6V
//!

use common::volatile_cell::VolatileCell;
use core::mem::transmute;

/// Registers for the Power Management Unit (PMU)
// Non-public fields prefixed with "_" mark unused registers
#[repr(C, packed)]
pub struct PMURegisters {
    _reset: VolatileCell<u32>,
    _set_reset: VolatileCell<u32>,

    /// Clear register for the reset source
    pub clear_reset: VolatileCell<u32>,

    /// Status for source of last reset event
    ///
    /// Bits 0-7 correspond to:
    ///
    /// | bit | Description                                       |
    /// | --- | :------------------------------------------------ |
    /// | 0   | Power on reset                                    |
    /// | 1   | Low power exit                                    |
    /// | 2   | Watchdog reset                                    |
    /// | 3   | Lockup reset                                      |
    /// | 4   | SYSRESET                                          |
    /// | 5   | Software initiated reset through PMU_GLOBAL_RESET |
    /// | 6   | Fast burnout circuit                              |
    /// | 7   | Security breach reset                             |
    ///
    pub reset_source: VolatileCell<u32>,

    /// Global chip reset
    ///
    /// Initiates a reset of the system similar to toggling the external reset
    /// pin. To initiate a reset, write the key 0x7041776 to this register.
    pub global_reset: VolatileCell<u32>,

    pub low_power_disable: VolatileCell<u32>,

    pub low_power_bypass: VolatileCell<u32>,

    pub low_power_bypass_value: VolatileCell<u32>,

    pub set_wakeup_interrupt_controller: VolatileCell<u32>,

    pub clear_wakeup_interrupt_controller: VolatileCell<u32>,

    /// Value of the system vector table offset
    pub sysvtor: VolatileCell<u32>,

    /// Enable PMU to gate some clocks when processor is sleeping
    pub nap_enable: VolatileCell<u32>,

    _pmu_sw_pdb: VolatileCell<u32>,
    _pmu_sw_pdb_secure: VolatileCell<u32>,
    _pmu_vref: VolatileCell<u32>,
    _xtl_osc_bypass: VolatileCell<u32>,
    _flash_tm0_test_en_bypass: VolatileCell<u32>,

    /// Battery level indicator
    ///
    /// When non-zero, the voltage level is higher than specified in the vref
    /// register's BATMON field.
    pub battery_level_ok: VolatileCell<u32>,

    _b_reg_dig_ctrl: VolatileCell<u32>,
    _exitpd_mask: VolatileCell<u32>,
    _exitpd_src: VolatileCell<u32>,
    _exitpd_mon: VolatileCell<u32>,
    _osc_ctrl: VolatileCell<u32>,

    /// Turn on clocks for memory
    ///
    /// Bits 0-6 correspond to memory banks 0-6, respectively.
    pub memory_clk_set: VolatileCell<u32>,

    /// Turn off clocks for memory
    ///
    /// Bits 0-6 correspond to memory banks 0-6, respectively.
    pub memory_clk_clear: VolatileCell<u32>,

    /// Enable peripheral clocks (bank 0).
    ///
    /// Each bit corresponds to a different peripheral clock.
    pub peripheral_clocks0_enable: VolatileCell<u32>,

    /// Disable peripheral clocks (bank 0).
    ///
    /// Each bit corresponds to a different peripheral clock.
    pub peripheral_clocks0_disable: VolatileCell<u32>,

    /// Enable peripheral clocks (bank 1).
    ///
    /// Each bit corresponds to a different peripheral clock.
    pub peripheral_clocks1_enable: VolatileCell<u32>,

    /// Disable peripheral clocks (bank 1).
    ///
    /// Each bit corresponds to a different peripheral clock.
    pub peripheral_clocks1_disable: VolatileCell<u32>,
}

const PMU_BASE: isize = 0x40000000;

static mut PMU: *mut PMURegisters = PMU_BASE as *mut PMURegisters;

#[derive(Clone,Copy)]
pub enum PeripheralClock0 {
    Camo0,
    Crpyto0,
    Dma0,
    Flash0,
    Fuse0,
    GlobalSec,
    GlobalSecTimer,
    GlobalSecHs,
    Gpio0,
    Gpio1,
    I2C0,
    I2C1,
    I2CS0,
    KeyMgr0,
    PeriAPB0,
    PeriAPB1,
    PeriAPB2,
    PeriAPB2Timer,
    PeriAPB3,
    PeriAPB3Timer,
    PeriAPB3HS,
    PinMux,
    Pmu,
    RBox0,
    Rdd0,
    Rtc0,
    Rtc0Timer,
    Spi0Hs,
    Spi1Hs,
    Sps0,
    Sps0TimerHs,
    Swdp0,
    Temp0
}

#[derive(Clone,Copy)]
pub enum PeripheralClock1 {
    TimeHs0Timer,
    TimeHs1Timer,
    TimeLs0,
    TimeUs0Timer,
    Trng0,
    Uart0Timer,
    Uart1Timer,
    Uart2Timer,
    Usb0,
    Usb0TimerHs,
    Volt0,
    Watchdog0,
    Xo0,
    Xo0Timer,
    PeripheralMasterMatrix,
    PeripheralMatrix
}

#[derive(Clone,Copy)]
pub enum PeripheralClock {
    Bank0(PeripheralClock0),
    Bank1(PeripheralClock1)
}

/// Wrapper struct around `PeripheralClock` that can only be created by.
/// trusted code.
#[derive(Clone,Copy)]
pub struct Clock {
    // It's important that this field is private!
    clock: PeripheralClock
}

impl Clock {
    pub unsafe fn new(clock: PeripheralClock) -> Clock {
        Clock { clock: clock }
    }

    pub fn enable(&self) {
        let pmu: &mut PMURegisters = unsafe { transmute(PMU) };
        match self.clock {
            PeripheralClock::Bank0(clock) => {
                pmu.peripheral_clocks0_enable.set(1 << (clock as u32));
            },
            PeripheralClock::Bank1(clock) => {
                pmu.peripheral_clocks1_enable.set(1 << (clock as u32));
            }
        }
    }

    pub fn disable(&self) {
        let pmu: &mut PMURegisters = unsafe { transmute(PMU) };
        match self.clock {
            PeripheralClock::Bank0(clock) => {
                pmu.peripheral_clocks0_disable.set(1 << (clock as u32));
            },
            PeripheralClock::Bank1(clock) => {
                pmu.peripheral_clocks1_disable.set(1 << (clock as u32));
            }
        }
    }
}

<commit_msg>Clock::new can be const<commit_after>//! Power Management Unit (PMU)
//!
//! The Power Management Unit (PMU) controls the chip's power states and clock
//! power, as well as allows the chip to interface with peripherals at different
//! voltage levels.
//!
//! There are three types of power domains:
//!
//!   1. VDDIOMR:
//!
//!     * Always-on main I/O voltage supply domain necessary for the running the
//!       core.
//!     * Nominal 3.3V
//!
//!   2. VDDIOA & VDDIOB:
//!
//!     * I/O voltage supply domains for external peripherals.
//!
//!     * Can be shut down at any moment (not critical for core functions).
//!
//!     * Designed for 1.8-3.6V
//!
//!   3. VDDIOF:
//!
//!     * I/O voltage supply domain for flash memory.
//!
//!     * Designed for 1.8-3.6V
//!

use common::volatile_cell::VolatileCell;
use core::mem::transmute;

/// Registers for the Power Management Unit (PMU)
// Non-public fields prefixed with "_" mark unused registers
#[repr(C, packed)]
pub struct PMURegisters {
    _reset: VolatileCell<u32>,
    _set_reset: VolatileCell<u32>,

    /// Clear register for the reset source
    pub clear_reset: VolatileCell<u32>,

    /// Status for source of last reset event
    ///
    /// Bits 0-7 correspond to:
    ///
    /// | bit | Description                                       |
    /// | --- | :------------------------------------------------ |
    /// | 0   | Power on reset                                    |
    /// | 1   | Low power exit                                    |
    /// | 2   | Watchdog reset                                    |
    /// | 3   | Lockup reset                                      |
    /// | 4   | SYSRESET                                          |
    /// | 5   | Software initiated reset through PMU_GLOBAL_RESET |
    /// | 6   | Fast burnout circuit                              |
    /// | 7   | Security breach reset                             |
    ///
    pub reset_source: VolatileCell<u32>,

    /// Global chip reset
    ///
    /// Initiates a reset of the system similar to toggling the external reset
    /// pin. To initiate a reset, write the key 0x7041776 to this register.
    pub global_reset: VolatileCell<u32>,

    pub low_power_disable: VolatileCell<u32>,

    pub low_power_bypass: VolatileCell<u32>,

    pub low_power_bypass_value: VolatileCell<u32>,

    pub set_wakeup_interrupt_controller: VolatileCell<u32>,

    pub clear_wakeup_interrupt_controller: VolatileCell<u32>,

    /// Value of the system vector table offset
    pub sysvtor: VolatileCell<u32>,

    /// Enable PMU to gate some clocks when processor is sleeping
    pub nap_enable: VolatileCell<u32>,

    _pmu_sw_pdb: VolatileCell<u32>,
    _pmu_sw_pdb_secure: VolatileCell<u32>,
    _pmu_vref: VolatileCell<u32>,
    _xtl_osc_bypass: VolatileCell<u32>,
    _flash_tm0_test_en_bypass: VolatileCell<u32>,

    /// Battery level indicator
    ///
    /// When non-zero, the voltage level is higher than specified in the vref
    /// register's BATMON field.
    pub battery_level_ok: VolatileCell<u32>,

    _b_reg_dig_ctrl: VolatileCell<u32>,
    _exitpd_mask: VolatileCell<u32>,
    _exitpd_src: VolatileCell<u32>,
    _exitpd_mon: VolatileCell<u32>,
    _osc_ctrl: VolatileCell<u32>,

    /// Turn on clocks for memory
    ///
    /// Bits 0-6 correspond to memory banks 0-6, respectively.
    pub memory_clk_set: VolatileCell<u32>,

    /// Turn off clocks for memory
    ///
    /// Bits 0-6 correspond to memory banks 0-6, respectively.
    pub memory_clk_clear: VolatileCell<u32>,

    /// Enable peripheral clocks (bank 0).
    ///
    /// Each bit corresponds to a different peripheral clock.
    pub peripheral_clocks0_enable: VolatileCell<u32>,

    /// Disable peripheral clocks (bank 0).
    ///
    /// Each bit corresponds to a different peripheral clock.
    pub peripheral_clocks0_disable: VolatileCell<u32>,

    /// Enable peripheral clocks (bank 1).
    ///
    /// Each bit corresponds to a different peripheral clock.
    pub peripheral_clocks1_enable: VolatileCell<u32>,

    /// Disable peripheral clocks (bank 1).
    ///
    /// Each bit corresponds to a different peripheral clock.
    pub peripheral_clocks1_disable: VolatileCell<u32>,
}

const PMU_BASE: isize = 0x40000000;

static mut PMU: *mut PMURegisters = PMU_BASE as *mut PMURegisters;

#[derive(Clone,Copy)]
pub enum PeripheralClock0 {
    Camo0,
    Crpyto0,
    Dma0,
    Flash0,
    Fuse0,
    GlobalSec,
    GlobalSecTimer,
    GlobalSecHs,
    Gpio0,
    Gpio1,
    I2C0,
    I2C1,
    I2CS0,
    KeyMgr0,
    PeriAPB0,
    PeriAPB1,
    PeriAPB2,
    PeriAPB2Timer,
    PeriAPB3,
    PeriAPB3Timer,
    PeriAPB3HS,
    PinMux,
    Pmu,
    RBox0,
    Rdd0,
    Rtc0,
    Rtc0Timer,
    Spi0Hs,
    Spi1Hs,
    Sps0,
    Sps0TimerHs,
    Swdp0,
    Temp0
}

#[derive(Clone,Copy)]
pub enum PeripheralClock1 {
    TimeHs0Timer,
    TimeHs1Timer,
    TimeLs0,
    TimeUs0Timer,
    Trng0,
    Uart0Timer,
    Uart1Timer,
    Uart2Timer,
    Usb0,
    Usb0TimerHs,
    Volt0,
    Watchdog0,
    Xo0,
    Xo0Timer,
    PeripheralMasterMatrix,
    PeripheralMatrix
}

#[derive(Clone,Copy)]
pub enum PeripheralClock {
    Bank0(PeripheralClock0),
    Bank1(PeripheralClock1)
}

/// Wrapper struct around `PeripheralClock` that can only be created by.
/// trusted code.
#[derive(Clone,Copy)]
pub struct Clock {
    // It's important that this field is private!
    clock: PeripheralClock
}

impl Clock {
    pub const unsafe fn new(clock: PeripheralClock) -> Clock {
        Clock { clock: clock }
    }

    pub fn enable(&self) {
        let pmu: &mut PMURegisters = unsafe { transmute(PMU) };
        match self.clock {
            PeripheralClock::Bank0(clock) => {
                pmu.peripheral_clocks0_enable.set(1 << (clock as u32));
            },
            PeripheralClock::Bank1(clock) => {
                pmu.peripheral_clocks1_enable.set(1 << (clock as u32));
            }
        }
    }

    pub fn disable(&self) {
        let pmu: &mut PMURegisters = unsafe { transmute(PMU) };
        match self.clock {
            PeripheralClock::Bank0(clock) => {
                pmu.peripheral_clocks0_disable.set(1 << (clock as u32));
            },
            PeripheralClock::Bank1(clock) => {
                pmu.peripheral_clocks1_disable.set(1 << (clock as u32));
            }
        }
    }
}

<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::mem;

use llvm_sys::core;
use llvm_sys::prelude::{
  LLVMBuilderRef,
  LLVMValueRef
};
use libc::{c_char, c_uint};

use types::Ty;
use block::BasicBlock;
use value::Value;

static NULL_NAME:[c_char; 1] = [0];

pub struct Builder(pub LLVMBuilderRef);
impl_dispose!(Builder, core::LLVMDisposeBuilder);

impl Builder {

  pub fn get_insert_block(&self) -> BasicBlock
  {
    BasicBlock(unsafe { core::LLVMGetInsertBlock(self.0)})
  }

  /// Position the builder at `instr` within `block`.
  pub fn position_at(&self, block: &BasicBlock, instr: &Value)
  {
    unsafe { core::LLVMPositionBuilder(self.0, block.0, instr.0) }
  }

  /// Position the builder at the end of `block`.
  pub fn position_at_end(&self, block: &BasicBlock)
  {
    unsafe { core::LLVMPositionBuilderAtEnd(self.0, block.0) }
  }

  /// Build an instruction that returns from the function with void.
  pub fn create_ret_void(&self) -> Value
  {
    Value(unsafe {core::LLVMBuildRetVoid(self.0)})
  }

  /// Build an instruction that returns from the function with `value`.
  pub fn create_ret(&self, value: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildRet(self.0, value.0)})
  }

  /// Build an instruction that allocates an array with the element type `elem` and the size `size`.
  ///
  /// The size of this array will be the size of `elem` times `size`.
  pub fn build_array_alloca(&self, elem: &Ty, size: &Value) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildArrayAlloca(self.0,
    														 elem.0,
    														 size.0,
    														 NULL_NAME.as_ptr() as *const c_char)
    })
  }

  /// Build an instruction that allocates a pointer to fit the size of `ty` then returns this pointer.
  ///
  /// Make sure to call `build_free` with the pointer value when you're done with it, or you're
  /// gonna have a bad time.
  pub fn create_alloca(&self, ty: &Ty) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildAlloca(self.0,
    												ty.0,
    												NULL_NAME.as_ptr() as *const c_char)
    })
  }

  /// Build an instruction that frees the `val`, which _MUST_ be a pointer that was returned
  /// from `build_alloca`.
  pub fn create_free(&self, val: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildFree(self.0, val.0) })
  }

  /// Build an instruction that store the value `val` in the pointer `ptr`.
  pub fn create_store(&self, val: &Value, ptr: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildStore(self.0, val.0, ptr.0) })
  }

  /// Build an instruction that branches to the block `dest`.
  pub fn create_br(&self, dest: &BasicBlock) -> Value
  {
    Value(unsafe { core::LLVMBuildBr(self.0, dest.0)})
  }

  /// Build an instruction that branches to `if_block` if `cond` evaluates to true, and `else_block` otherwise.
  pub fn create_cond_br(&self, cond: &Value,
  	                    if_block: &BasicBlock, else_block: Option<&BasicBlock>) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildCondBr(self.0,
    		                    cond.0,
    		                    if_block.0,
    		                    mem::transmute(else_block))
    })
  }

  /// Build an instruction that yields to `true_val` if `cond` is equal to `1`, and `false_val` otherwise.
  pub fn create_select(&self, cond: &Value, true_val: &Value, false_val: &Value) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildSelect(self.0,
    		                    cond.0,
    		                    true_val.0,
    		                    false_val.0,
    		                    NULL_NAME.as_ptr()) })
  }

  /// Build an instruction that casts a value into a certain type.
  pub fn create_bit_cast(&self, value: &Value, dest: &Ty) -> Value
  {
    Value(unsafe { core::LLVMBuildBitCast(
    		self.0,
    		value.0,
    		dest.0,
    		NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction that inserts a value into an aggregate data value.
  pub fn create_insert_value(&self, agg: &Value, elem: &Value, index: usize) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildInsertValue(self.0,
    		                         agg.0,
    		                         elem.0,
    		                         index as c_uint,
    		                         NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction that extracts a value from an aggregate type.
	pub fn create_extract_value(&self, agg: &Value, index: usize) -> Value {
    Value(unsafe {
    	core::LLVMBuildExtractValue(self.0,
    		                          agg.0,
    		                          index as c_uint,
    		                          NULL_NAME.as_ptr())
   	})
  }

  /// Build an instruction that computes the address of a subelement of an aggregate data structure.
  ///
  /// Basically type-safe pointer arithmetic.
  pub fn create_gep(&self, pointer: &Value, indices: &[&Value]) -> Value
  {
    let values = indices.iter().map(|v| v.0).collect::<Vec<LLVMValueRef>>();

    Value(unsafe {
    	core::LLVMBuildInBoundsGEP(self.0,
    	                           pointer.0,
    	                           values.as_ptr() as *mut LLVMValueRef,
    	                           indices.len() as c_uint,
    	                           NULL_NAME.as_ptr())
    })
  }

  /*
  /// Build an instruction to select a value depending on the predecessor of the current block.
  pub fn create_phi(&self, ty: &Type, name: &str) -> &PhiNode
  {
	  unsafe {
	  	core::LLVMBuildPhi(self.into(), ty.into(), CString::new(name).unwrap().as_ptr())
  	}.into()
  }*/

  /// Build an instruction that runs whichever block matches the value, or `default` if none of them matched it.
  pub fn create_switch(&self,
  	                   value: &Value,
  	                   default: &BasicBlock,
  	                   cases: &[(&Value, &BasicBlock)]) -> Value {
    Value(unsafe {
      let switch = core::LLVMBuildSwitch(self.0,
      	                                 value.0,
      	                                 default.0,
      	                                 cases.len() as c_uint);
      for case in cases {
        core::LLVMAddCase(switch, (case.0).0, (case.1).0);
      }

      switch
    })
  }
}<commit_msg>Add create_phi to Builder.<commit_after>#![allow(dead_code)]

use std::mem;

use llvm_sys::core;
use llvm_sys::prelude::{
  LLVMBuilderRef,
  LLVMValueRef
};
use libc::{c_char, c_uint};

use types::Ty;
use block::BasicBlock;
use value::{PhiNode, Value};

static NULL_NAME:[c_char; 1] = [0];

pub struct Builder(pub LLVMBuilderRef);
impl_dispose!(Builder, core::LLVMDisposeBuilder);

impl Builder {

  pub fn get_insert_block(&self) -> BasicBlock
  {
    BasicBlock(unsafe { core::LLVMGetInsertBlock(self.0)})
  }

  /// Position the builder at `instr` within `block`.
  pub fn position_at(&self, block: &BasicBlock, instr: &Value)
  {
    unsafe { core::LLVMPositionBuilder(self.0, block.0, instr.0) }
  }

  /// Position the builder at the end of `block`.
  pub fn position_at_end(&self, block: &BasicBlock)
  {
    unsafe { core::LLVMPositionBuilderAtEnd(self.0, block.0) }
  }

  /// Build an instruction that returns from the function with void.
  pub fn create_ret_void(&self) -> Value
  {
    Value(unsafe {core::LLVMBuildRetVoid(self.0)})
  }

  /// Build an instruction that returns from the function with `value`.
  pub fn create_ret(&self, value: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildRet(self.0, value.0)})
  }

  /// Build an instruction that allocates an array with the element type `elem` and the size `size`.
  ///
  /// The size of this array will be the size of `elem` times `size`.
  pub fn build_array_alloca(&self, elem: &Ty, size: &Value) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildArrayAlloca(self.0,
    														 elem.0,
    														 size.0,
    														 NULL_NAME.as_ptr() as *const c_char)
    })
  }

  /// Build an instruction that allocates a pointer to fit the size of `ty` then returns this pointer.
  ///
  /// Make sure to call `build_free` with the pointer value when you're done with it, or you're
  /// gonna have a bad time.
  pub fn create_alloca(&self, ty: &Ty) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildAlloca(self.0,
    												ty.0,
    												NULL_NAME.as_ptr() as *const c_char)
    })
  }

  /// Build an instruction that frees the `val`, which _MUST_ be a pointer that was returned
  /// from `build_alloca`.
  pub fn create_free(&self, val: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildFree(self.0, val.0) })
  }

  /// Build an instruction that store the value `val` in the pointer `ptr`.
  pub fn create_store(&self, val: &Value, ptr: &Value) -> Value
  {
    Value(unsafe { core::LLVMBuildStore(self.0, val.0, ptr.0) })
  }

  /// Build an instruction that branches to the block `dest`.
  pub fn create_br(&self, dest: &BasicBlock) -> Value
  {
    Value(unsafe { core::LLVMBuildBr(self.0, dest.0)})
  }

  /// Build an instruction that branches to `if_block` if `cond` evaluates to true, and `else_block` otherwise.
  pub fn create_cond_br(&self, cond: &Value,
  	                    if_block: &BasicBlock, else_block: Option<&BasicBlock>) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildCondBr(self.0,
    		                    cond.0,
    		                    if_block.0,
    		                    mem::transmute(else_block))
    })
  }

  /// Build an instruction that yields to `true_val` if `cond` is equal to `1`, and `false_val` otherwise.
  pub fn create_select(&self, cond: &Value, true_val: &Value, false_val: &Value) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildSelect(self.0,
    		                    cond.0,
    		                    true_val.0,
    		                    false_val.0,
    		                    NULL_NAME.as_ptr()) })
  }

  /// Build an instruction that casts a value into a certain type.
  pub fn create_bit_cast(&self, value: &Value, dest: &Ty) -> Value
  {
    Value(unsafe { core::LLVMBuildBitCast(
    		self.0,
    		value.0,
    		dest.0,
    		NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction that inserts a value into an aggregate data value.
  pub fn create_insert_value(&self, agg: &Value, elem: &Value, index: usize) -> Value
  {
    Value(unsafe {
    	core::LLVMBuildInsertValue(self.0,
    		                         agg.0,
    		                         elem.0,
    		                         index as c_uint,
    		                         NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction that extracts a value from an aggregate type.
	pub fn create_extract_value(&self, agg: &Value, index: usize) -> Value {
    Value(unsafe {
    	core::LLVMBuildExtractValue(self.0,
    		                          agg.0,
    		                          index as c_uint,
    		                          NULL_NAME.as_ptr())
   	})
  }

  /// Build an instruction that computes the address of a subelement of an aggregate data structure.
  ///
  /// Basically type-safe pointer arithmetic.
  pub fn create_gep(&self, pointer: &Value, indices: &[&Value]) -> Value
  {
    let values = indices.iter().map(|v| v.0).collect::<Vec<LLVMValueRef>>();

    Value(unsafe {
    	core::LLVMBuildInBoundsGEP(self.0,
    	                           pointer.0,
    	                           values.as_ptr() as *mut LLVMValueRef,
    	                           indices.len() as c_uint,
    	                           NULL_NAME.as_ptr())
    })
  }

  /// Build an instruction to select a value depending on the predecessor of the current block.
  pub fn create_phi(&self, ty: &Ty, name: &str) -> PhiNode
  {
	  PhiNode(unsafe {
	  	core::LLVMBuildPhi(self.0, ty.0, ::util::str_to_chars(name))
  	})
  }

  /// Build an instruction that runs whichever block matches the value, or `default` if none of them matched it.
  pub fn create_switch(&self,
  	                   value: &Value,
  	                   default: &BasicBlock,
  	                   cases: &[(&Value, &BasicBlock)]) -> Value {
    Value(unsafe {
      let switch = core::LLVMBuildSwitch(self.0,
      	                                 value.0,
      	                                 default.0,
      	                                 cases.len() as c_uint);
      for case in cases {
        core::LLVMAddCase(switch, (case.0).0, (case.1).0);
      }

      switch
    })
  }
}<|endoftext|>


<commit_before>//! Various definitions of types, constants, traint, ... related to network

use core::fmt::{
    Binary,
    Octal,
    LowerHex,
    UpperHex,
    Debug,
    Display,
    Formatter,
    Error
};

use core::str::FromStr;

use vec::Vec;

use num::PrimInt;

use net::Packet;

/// Type of the ether_type
pub type EtherType = u16;
/// Type that represent a protocol id
pub type ProtocolIdType = u8;
/// Type that represent a port
pub type PortType = u16;

#[derive(Clone)]
/// Ethernet layer part of the rule
pub struct EthernetRule {
    pub ether_type: EtherType,
    pub hw_in: Option<HwAddr>,
}

#[derive(Clone)]
/// Network layer part of the rule
pub struct NetworkRule {
    pub protocol_id: ProtocolIdType,
    pub ip_in: Option<IpAddr>,
}

#[derive(Clone)]
/// Transport layer part of the rule
pub struct TransportRule {
    pub port: PortType,
}

#[derive(Clone)]
/// Represent a rule that a packet must match to be enqueued in a connexion
pub struct Rule {
    pub eth_rule: Option<EthernetRule>,
    pub net_rule: Option<NetworkRule>,
    pub tspt_rule: Option<TransportRule>,
}

/// Trait implemented by hardware interfaces
pub trait Device {
    /// Periodically called by the network thread to let the interface
    /// refresh its rx/tx buffers, ...
    fn refresh(&mut self);

    /// Transmit a packet via the interface
    fn tx_packet(&mut self, pkt: Packet);
}

/// Network integer representation
///
/// This type stores an integer using network's endianness and let the user
/// manipulates it using host's endianness.
#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Int<T: PrimInt + Clone>(T);

impl<T> Int<T> where T: PrimInt + Clone {
    /// Construct from an integer represented using network's endianness
    pub fn from_net(i: T) -> Self {
        Int(i)
    }

    /// Construct from an integer represented using host's endianness
    pub fn from_host(i: T) -> Self {
        Int(i.to_be())
    }

    /// Returns the contained integer using host's endianness
    pub fn as_host(&self) -> T {
        T::from_be(self.0.clone())
    }

    /// Returns the contained integer using network's endianness
    pub fn as_net(&self) -> T {
        self.0.clone()
    }
}

impl<T> Binary for Int<T> where T: PrimInt + Clone + Binary {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Octal for Int<T> where T: PrimInt + Clone + Octal {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> LowerHex for Int<T> where T: PrimInt + Clone + LowerHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> UpperHex for Int<T> where T: PrimInt + Clone + UpperHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Debug for Int<T> where T: PrimInt + Clone + Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Display for Int<T> where T: PrimInt + Clone + Display {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

const COUNT_HWADDR_BYTES: usize = 6;

#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
/// An IP address, either V4 or V6
pub enum IpAddr {
    /// An IPv4 address
    V4(Ipv4Addr),
    /// An IPv6 address
    V6(Ipv6Addr)
}

#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
/// An IPv4 address
pub struct Ipv4Addr {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
}

impl Ipv4Addr {
    /// Creates a new IPv4 address
    ///
    /// The result will represent the IP address `a`.`b`.`c`.`d`
    pub fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
        Ipv4Addr {
            a: a,
            b: b,
            c: c,
            d: d,
        }
    }
}

impl Display for Ipv4Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}.{}.{}.{}", self.a, self.b, self.c,
                                 self.d))
    }
}

#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
/// An IPv6 address
pub struct Ipv6Addr {
    a: Int<u16>,
    b: Int<u16>,
    c: Int<u16>,
    d: Int<u16>,
    e: Int<u16>,
    f: Int<u16>,
    g: Int<u16>,
    h: Int<u16>,
}

impl Ipv6Addr {
    /// Creates a new IPv6 address
    ///
    /// The result will represent the IP address `a`:`b`:`c`:`d`:`e`:`f`:`g`:`h`
    pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16,
               h: u16) -> Ipv6Addr {
        Ipv6Addr {
            a: Int::from_host(a),
            b: Int::from_host(b),
            c: Int::from_host(c),
            d: Int::from_host(d),
            e: Int::from_host(e),
            f: Int::from_host(f),
            g: Int::from_host(g),
            h: Int::from_host(h),
        }
    }
}

impl Display for Ipv6Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}:{}:{}:{}:{}:{}:{}:{}", self.a, self.b,
                                 self.c, self.d, self.e, self.f, self.g,
                                 self.h))
    }
}

#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
/// A MAC address
pub struct HwAddr {
    bytes: [u8; COUNT_HWADDR_BYTES],
}

impl HwAddr {
    /// Create an empty hardware address (i.e., 00:00:00:00:00:00)
    pub fn empty() -> Self {
        HwAddr {
            bytes: [0; COUNT_HWADDR_BYTES],
        }
    }

    /// Create an hardware address from bytes.
    ///
    /// This method is unsafe because the slice *MUST* contain at least 6
    /// elements.
    pub unsafe fn from_bytes(bytes: &[u8]) -> Self {
        let mut ret = Self::empty();

        ret.bytes[0] = bytes[0];
        ret.bytes[1] = bytes[1];
        ret.bytes[2] = bytes[2];
        ret.bytes[3] = bytes[3];
        ret.bytes[4] = bytes[4];
        ret.bytes[5] = bytes[5];

        ret
    }

    #[inline]
    /// Returns the internal representation of an hardware address
    pub fn as_bytes(&self) -> &[u8] {
        &self.bytes[..]
    }
}

impl FromStr for HwAddr {
    type Err = ();

    /// Convert a string with format XX:XX:XX:XX:XX:XX to an hardware address
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let split: Vec<&str> = s.split(':').collect();

        if split.len() != COUNT_HWADDR_BYTES {
            return Err(())
        }

        let mut ret = Self::empty();

        for (i, b) in split.iter().enumerate() {
            let bytes = b.as_bytes();

            if bytes.len() != 2 {
                return Err(())
            }

            let d1 = try!(b.char_at(0).to_digit(16).ok_or(())) * 16;
            let d2 = try!(b.char_at(1).to_digit(16).ok_or(()));

            ret.bytes[i] = d1 as u8 + d2 as u8;
        }

        Ok(ret)
    }
}

impl Display for HwAddr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
                                 self.bytes[0], self.bytes[1], self.bytes[2],
                                 self.bytes[3], self.bytes[4], self.bytes[5]))
    }
}
<commit_msg>net/defs: Add HwAddr::{is_broadcast(), broadcast()}<commit_after>//! Various definitions of types, constants, traint, ... related to network

use core::fmt::{
    Binary,
    Octal,
    LowerHex,
    UpperHex,
    Debug,
    Display,
    Formatter,
    Error
};

use core::str::FromStr;

use vec::Vec;

use num::PrimInt;

use net::Packet;

/// Type of the ether_type
pub type EtherType = u16;
/// Type that represent a protocol id
pub type ProtocolIdType = u8;
/// Type that represent a port
pub type PortType = u16;

#[derive(Clone)]
/// Ethernet layer part of the rule
pub struct EthernetRule {
    pub ether_type: EtherType,
    pub hw_in: Option<HwAddr>,
}

#[derive(Clone)]
/// Network layer part of the rule
pub struct NetworkRule {
    pub protocol_id: ProtocolIdType,
    pub ip_in: Option<IpAddr>,
}

#[derive(Clone)]
/// Transport layer part of the rule
pub struct TransportRule {
    pub port: PortType,
}

#[derive(Clone)]
/// Represent a rule that a packet must match to be enqueued in a connexion
pub struct Rule {
    pub eth_rule: Option<EthernetRule>,
    pub net_rule: Option<NetworkRule>,
    pub tspt_rule: Option<TransportRule>,
}

/// Trait implemented by hardware interfaces
pub trait Device {
    /// Periodically called by the network thread to let the interface
    /// refresh its rx/tx buffers, ...
    fn refresh(&mut self);

    /// Transmit a packet via the interface
    fn tx_packet(&mut self, pkt: Packet);
}

/// Network integer representation
///
/// This type stores an integer using network's endianness and let the user
/// manipulates it using host's endianness.
#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Int<T: PrimInt + Clone>(T);

impl<T> Int<T> where T: PrimInt + Clone {
    /// Construct from an integer represented using network's endianness
    pub fn from_net(i: T) -> Self {
        Int(i)
    }

    /// Construct from an integer represented using host's endianness
    pub fn from_host(i: T) -> Self {
        Int(i.to_be())
    }

    /// Returns the contained integer using host's endianness
    pub fn as_host(&self) -> T {
        T::from_be(self.0.clone())
    }

    /// Returns the contained integer using network's endianness
    pub fn as_net(&self) -> T {
        self.0.clone()
    }
}

impl<T> Binary for Int<T> where T: PrimInt + Clone + Binary {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Octal for Int<T> where T: PrimInt + Clone + Octal {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> LowerHex for Int<T> where T: PrimInt + Clone + LowerHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> UpperHex for Int<T> where T: PrimInt + Clone + UpperHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Debug for Int<T> where T: PrimInt + Clone + Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Display for Int<T> where T: PrimInt + Clone + Display {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

const COUNT_HWADDR_BYTES: usize = 6;

#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
/// An IP address, either V4 or V6
pub enum IpAddr {
    /// An IPv4 address
    V4(Ipv4Addr),
    /// An IPv6 address
    V6(Ipv6Addr)
}

#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
/// An IPv4 address
pub struct Ipv4Addr {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
}

impl Ipv4Addr {
    /// Creates a new IPv4 address
    ///
    /// The result will represent the IP address `a`.`b`.`c`.`d`
    pub fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
        Ipv4Addr {
            a: a,
            b: b,
            c: c,
            d: d,
        }
    }
}

impl Display for Ipv4Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}.{}.{}.{}", self.a, self.b, self.c,
                                 self.d))
    }
}

#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
/// An IPv6 address
pub struct Ipv6Addr {
    a: Int<u16>,
    b: Int<u16>,
    c: Int<u16>,
    d: Int<u16>,
    e: Int<u16>,
    f: Int<u16>,
    g: Int<u16>,
    h: Int<u16>,
}

impl Ipv6Addr {
    /// Creates a new IPv6 address
    ///
    /// The result will represent the IP address `a`:`b`:`c`:`d`:`e`:`f`:`g`:`h`
    pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16,
               h: u16) -> Ipv6Addr {
        Ipv6Addr {
            a: Int::from_host(a),
            b: Int::from_host(b),
            c: Int::from_host(c),
            d: Int::from_host(d),
            e: Int::from_host(e),
            f: Int::from_host(f),
            g: Int::from_host(g),
            h: Int::from_host(h),
        }
    }
}

impl Display for Ipv6Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}:{}:{}:{}:{}:{}:{}:{}", self.a, self.b,
                                 self.c, self.d, self.e, self.f, self.g,
                                 self.h))
    }
}

#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
/// A MAC address
pub struct HwAddr {
    bytes: [u8; COUNT_HWADDR_BYTES],
}

impl HwAddr {
    /// Create an empty hardware address (i.e., 00:00:00:00:00:00)
    pub fn empty() -> Self {
        HwAddr {
            bytes: [0; COUNT_HWADDR_BYTES],
        }
    }

    /// Create a broadcast hardware address (i.e., FF:FF:FF:FF:FF:FF)
    pub fn broadcast() -> Self {
        HwAddr {
            bytes: [0xFF; COUNT_HWADDR_BYTES],
        }
    }

    /// Is the current hardware address a broadcast
    /// address (i.e., FF:FF:FF:FF:FF:FF)
    pub fn is_broadcast(&self) -> bool {
        *self == Self::broadcast()
    }

    /// Create an hardware address from bytes.
    ///
    /// This method is unsafe because the slice *MUST* contain at least 6
    /// elements.
    pub unsafe fn from_bytes(bytes: &[u8]) -> Self {
        let mut ret = Self::empty();

        ret.bytes[0] = bytes[0];
        ret.bytes[1] = bytes[1];
        ret.bytes[2] = bytes[2];
        ret.bytes[3] = bytes[3];
        ret.bytes[4] = bytes[4];
        ret.bytes[5] = bytes[5];

        ret
    }

    #[inline]
    /// Returns the internal representation of an hardware address
    pub fn as_bytes(&self) -> &[u8] {
        &self.bytes[..]
    }
}

impl FromStr for HwAddr {
    type Err = ();

    /// Convert a string with format XX:XX:XX:XX:XX:XX to an hardware address
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let split: Vec<&str> = s.split(':').collect();

        if split.len() != COUNT_HWADDR_BYTES {
            return Err(())
        }

        let mut ret = Self::empty();

        for (i, b) in split.iter().enumerate() {
            let bytes = b.as_bytes();

            if bytes.len() != 2 {
                return Err(())
            }

            let d1 = try!(b.char_at(0).to_digit(16).ok_or(())) * 16;
            let d2 = try!(b.char_at(1).to_digit(16).ok_or(()));

            ret.bytes[i] = d1 as u8 + d2 as u8;
        }

        Ok(ret)
    }
}

impl Display for HwAddr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
                                 self.bytes[0], self.bytes[1], self.bytes[2],
                                 self.bytes[3], self.bytes[4], self.bytes[5]))
    }
}
<|endoftext|>


<commit_before>use error::Result;
use token::Token;

pub struct Module;

/// Root Twig AST node.
impl Module {
    pub fn from_tokens<'code, I>(tokens: I)
        -> Result<Module>
            where I: IntoIterator<Item=Result<Token<'code>>>
    {
        let mut i = tokens.into_iter();
        i.next();
        Ok(Module)
    }
}
<commit_msg>Starting from Module and trying to keep it simple as much as possible.<commit_after>use error::Result;
use token::Token;

pub struct Body;
pub struct Block;
pub struct Macro;
pub struct Trait;
pub struct AnyNode;

pub struct Module {
    // Sub nodes.
    body: Vec<Body>,
    blocks: Vec<Block>,
    macros: Vec<Macro>,
    traits: Vec<Trait>,

    // Attributes.
    file_id: Option<String>, // this must NOT be treated as file name
    index: i32, // TODO: wtf is this
    embedded_templates: Vec<()>, // TODO: should this be here

    // TODO: check usage of things bellow
    display_start: AnyNode,
    display_end: AnyNode,
    constructor_start: AnyNode,
    constructor_end: AnyNode,
    class_end: AnyNode,
}

/// Root Twig AST node.
impl Module {
    pub fn new() -> Module {
        Module {
            body: vec![],
            blocks: vec![],
            macros: vec![],
            traits: vec![],

            file_id: None,
            index: 0,
            embedded_templates: vec![],

            display_start: AnyNode,
            display_end: AnyNode,
            constructor_start: AnyNode,
            constructor_end: AnyNode,
            class_end: AnyNode,
        }
    }

    pub fn from_tokens<'code, I>(tokens: I)
        -> Result<Module>
            where I: IntoIterator<Item=Result<Token<'code>>>
    {
        let mut i = tokens.into_iter();
        i.next();
        Ok(Module::new())
    }
}
<|endoftext|>


<commit_before>use std::default::Default;
use std::env;
use std::path::Path;

use syntax::ast;
use syntax::codemap;
use syntax::ext::base;
use syntax::fold::Folder;
use syntax::parse;
use syntax::parse::token;
use syntax::ptr::P;
use syntax::util::small_vector::SmallVector;

use bindgen::{Bindings, BindgenOptions, LinkType, Logger, self};

pub fn bindgen_macro(cx: &mut base::ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree]) -> Box<base::MacResult+'static> {
    let mut visit = BindgenArgsVisitor {
        options: Default::default(),
        seen_named: false
    };

    visit.options.builtins = true;
    if !parse_macro_opts(cx, tts, &mut visit) {
        return base::DummyResult::any(sp);
    }

    // Reparse clang_args as it is passed in string form
    let clang_args = visit.options.clang_args.connect(" ");
    visit.options.clang_args = parse_process_args(&clang_args[..]);

    if let Some(path) = bindgen::get_include_dir() {
        visit.options.clang_args.push("-I".to_owned());
        visit.options.clang_args.push(path);
    }

    // Set the working dir to the directory containing the invoking rs file so
    // that clang searches for headers relative to it rather than the crate root
    let filename = cx.codemap().span_to_filename(sp);
    let mod_dir = Path::new(&filename).parent().unwrap();
    let cwd = match env::current_dir() {
      Ok(d)   => d,
      Err(e)  => panic!("Invalid current working directory: {}", e),
    };
    let p = Path::new(mod_dir);
    if let Err(e) = env::set_current_dir(&p) {
      panic!("Failed to change to directory {}: {}", p.display(), e);
    };

    // We want the span for errors to just match the bindgen! symbol
    // instead of the whole invocation which can span multiple lines
    let mut short_span = sp;
    short_span.hi = short_span.lo + codemap::BytePos(8);

    let logger = MacroLogger { sp: short_span, cx: cx };

    let ret = match Bindings::generate(&visit.options, Some(&logger as &Logger), None) {
        Ok(bindings) => {
            // syntex_syntax is not compatible with libsyntax so convert to string and reparse
            let bindings_str = bindings.to_string();
            // Unfortunately we lose span information due to reparsing
            let mut parser = parse::new_parser_from_source_str(cx.parse_sess(), cx.cfg(), "(Auto-generated bindings)".to_string(), bindings_str);

            let mut items = Vec::new();
            while let Some(item) = parser.parse_item() {
                items.push(item);
            }

            Box::new(BindgenResult { items: Some(SmallVector::many(items)) }) as Box<base::MacResult>

        }
        Err(_) => base::DummyResult::any(sp)
    };

    let p = Path::new(&cwd);
    if let Err(e) = env::set_current_dir(&p) {
      panic!("Failed to return to directory {}: {}", p.display(), e);
    }

    ret
}

trait MacroArgsVisitor {
    fn visit_str(&mut self, name: Option<&str>, val: &str) -> bool;
    fn visit_int(&mut self, name: Option<&str>, val: i64) -> bool;
    fn visit_bool(&mut self, name: Option<&str>, val: bool) -> bool;
    fn visit_ident(&mut self, name: Option<&str>, ident: &str) -> bool;
}

struct BindgenArgsVisitor {
    pub options: BindgenOptions,
    seen_named: bool
}

impl MacroArgsVisitor for BindgenArgsVisitor {
    fn visit_str(&mut self, mut name: Option<&str>, val: &str) -> bool {
        if name.is_some() { self.seen_named = true; }
        else if !self.seen_named { name = Some("clang_args") }
        match name {
            Some("link") => self.options.links.push((val.to_string(), LinkType::Default)),
            Some("link_static") => self.options.links.push((val.to_string(), LinkType::Static)),
            Some("link_framework") => self.options.links.push((val.to_string(), LinkType::Framework)),
            Some("match") => self.options.match_pat.push(val.to_string()),
            Some("clang_args") => self.options.clang_args.push(val.to_string()),
            Some("enum_type") => self.options.override_enum_ty = val.to_string(),
            _ => return false
        }
        true
    }

    fn visit_int(&mut self, name: Option<&str>, _val: i64) -> bool {
        if name.is_some() { self.seen_named = true; }
        false
    }

    fn visit_bool(&mut self, name: Option<&str>, val: bool) -> bool {
        if name.is_some() { self.seen_named = true; }
        match name {
            Some("allow_unknown_types") => self.options.fail_on_unknown_type = !val,
            Some("emit_builtins") => self.options.builtins = val,
            _ => return false
        }
        true
    }

    fn visit_ident(&mut self, name: Option<&str>, _val: &str) -> bool {
        if name.is_some() { self.seen_named = true; }
        false
    }
}

// Parses macro invocations in the form [ident=|:]value where value is an ident or literal
// e.g. bindgen!(module_name, "header.h", emit_builtins=false, clang_args:"-I /usr/local/include")
fn parse_macro_opts(cx: &mut base::ExtCtxt, tts: &[ast::TokenTree], visit: &mut MacroArgsVisitor) -> bool {
    let mut parser = cx.new_parser_from_tts(tts);
    let mut args_good = true;

    loop {
        let mut name: Option<String> = None;
        let mut span = parser.span;

        // Check for [ident=]value and if found save ident to name
        if parser.look_ahead(1, |t| t == &token::Eq) {
            match parser.bump_and_get() {
                Ok(token::Ident(ident, _)) => {
                    let ident = parser.id_to_interned_str(ident);
                    name = Some(ident.to_string());
                    parser.expect(&token::Eq);
                },
                _ => {
                    cx.span_err(span, "invalid argument format");
                    return false
                }
            }
        }

        match parser.token {
            // Match [ident]
            token::Ident(val, _) => {
                let val = parser.id_to_interned_str(val);
                span.hi = parser.span.hi;
                parser.bump();

                // Bools are simply encoded as idents
                let ret = match &*val {
                    "true" => visit.visit_bool(as_str(&name), true),
                    "false" => visit.visit_bool(as_str(&name), false),
                    val => visit.visit_ident(as_str(&name), val)
                };
                if !ret {
                    cx.span_err(span, "invalid argument");
                    args_good = false;
                }
            }
            // Match [literal] and parse as an expression so we can expand macros
            _ => {
                let expr = cx.expander().fold_expr(parser.parse_expr());
                span.hi = expr.span.hi;
                match expr.node {
                    ast::ExprLit(ref lit) => {
                        let ret = match lit.node {
                            ast::LitStr(ref s, _) => visit.visit_str(as_str(&name), &*s),
                            ast::LitBool(b) => visit.visit_bool(as_str(&name), b),
                            ast::LitInt(i, ast::SignedIntLit(_, sign)) |
                            ast::LitInt(i, ast::UnsuffixedIntLit(sign)) => {
                                let i = i as i64;
                                let i = if sign == ast::Minus { -i } else { i };
                                visit.visit_int(as_str(&name), i)
                            },
                            ast::LitInt(i, ast::UnsignedIntLit(_)) => visit.visit_int(as_str(&name), i as i64),
                            _ => {
                                cx.span_err(span, "invalid argument format");
                                return false
                            }
                        };
                        if !ret {
                            cx.span_err(span, "invalid argument");
                            args_good = false;
                        }
                    },
                    _ => {
                        cx.span_err(span, "invalid argument format");
                        return false
                    }
                }
            }
        }

        if parser.check(&token::Eof) {
            return args_good
        }

        if parser.eat(&token::Comma).is_err() {
            cx.span_err(parser.span, "invalid argument format");
            return false
        }
    }
}

// I'm sure there's a nicer way of doing it
fn as_str<'a>(owned: &'a Option<String>) -> Option<&'a str> {
    match owned {
        &Some(ref s) => Some(&s[..]),
        &None => None
    }
}

#[derive(PartialEq, Eq)]
enum QuoteState {
    InNone,
    InSingleQuotes,
    InDoubleQuotes
}

fn parse_process_args(s: &str) -> Vec<String> {
    let s = s.trim();
    let mut parts = Vec::new();
    let mut quote_state = QuoteState::InNone;
    let mut positions = vec!(0);
    let mut last = ' ';
    for (i, c) in s.chars().chain(" ".chars()).enumerate() {
        match (last, c) {
            // Match \" set has_escaped and skip
            ('\\', '\"') => (),
            // Match \'
            ('\\', '\'') => (),
            // Match \<space>
            // Check we don't escape the final added space
            ('\\', ' ') if i < s.len() => (),
            // Match \\
            ('\\', '\\') => (),
            // Match <any>"
            (_, '\"') if quote_state == QuoteState::InNone => {
                quote_state = QuoteState::InDoubleQuotes;
                positions.push(i);
                positions.push(i + 1);
            },
            (_, '\"') if quote_state == QuoteState::InDoubleQuotes => {
                quote_state = QuoteState::InNone;
                positions.push(i);
                positions.push(i + 1);
            },
            // Match <any>'
            (_, '\'') if quote_state == QuoteState::InNone => {
                quote_state = QuoteState::InSingleQuotes;
                positions.push(i);
                positions.push(i + 1);
            },
            (_, '\'') if quote_state == QuoteState::InSingleQuotes => {
                quote_state = QuoteState::InNone;
                positions.push(i);
                positions.push(i + 1);
            },
            // Match <any><space>
            // If we are at the end of the string close any open quotes
            (_, ' ') if quote_state == QuoteState::InNone || i >= s.len() => {
                {
                    positions.push(i);

                    let starts = positions.iter().enumerate().filter(|&(i, _)| i % 2 == 0);
                    let ends = positions.iter().enumerate().filter(|&(i, _)| i % 2 == 1);

                    let part: Vec<String> = starts.zip(ends).map(|((_, start), (_, end))| s[*start..*end].to_string()).collect();

                    let part = part.connect("");

                    if part.len() > 0 {
                        // Remove any extra whitespace outside the quotes
                        let part = &part[..].trim();
                        // Replace quoted characters
                        let part = part.replace("\\\"", "\"");
                        let part = part.replace("\\\'", "\'");
                        let part = part.replace("\\ ", " ");
                        let part = part.replace("\\\\", "\\");
                        parts.push(part);
                    }
                }

                positions.clear();
                positions.push(i + 1);
            },
            (_, _) => ()
        }
        last = c;
    }
    parts
}

struct MacroLogger<'a, 'b:'a> {
    sp: codemap::Span,
    cx: &'a base::ExtCtxt<'b>
}

impl<'a, 'b> Logger for MacroLogger<'a, 'b> {
    fn error(&self, msg: &str) {
        self.cx.span_err(self.sp, msg)
    }

    fn warn(&self, msg: &str) {
        self.cx.span_warn(self.sp, msg)
    }
}

struct BindgenResult {
    items: Option<SmallVector<P<ast::Item>>>
}

impl base::MacResult for BindgenResult {
    fn make_items(mut self: Box<BindgenResult>) -> Option<SmallVector<P<ast::Item>>> {
        self.items.take()
    }
}

#[test]
fn test_parse_process_args() {
    assert_eq!(parse_process_args("a b c"),         vec!("a", "b", "c"));
    assert_eq!(parse_process_args("a \"b\" c"),     vec!("a", "b", "c"));
    assert_eq!(parse_process_args("a \'b\' c"),     vec!("a", "b", "c"));
    assert_eq!(parse_process_args("a \"b c\""),     vec!("a", "b c"));
    assert_eq!(parse_process_args("a \'\"b\"\' c"), vec!("a", "\"b\"", "c"));
    assert_eq!(parse_process_args("a b\\ c"),       vec!("a", "b c"));
    assert_eq!(parse_process_args("a b c\\"),       vec!("a", "b", "c\\"));
}
<commit_msg>Fix compiler errors<commit_after>use std::default::Default;
use std::env;
use std::path::Path;

use syntax::ast;
use syntax::codemap;
use syntax::ext::base;
use syntax::fold::Folder;
use syntax::parse;
use syntax::parse::token;
use syntax::ptr::P;
use syntax::util::small_vector::SmallVector;

use bindgen::{Bindings, BindgenOptions, LinkType, Logger, self};

pub fn bindgen_macro(cx: &mut base::ExtCtxt, sp: codemap::Span, tts: &[ast::TokenTree]) -> Box<base::MacResult+'static> {
    let mut visit = BindgenArgsVisitor {
        options: Default::default(),
        seen_named: false
    };

    visit.options.builtins = true;
    if !parse_macro_opts(cx, tts, &mut visit) {
        return base::DummyResult::any(sp);
    }

    // Reparse clang_args as it is passed in string form
    let clang_args = visit.options.clang_args.join(" ");
    visit.options.clang_args = parse_process_args(&clang_args[..]);

    if let Some(path) = bindgen::get_include_dir() {
        visit.options.clang_args.push("-I".to_owned());
        visit.options.clang_args.push(path);
    }

    // Set the working dir to the directory containing the invoking rs file so
    // that clang searches for headers relative to it rather than the crate root
    let filename = cx.codemap().span_to_filename(sp);
    let mod_dir = Path::new(&filename).parent().unwrap();
    let cwd = match env::current_dir() {
      Ok(d)   => d,
      Err(e)  => panic!("Invalid current working directory: {}", e),
    };
    let p = Path::new(mod_dir);
    if let Err(e) = env::set_current_dir(&p) {
      panic!("Failed to change to directory {}: {}", p.display(), e);
    };

    // We want the span for errors to just match the bindgen! symbol
    // instead of the whole invocation which can span multiple lines
    let mut short_span = sp;
    short_span.hi = short_span.lo + codemap::BytePos(8);

    let logger = MacroLogger { sp: short_span, cx: cx };

    let ret = match Bindings::generate(&visit.options, Some(&logger as &Logger), None) {
        Ok(bindings) => {
            // syntex_syntax is not compatible with libsyntax so convert to string and reparse
            let bindings_str = bindings.to_string();
            // Unfortunately we lose span information due to reparsing
            let mut parser = parse::new_parser_from_source_str(cx.parse_sess(), cx.cfg(), "(Auto-generated bindings)".to_string(), bindings_str);

            let mut items = Vec::new();
            while let Ok(Some(item)) = parser.parse_item() {
                items.push(item);
            }

            Box::new(BindgenResult { items: Some(SmallVector::many(items)) }) as Box<base::MacResult>

        }
        Err(_) => base::DummyResult::any(sp)
    };

    let p = Path::new(&cwd);
    if let Err(e) = env::set_current_dir(&p) {
      panic!("Failed to return to directory {}: {}", p.display(), e);
    }

    ret
}

trait MacroArgsVisitor {
    fn visit_str(&mut self, name: Option<&str>, val: &str) -> bool;
    fn visit_int(&mut self, name: Option<&str>, val: i64) -> bool;
    fn visit_bool(&mut self, name: Option<&str>, val: bool) -> bool;
    fn visit_ident(&mut self, name: Option<&str>, ident: &str) -> bool;
}

struct BindgenArgsVisitor {
    pub options: BindgenOptions,
    seen_named: bool
}

impl MacroArgsVisitor for BindgenArgsVisitor {
    fn visit_str(&mut self, mut name: Option<&str>, val: &str) -> bool {
        if name.is_some() { self.seen_named = true; }
        else if !self.seen_named { name = Some("clang_args") }
        match name {
            Some("link") => self.options.links.push((val.to_string(), LinkType::Default)),
            Some("link_static") => self.options.links.push((val.to_string(), LinkType::Static)),
            Some("link_framework") => self.options.links.push((val.to_string(), LinkType::Framework)),
            Some("match") => self.options.match_pat.push(val.to_string()),
            Some("clang_args") => self.options.clang_args.push(val.to_string()),
            Some("enum_type") => self.options.override_enum_ty = val.to_string(),
            _ => return false
        }
        true
    }

    fn visit_int(&mut self, name: Option<&str>, _val: i64) -> bool {
        if name.is_some() { self.seen_named = true; }
        false
    }

    fn visit_bool(&mut self, name: Option<&str>, val: bool) -> bool {
        if name.is_some() { self.seen_named = true; }
        match name {
            Some("allow_unknown_types") => self.options.fail_on_unknown_type = !val,
            Some("emit_builtins") => self.options.builtins = val,
            _ => return false
        }
        true
    }

    fn visit_ident(&mut self, name: Option<&str>, _val: &str) -> bool {
        if name.is_some() { self.seen_named = true; }
        false
    }
}

// Parses macro invocations in the form [ident=|:]value where value is an ident or literal
// e.g. bindgen!(module_name, "header.h", emit_builtins=false, clang_args:"-I /usr/local/include")
fn parse_macro_opts(cx: &mut base::ExtCtxt, tts: &[ast::TokenTree], visit: &mut MacroArgsVisitor) -> bool {
    let mut parser = cx.new_parser_from_tts(tts);
    let mut args_good = true;

    loop {
        let mut name: Option<String> = None;
        let mut span = parser.span;

        // Check for [ident=]value and if found save ident to name
        if parser.look_ahead(1, |t| t == &token::Eq) {
            match parser.bump_and_get() {
                Ok(token::Ident(ident, _)) => {
                    let ident = parser.id_to_interned_str(ident);
                    name = Some(ident.to_string());
                    if let Err(_) = parser.expect(&token::Eq) {
                        return false;
                    }
                },
                _ => {
                    cx.span_err(span, "invalid argument format");
                    return false
                }
            }
        }

        match parser.token {
            // Match [ident]
            token::Ident(val, _) => {
                let val = parser.id_to_interned_str(val);
                span.hi = parser.span.hi;
                if let Err(_) = parser.bump() {
                    return false;
                }

                // Bools are simply encoded as idents
                let ret = match &*val {
                    "true" => visit.visit_bool(as_str(&name), true),
                    "false" => visit.visit_bool(as_str(&name), false),
                    val => visit.visit_ident(as_str(&name), val)
                };
                if !ret {
                    cx.span_err(span, "invalid argument");
                    args_good = false;
                }
            }
            // Match [literal] and parse as an expression so we can expand macros
            _ => {
                let expr = cx.expander().fold_expr(parser.parse_expr().unwrap());
                span.hi = expr.span.hi;
                match expr.node {
                    ast::ExprLit(ref lit) => {
                        let ret = match lit.node {
                            ast::LitStr(ref s, _) => visit.visit_str(as_str(&name), &*s),
                            ast::LitBool(b) => visit.visit_bool(as_str(&name), b),
                            ast::LitInt(i, ast::SignedIntLit(_, sign)) |
                            ast::LitInt(i, ast::UnsuffixedIntLit(sign)) => {
                                let i = i as i64;
                                let i = if sign == ast::Minus { -i } else { i };
                                visit.visit_int(as_str(&name), i)
                            },
                            ast::LitInt(i, ast::UnsignedIntLit(_)) => visit.visit_int(as_str(&name), i as i64),
                            _ => {
                                cx.span_err(span, "invalid argument format");
                                return false
                            }
                        };
                        if !ret {
                            cx.span_err(span, "invalid argument");
                            args_good = false;
                        }
                    },
                    _ => {
                        cx.span_err(span, "invalid argument format");
                        return false
                    }
                }
            }
        }

        if parser.check(&token::Eof) {
            return args_good
        }

        if parser.eat(&token::Comma).is_err() {
            cx.span_err(parser.span, "invalid argument format");
            return false
        }
    }
}

// I'm sure there's a nicer way of doing it
fn as_str<'a>(owned: &'a Option<String>) -> Option<&'a str> {
    match owned {
        &Some(ref s) => Some(&s[..]),
        &None => None
    }
}

#[derive(PartialEq, Eq)]
enum QuoteState {
    InNone,
    InSingleQuotes,
    InDoubleQuotes
}

fn parse_process_args(s: &str) -> Vec<String> {
    let s = s.trim();
    let mut parts = Vec::new();
    let mut quote_state = QuoteState::InNone;
    let mut positions = vec!(0);
    let mut last = ' ';
    for (i, c) in s.chars().chain(" ".chars()).enumerate() {
        match (last, c) {
            // Match \" set has_escaped and skip
            ('\\', '\"') => (),
            // Match \'
            ('\\', '\'') => (),
            // Match \<space>
            // Check we don't escape the final added space
            ('\\', ' ') if i < s.len() => (),
            // Match \\
            ('\\', '\\') => (),
            // Match <any>"
            (_, '\"') if quote_state == QuoteState::InNone => {
                quote_state = QuoteState::InDoubleQuotes;
                positions.push(i);
                positions.push(i + 1);
            },
            (_, '\"') if quote_state == QuoteState::InDoubleQuotes => {
                quote_state = QuoteState::InNone;
                positions.push(i);
                positions.push(i + 1);
            },
            // Match <any>'
            (_, '\'') if quote_state == QuoteState::InNone => {
                quote_state = QuoteState::InSingleQuotes;
                positions.push(i);
                positions.push(i + 1);
            },
            (_, '\'') if quote_state == QuoteState::InSingleQuotes => {
                quote_state = QuoteState::InNone;
                positions.push(i);
                positions.push(i + 1);
            },
            // Match <any><space>
            // If we are at the end of the string close any open quotes
            (_, ' ') if quote_state == QuoteState::InNone || i >= s.len() => {
                {
                    positions.push(i);

                    let starts = positions.iter().enumerate().filter(|&(i, _)| i % 2 == 0);
                    let ends = positions.iter().enumerate().filter(|&(i, _)| i % 2 == 1);

                    let part: Vec<String> = starts.zip(ends).map(|((_, start), (_, end))| s[*start..*end].to_string()).collect();

                    let part = part.join("");

                    if part.len() > 0 {
                        // Remove any extra whitespace outside the quotes
                        let part = &part[..].trim();
                        // Replace quoted characters
                        let part = part.replace("\\\"", "\"");
                        let part = part.replace("\\\'", "\'");
                        let part = part.replace("\\ ", " ");
                        let part = part.replace("\\\\", "\\");
                        parts.push(part);
                    }
                }

                positions.clear();
                positions.push(i + 1);
            },
            (_, _) => ()
        }
        last = c;
    }
    parts
}

struct MacroLogger<'a, 'b:'a> {
    sp: codemap::Span,
    cx: &'a base::ExtCtxt<'b>
}

impl<'a, 'b> Logger for MacroLogger<'a, 'b> {
    fn error(&self, msg: &str) {
        self.cx.span_err(self.sp, msg)
    }

    fn warn(&self, msg: &str) {
        self.cx.span_warn(self.sp, msg)
    }
}

struct BindgenResult {
    items: Option<SmallVector<P<ast::Item>>>
}

impl base::MacResult for BindgenResult {
    fn make_items(mut self: Box<BindgenResult>) -> Option<SmallVector<P<ast::Item>>> {
        self.items.take()
    }
}

#[test]
fn test_parse_process_args() {
    assert_eq!(parse_process_args("a b c"),         vec!("a", "b", "c"));
    assert_eq!(parse_process_args("a \"b\" c"),     vec!("a", "b", "c"));
    assert_eq!(parse_process_args("a \'b\' c"),     vec!("a", "b", "c"));
    assert_eq!(parse_process_args("a \"b c\""),     vec!("a", "b c"));
    assert_eq!(parse_process_args("a \'\"b\"\' c"), vec!("a", "\"b\"", "c"));
    assert_eq!(parse_process_args("a b\\ c"),       vec!("a", "b c"));
    assert_eq!(parse_process_args("a b c\\"),       vec!("a", "b", "c\\"));
}
<|endoftext|>