<commit_before>use super::*;

#[test]
fn test_encode_u8() {
    let mut array = [0u8; 10];
    {
        let mut dest = PacketWriter::new(&mut array);
        for x in 0u8..10u8 {
            x.encode(&mut dest).unwrap();
        }
        assert!(dest.available() == 0); //we should have filled it.
    }
    assert!(array == [0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
}

#[test]
fn test_encode_i8() {
    let mut array = [0u8; 10];
    {
        let mut dest = PacketWriter::new(&mut array);
        for x in -5i8..5i8 {
            x.encode(&mut dest).unwrap();
        }
        assert!(dest.available() == 0);
    }
    //The following literal comes from knowledge of twos complement arithmetic.
    //namely, if x>0 then -x = (~x)+1
    assert!(array == [251u8, 252u8, 253u8, 254u8, 255u8, 0u8, 1u8, 2u8, 3u8, 4u8]);
}

#[test]
fn test_encode_u16() {
    let mut array = [0u8; 8]; //encoding 4 u16s.
    {
        let mut dest = PacketWriter::new(&mut array);
        1u16.encode(&mut dest).unwrap();
        256u16.encode(&mut dest).unwrap();
        0x1010u16.encode(&mut dest).unwrap();
        0xffffu16.encode(&mut dest).unwrap();
        assert!(dest.available() == 0);
    }
    assert!(array == [0u8, 1u8, 1u8, 0u8, 0x10u8, 0x10u8, 0xffu8, 0xffu8]);
}

#[test]
fn test_encode_i16() {
    let mut array = [0u8; 8];
    {
        let mut dest = PacketWriter::new(&mut array);
        1i16.encode(&mut dest).unwrap();
        0x2345i16.encode(&mut dest).unwrap();
        (-1i16).encode(&mut dest).unwrap();
        (-2i16).encode(&mut dest).unwrap();
        assert!(dest.available() == 0);
    }
    assert!(array == [0u8, 1, 0x23, 0x45, 0xff, 0xff, 0xff, 0xfe]);
}

#[test]
fn test_encode_u32() {
    let mut array = [0u8; 8];
    {
        let mut dest = PacketWriter::new(&mut array);
        1u32.encode(&mut dest).unwrap();
        0x23456789u32.encode(&mut dest).unwrap();
        assert!(dest.available() == 0);
    }
    assert!(array == [0u8, 0, 0, 1,
    0x23, 0x45, 0x67, 0x89]);
}

#[test]
fn test_encode_i32() {
    let mut array = [0u8; 8];
    {
        let mut dest = PacketWriter::new(&mut array);
        0x23456789i32.encode(&mut dest).unwrap();
        (-2i32).encode(&mut dest).unwrap();
        assert!(dest.available() == 0);
    }
    assert!(array == [0x23u8, 0x45, 0x67, 0x89,
    0xff, 0xff, 0xff, 0xfe]);
}

#[test]
fn test_encode_str() {
    let mut array = [0u8; 6];
    {
        let mut dest = PacketWriter::new(&mut array);
        "hello".encode(&mut dest).unwrap();
        assert!(dest.available() == 0);
    }
    assert!(array == [b'h', b'e', b'l', b'l', b'o', 0]);
}

#[test]
fn test_encode_string() {
    let mut array = [0u8; 6];
    {
        let mut dest = PacketWriter::new(&mut array);
        "hello".to_string().encode(&mut dest).unwrap();
        assert!(dest.available() == 0);
    }
    assert!(array == [b'h', b'e', b'l', b'l', b'o', 0]);
}

#[test]
fn test_encode_status_request() {
    use super::StatusRequest::*;
    let mut     array = [0u8; 500];
    {
        let mut dest = PacketWriter::new(&mut array);
        FastnetQuery.encode(&mut dest).unwrap();
        assert!(dest.written() == 1);
    }
    assert!(array[0] == 0);
    {
        let mut dest = PacketWriter::new(&mut array);
        VersionQuery.encode(&mut dest);
        assert!(dest.written() == 1);
    }
    assert!(array[0] == 1u8);
    {
        let mut dest = PacketWriter::new(&mut array);
        ExtensionQuery("test_atest".to_string()).encode(&mut dest).unwrap();
        assert!(dest.written() == 12);
    }
    assert!(array[..12] == [2u8, b't', b'e', b's', b't', b'_',
    b'a', b't', b'e', b's', b't', 0]);
}

#[test]
fn test_encode_status_response() {
    use super::StatusResponse::*;
    let mut array = [0u8; 500];
    {
        let mut dest = PacketWriter::new(&mut array);
        FastnetResponse(1).encode(&mut dest).unwrap();
        assert!(dest.written() == 2)
    }
    assert!(array[..2] == [0u8, 1u8]);
    {
        let mut dest = PacketWriter::new(&mut array);
        VersionResponse("1.0".to_string()).encode(&mut dest).unwrap();
        assert!(dest.written() == 5);
    }
    assert!(array[..5] == [1u8, b'1', b'.', b'0', 0]);
    {
        let mut dest = PacketWriter::new(&mut array);
        ExtensionResponse{name: "test_atest".to_string(), supported: 1}.encode(&mut dest).unwrap();
        assert!(dest.written() == 13);
    }
    assert!(array[..13] == [2u8, b't', b'e', b's', b't', b'_',
    b'a', b't', b'e', b's', b't', 0, 1]);
}
<commit_msg>Rewrite encoder tests to use a macro.<commit_after>use super::*;

macro_rules! encoder_test {
    ($name: ident, $result: expr, $($encodees: expr),* ) => {
        #[test]
        fn $name() {
            let mut array = [0u8;1024];
            {
                let mut dest = PacketWriter::new(&mut array);
                $(($encodees).encode(&mut dest).unwrap();)*
                assert!(dest.written() == ($result).len());
            }
            assert!($result == array[..($result).len()]);
        }
    };
}

encoder_test!(test_encode_u8,
[0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9],
0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8);

encoder_test!(test_encode_i8,
[251u8, 252u8, 253u8, 254u8, 255u8, 0u8, 1u8, 2u8, 3u8, 4u8],
-5i8, -4i8, -3i8, -2i8, -1i8, 0i8, 1i8, 2i8, 3i8, 4i8);

encoder_test!(test_encode_u16,
[0u8, 1u8, 1u8, 0u8, 1u8, 1u8, 255u8, 255u8],
0x0001u16, 0x0100u16, 0x0101u16, 0xffffu16);

encoder_test!(test_encode_i16,
[0u8, 1, 0x23, 0x45, 0xff, 0xfe, 0xff, 0xff],
1i16, 0x2345i16, -2i16, -1i16);

encoder_test!(test_encode_u32,
[0u8, 0, 0, 1, 0x23, 0x45, 0x67, 0x89],
1u32, 0x23456789u32);

encoder_test!(test_encode_i32,
[0x23u8, 0x45, 0x67, 0x89, 0xff, 0xff, 0xff, 0xff],
0x23456789i32, -1i32);

encoder_test!(test_encode_str,
[b'h', b'e', b'l', b'l', b'o', 0u8],
"hello");

encoder_test!(test_encode_string,
[b'h', b'e', b'l', b'l', b'o', 0u8],
"hello".to_string());

encoder_test!(test_encode_status_request,
[0u8, //Fastnet query.
1, //Version query.
2, b't', b'e', b's', b't', b'_',
b'a', b't', b'e', b's', b't', 0], //Extension query.
StatusRequest::FastnetQuery, StatusRequest::VersionQuery, StatusRequest::ExtensionQuery("test_atest".to_string()));

encoder_test!(test_encode_status_response,
[0u8, 1, //fastnet response.
1, b'1', b'.', b'0', 0, //Version.
2, b't', b'e', b's', b't', b'_',
b'a', b't', b'e', b's', b't', 0, 1], //Extension "test_atest" is supported.
StatusResponse::FastnetResponse(1), StatusResponse::VersionResponse("1.0".to_string()),
StatusResponse::ExtensionResponse{name: "test_atest".to_string(), supported: 1});
<|endoftext|>


<commit_before>use crate::prelude::*;
use serde_derive::*;
use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::Write;
use std::rc::Rc;
use std::str;

use crate::handles::Handle;
use lldb::*;
use superslice::Ext;

struct Ranges {
    pub by_handle: HashMap<Handle, Rc<DisassembledRange>>,
    pub by_address: Vec<Rc<DisassembledRange>>,
}
pub struct AddressSpace {
    target: SBTarget,
    ranges: RefCell<Ranges>,
}

impl AddressSpace {
    pub fn new(target: &SBTarget) -> AddressSpace {
        AddressSpace {
            target: target.clone(),
            ranges: RefCell::new(Ranges {
                by_handle: HashMap::new(),
                by_address: Vec::new(),
            }),
        }
    }

    pub fn find_by_handle(&self, handle: Handle) -> Option<Rc<DisassembledRange>> {
        self.ranges.borrow_mut().by_handle.get(&handle).map(|dasm| dasm.clone())
    }

    fn find_by_address(&self, load_addr: Address) -> Option<Rc<DisassembledRange>> {
        let ranges = self.ranges.borrow_mut();
        let idx = ranges.by_address.upper_bound_by_key(&load_addr, |dasm| dasm.start_load_addr);
        if idx == 0 {
            None
        } else {
            let dasm = &ranges.by_address[idx - 1];
            if dasm.start_load_addr <= load_addr && load_addr < dasm.end_load_addr {
                Some(dasm.clone())
            } else {
                None
            }
        }
    }

    pub fn from_address(&self, load_addr: Address) -> Result<Rc<DisassembledRange>, Error> {
        if let Some(dasm) = self.find_by_address(load_addr) {
            return Ok(dasm);
        }

        let addr = SBAddress::from_load_address(load_addr, &self.target);
        debug!("{:?}", addr);

        let start_addr;
        let end_addr;
        let instructions;
        match addr.symbol() {
            Some(symbol) => {
                start_addr = symbol.start_address();
                end_addr = symbol.end_address();
                instructions = symbol.instructions(&self.target);
            }
            None => {
                // How many instructions to put into DisassembledRange if the address is not in scope of any symbol.
                const NO_SYMBOL_INSTRUCTIONS: u32 = 32;
                start_addr = addr.clone();
                instructions = self.target.read_instructions(&start_addr, NO_SYMBOL_INSTRUCTIONS + 1);
                end_addr = if instructions.len() > 0 {
                    let last_instr = instructions.instruction_at_index((instructions.len() - 1) as u32);
                    last_instr.address()
                } else {
                    start_addr.clone()
                };
            }
        }

        if instructions.len() > 0 {
            Ok(self.add(start_addr, end_addr, instructions))
        } else {
            bail!("Can't read instructions at that address.")
        }
    }

    fn add(
        &self,
        start_addr: SBAddress,
        end_addr: SBAddress,
        instructions: SBInstructionList,
    ) -> Rc<DisassembledRange> {
        let mut ranges = self.ranges.borrow_mut();
        let handle = Handle::new((ranges.by_handle.len() + 1000) as u32).unwrap();
        let instruction_addrs = instructions.iter().map(|i| i.address().load_address(&self.target)).collect();
        let start_load_addr = start_addr.load_address(&self.target);
        let end_load_addr = end_addr.load_address(&self.target);
        let source_name = match start_addr.symbol() {
            Some(symbol) => format!("@{}", symbol.name()),
            None => format!("@{:x}..{:x}", start_load_addr, end_load_addr),
        };
        let dasm = Rc::new(DisassembledRange {
            handle: handle,
            target: self.target.clone(),
            start_addr: start_addr,
            end_addr: end_addr,
            start_load_addr: start_load_addr,
            end_load_addr: end_load_addr,
            source_name: source_name,
            instructions: instructions,
            instruction_addresses: instruction_addrs,
            source_text: RefCell::new(None),
        });
        ranges.by_handle.insert(handle, dasm.clone());
        let idx = ranges.by_address.lower_bound_by_key(&dasm.start_load_addr, |dasm| dasm.start_load_addr);
        ranges.by_address.insert(idx, dasm.clone());
        dasm
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct AdapterData {
    pub start: Address,
    pub end: Address,
    pub line_offsets: Vec<u32>,
}

#[derive(Debug)]
pub struct DisassembledRange {
    handle: Handle,
    target: SBTarget,
    start_addr: SBAddress,
    end_addr: SBAddress,
    start_load_addr: Address,
    end_load_addr: Address,
    source_name: String,
    instructions: SBInstructionList,
    instruction_addresses: Vec<Address>,
    source_text: RefCell<Option<String>>,
}

impl DisassembledRange {
    pub fn handle(&self) -> Handle {
        self.handle
    }

    pub fn source_name(&self) -> &str {
        &self.source_name
    }

    pub fn line_num_by_address(&self, load_addr: Address) -> u32 {
        self.instruction_addresses.lower_bound(&load_addr) as u32 + 3
    }

    pub fn address_by_line_num(&self, line: u32) -> Address {
        self.instruction_addresses[line as usize - 3]
    }

    pub fn adapter_data(&self) -> AdapterData {
        let line_offsets = self.instruction_addresses.windows(2).map(|w| (w[1] - w[0]) as u32).collect();
        AdapterData {
            start: self.start_load_addr,
            end: self.end_load_addr,
            line_offsets: line_offsets,
        }
    }

    pub fn lines_from_adapter_data(adapter_data: &AdapterData) -> Vec<Address> {
        std::iter::repeat(adapter_data.start)
            .take(4) // lines are 1-based + 2 header lines + 1st instruction
            .chain(adapter_data.line_offsets.iter().scan(adapter_data.start, |addr, &delta| {
                *addr += delta as u64;
                Some(*addr)
            }))
            .collect()
    }

    pub fn get_source_text(&self) -> String {
        let source_location: Cow<str> = match self.start_addr.line_entry() {
            Some(le) => format!("{}:{}", le.file_spec().path().display(), le.line()).into(),
            None => "unknown".into(),
        };

        let description: Cow<str> = match self.start_addr.symbol() {
            Some(symbol) => {
                let mut descr = SBStream::new();
                if symbol.get_description(&mut descr) {
                    match str::from_utf8(descr.data()) {
                        Ok(s) => Some(s.to_owned().into()),
                        Err(_) => None,
                    }
                } else {
                    None
                }
            }
            None => None,
        }
        .unwrap_or("No Symbol Info".into());

        let mut text = String::new();
        let _ = writeln!(text, "; {}", description);
        let _ = writeln!(text, "; Source location: {}", source_location);

        const MAX_INSTR_BYTES: usize = 8;
        let mut instr_data = vec![];
        let mut dump = String::new();
        for instr in self.instructions.iter() {
            let load_addr = instr.address().load_address(&self.target);
            instr_data.resize(instr.byte_size(), 0);
            instr.data(&self.target).read_raw_data(0, &mut instr_data).unwrap();
            dump.clear();
            for (i, b) in instr_data.iter().enumerate() {
                if i >= MAX_INSTR_BYTES {
                    let _ = write!(dump, ">");
                    break;
                }
                let _ = write!(dump, "{:02X} ", b);
            }
            let mnemonic = instr.mnemonic(&self.target);
            let operands = instr.operands(&self.target);
            let comment = instr.comment(&self.target);
            let comment_sep = if comment.is_empty() {
                ""
            } else {
                "  ; "
            };
            #[rustfmt::skip]
            let _ = writeln!(text, "{:08X}: {:<dumpwidth$} {:<6} {}{}{}", //.
                load_addr, dump, mnemonic, operands, comment_sep, comment,
                dumpwidth=MAX_INSTR_BYTES * 3 + 2
            );
        }

        text
    }
}

#[test]
fn test_adapter_data() {
    let addresses = &[10, 20, 23, 25, 30, 35, 41, 42, 50];
    let adapter_data = AdapterData {
        start: 10,
        end: 55,
        line_offsets: addresses.windows(2).map(|w| (w[1] - w[0]) as u32).collect(),
    };
    let addresses2 = DisassembledRange::lines_from_adapter_data(&adapter_data);
    assert_eq!(addresses, &addresses2[3..]);
}
<commit_msg>Remove unused fields<commit_after>use crate::prelude::*;
use serde_derive::*;
use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::Write;
use std::rc::Rc;
use std::str;

use crate::handles::Handle;
use lldb::*;
use superslice::Ext;

struct Ranges {
    pub by_handle: HashMap<Handle, Rc<DisassembledRange>>,
    pub by_address: Vec<Rc<DisassembledRange>>,
}
pub struct AddressSpace {
    target: SBTarget,
    ranges: RefCell<Ranges>,
}

impl AddressSpace {
    pub fn new(target: &SBTarget) -> AddressSpace {
        AddressSpace {
            target: target.clone(),
            ranges: RefCell::new(Ranges {
                by_handle: HashMap::new(),
                by_address: Vec::new(),
            }),
        }
    }

    pub fn find_by_handle(&self, handle: Handle) -> Option<Rc<DisassembledRange>> {
        self.ranges.borrow_mut().by_handle.get(&handle).map(|dasm| dasm.clone())
    }

    fn find_by_address(&self, load_addr: Address) -> Option<Rc<DisassembledRange>> {
        let ranges = self.ranges.borrow_mut();
        let idx = ranges.by_address.upper_bound_by_key(&load_addr, |dasm| dasm.start_load_addr);
        if idx == 0 {
            None
        } else {
            let dasm = &ranges.by_address[idx - 1];
            if dasm.start_load_addr <= load_addr && load_addr < dasm.end_load_addr {
                Some(dasm.clone())
            } else {
                None
            }
        }
    }

    pub fn from_address(&self, load_addr: Address) -> Result<Rc<DisassembledRange>, Error> {
        if let Some(dasm) = self.find_by_address(load_addr) {
            return Ok(dasm);
        }

        let addr = SBAddress::from_load_address(load_addr, &self.target);
        debug!("{:?}", addr);

        let start_addr;
        let end_addr;
        let instructions;
        match addr.symbol() {
            Some(symbol) => {
                start_addr = symbol.start_address();
                end_addr = symbol.end_address();
                instructions = symbol.instructions(&self.target);
            }
            None => {
                // How many instructions to put into DisassembledRange if the address is not in scope of any symbol.
                const NO_SYMBOL_INSTRUCTIONS: u32 = 32;
                start_addr = addr.clone();
                instructions = self.target.read_instructions(&start_addr, NO_SYMBOL_INSTRUCTIONS + 1);
                end_addr = if instructions.len() > 0 {
                    let last_instr = instructions.instruction_at_index((instructions.len() - 1) as u32);
                    last_instr.address()
                } else {
                    start_addr.clone()
                };
            }
        }

        if instructions.len() > 0 {
            Ok(self.add(start_addr, end_addr, instructions))
        } else {
            bail!("Can't read instructions at that address.")
        }
    }

    fn add(
        &self,
        start_addr: SBAddress,
        end_addr: SBAddress,
        instructions: SBInstructionList,
    ) -> Rc<DisassembledRange> {
        let mut ranges = self.ranges.borrow_mut();
        let handle = Handle::new((ranges.by_handle.len() + 1000) as u32).unwrap();
        let instruction_addrs = instructions.iter().map(|i| i.address().load_address(&self.target)).collect();
        let start_load_addr = start_addr.load_address(&self.target);
        let end_load_addr = end_addr.load_address(&self.target);
        let source_name = match start_addr.symbol() {
            Some(symbol) => format!("@{}", symbol.name()),
            None => format!("@{:x}..{:x}", start_load_addr, end_load_addr),
        };
        let dasm = Rc::new(DisassembledRange {
            handle: handle,
            target: self.target.clone(),
            start_addr: start_addr,
            start_load_addr: start_load_addr,
            end_load_addr: end_load_addr,
            source_name: source_name,
            instructions: instructions,
            instruction_addresses: instruction_addrs,
        });
        ranges.by_handle.insert(handle, dasm.clone());
        let idx = ranges.by_address.lower_bound_by_key(&dasm.start_load_addr, |dasm| dasm.start_load_addr);
        ranges.by_address.insert(idx, dasm.clone());
        dasm
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct AdapterData {
    pub start: Address,
    pub end: Address,
    pub line_offsets: Vec<u32>,
}

#[derive(Debug)]
pub struct DisassembledRange {
    handle: Handle,
    target: SBTarget,
    start_addr: SBAddress,
    start_load_addr: Address,
    end_load_addr: Address,
    source_name: String,
    instructions: SBInstructionList,
    instruction_addresses: Vec<Address>,
}

impl DisassembledRange {
    pub fn handle(&self) -> Handle {
        self.handle
    }

    pub fn source_name(&self) -> &str {
        &self.source_name
    }

    pub fn line_num_by_address(&self, load_addr: Address) -> u32 {
        self.instruction_addresses.lower_bound(&load_addr) as u32 + 3
    }

    pub fn address_by_line_num(&self, line: u32) -> Address {
        self.instruction_addresses[line as usize - 3]
    }

    pub fn adapter_data(&self) -> AdapterData {
        let line_offsets = self.instruction_addresses.windows(2).map(|w| (w[1] - w[0]) as u32).collect();
        AdapterData {
            start: self.start_load_addr,
            end: self.end_load_addr,
            line_offsets: line_offsets,
        }
    }

    pub fn lines_from_adapter_data(adapter_data: &AdapterData) -> Vec<Address> {
        std::iter::repeat(adapter_data.start)
            .take(4) // lines are 1-based + 2 header lines + 1st instruction
            .chain(adapter_data.line_offsets.iter().scan(adapter_data.start, |addr, &delta| {
                *addr += delta as u64;
                Some(*addr)
            }))
            .collect()
    }

    pub fn get_source_text(&self) -> String {
        let source_location: Cow<str> = match self.start_addr.line_entry() {
            Some(le) => format!("{}:{}", le.file_spec().path().display(), le.line()).into(),
            None => "unknown".into(),
        };

        let description: Cow<str> = match self.start_addr.symbol() {
            Some(symbol) => {
                let mut descr = SBStream::new();
                if symbol.get_description(&mut descr) {
                    match str::from_utf8(descr.data()) {
                        Ok(s) => Some(s.to_owned().into()),
                        Err(_) => None,
                    }
                } else {
                    None
                }
            }
            None => None,
        }
        .unwrap_or("No Symbol Info".into());

        let mut text = String::new();
        let _ = writeln!(text, "; {}", description);
        let _ = writeln!(text, "; Source location: {}", source_location);

        const MAX_INSTR_BYTES: usize = 8;
        let mut instr_data = vec![];
        let mut dump = String::new();
        for instr in self.instructions.iter() {
            let load_addr = instr.address().load_address(&self.target);
            instr_data.resize(instr.byte_size(), 0);
            instr.data(&self.target).read_raw_data(0, &mut instr_data).unwrap();
            dump.clear();
            for (i, b) in instr_data.iter().enumerate() {
                if i >= MAX_INSTR_BYTES {
                    let _ = write!(dump, ">");
                    break;
                }
                let _ = write!(dump, "{:02X} ", b);
            }
            let mnemonic = instr.mnemonic(&self.target);
            let operands = instr.operands(&self.target);
            let comment = instr.comment(&self.target);
            let comment_sep = if comment.is_empty() {
                ""
            } else {
                "  ; "
            };
            #[rustfmt::skip]
            let _ = writeln!(text, "{:08X}: {:<dumpwidth$} {:<6} {}{}{}", //.
                load_addr, dump, mnemonic, operands, comment_sep, comment,
                dumpwidth=MAX_INSTR_BYTES * 3 + 2
            );
        }

        text
    }
}

#[test]
fn test_adapter_data() {
    let addresses = &[10, 20, 23, 25, 30, 35, 41, 42, 50];
    let adapter_data = AdapterData {
        start: 10,
        end: 55,
        line_offsets: addresses.windows(2).map(|w| (w[1] - w[0]) as u32).collect(),
    };
    let addresses2 = DisassembledRange::lines_from_adapter_data(&adapter_data);
    assert_eq!(addresses, &addresses2[3..]);
}
<|endoftext|>


<commit_before>//! Plugin manager for Lua plugins

use lua;
use config;
use std::{io, libc, str};

/// Manages the Lua state for plugins
pub struct PluginManager {
    priv state: lua::State
}

impl PluginManager {
    /// Creates a new PluginManager and loads all the plugins
    pub fn new(conf: &config::Config) -> PluginManager {
        let mut L = lua::State::new();
        L.openlibs();

        // set up our packages for loading
        L.pushcfunction(lua_setup_packages);
        match L.pcall(0, 0, 0) {
            Ok(()) => (),
            Err(e) => {
                fail!("Error setting up lua packages: {}: {}", e, L.describe(-1));
            }
        }

        match io::fs::readdir(&conf.plugin_dir) {
            Err(e) => {
                println!("Warning: Could not read plugin dir `{}': {}",
                         conf.plugin_dir.display(), e);
            }
            Ok(paths) => {
                for path in paths.iter() {
                    if path.as_vec() == bytes!(".") || path.as_vec() == bytes!("..") {
                        continue;
                    }
                    if !path.is_file() { continue; }
                    if path.extension() == Some(bytes!("lua")) {
                        // found a plugin
                        debug!("Loading plugin {}", path.filename_display());
                        match L.loadfile(Some(path)) {
                            Ok(()) => (),
                            Err(_) => {
                                println!("Error loading plugin {}: {}", path.filename_display(),
                                         L.describe(-1));
                                L.pop(1);
                                continue;
                            }
                        }
                        // call the plugin's chunk with a single argument, the name of the plugin
                        let name = str::from_utf8_lossy(path.filestem().unwrap());
                        L.pushstring(name.as_slice());
                        match L.pcall(1, 0, 0) {
                            Ok(()) => (),
                            Err(e) => {
                                println!("Error running plugin {}: {}: {}",
                                         path.filename_display(), e, L.describe(-1));
                                L.pop(1);
                                continue;
                            }
                        }
                    }
                }
            }
        }

        PluginManager { state: L }
    }

    /// Dispatches an IRC event
    pub fn dispatch_irc_event(&mut self, event: &irc::conn::Event) {
        self.state.pushcfunction(irc::lua_dispatch_event);
        self.state.pushlightuserdata(event as *irc::conn::Event as *mut libc::c_void);
        match self.state.pcall(1, 0, 0) {
            Ok(()) => (),
            Err(e) => {
                println!("Error dispatching IRC event: {}: {}", e, self.state.describe(-1));
                self.state.pop(1);
            }
        }
    }
}

extern "C" fn lua_setup_packages(L: *mut lua::raw::lua_State) -> libc::c_int {
    let mut L = unsafe { lua::State::from_lua_State(L) };

    // insert our package loaders into package.preload
    L.getglobal("package");
    L.getfield(-1, "preload");

    // irc
    L.pushcfunction(irc::lua_require);
    L.setfield(-2, "irc");

    L.pop(2);
    0
}

mod irc;
<commit_msg>Add an error handler for plugins<commit_after>//! Plugin manager for Lua plugins

use lua;
use config;
use std::{io, libc, str};

static ERROR_HANDLER: &'static str = "error_handler";

/// Manages the Lua state for plugins
pub struct PluginManager {
    priv state: lua::State
}

impl PluginManager {
    /// Creates a new PluginManager and loads all the plugins
    pub fn new(conf: &config::Config) -> PluginManager {
        let mut L = lua::State::new();
        L.openlibs();

        // create the error function and store it in the registry
        match L.loadstring("local msg = ...; return debug.traceback(msg, 2)") {
            Ok(()) => (),
            Err(e) => {
                fail!("Error creating error handler: {}: {}", e, L.describe(-1))
            }
        }
        L.setfield(lua::REGISTRYINDEX, ERROR_HANDLER);

        // set up our packages for loading
        L.getfield(lua::REGISTRYINDEX, ERROR_HANDLER);
        L.pushcfunction(lua_setup_packages);
        match L.pcall(0, 0, -2) {
            Ok(()) => (),
            Err(e) => {
                fail!("Error setting up lua packages: {}: {}", e, L.describe(-1));
            }
        }
        L.pop(1); // pop error handler

        match io::fs::readdir(&conf.plugin_dir) {
            Err(e) => {
                println!("Warning: Could not read plugin dir `{}': {}",
                         conf.plugin_dir.display(), e);
            }
            Ok(paths) => {
                for path in paths.iter() {
                    if path.as_vec() == bytes!(".") || path.as_vec() == bytes!("..") {
                        continue;
                    }
                    if !path.is_file() { continue; }
                    if path.extension() == Some(bytes!("lua")) {
                        // found a plugin
                        debug!("Loading plugin {}", path.filename_display());
                        L.getfield(lua::REGISTRYINDEX, ERROR_HANDLER);
                        match L.loadfile(Some(path)) {
                            Ok(()) => (),
                            Err(_) => {
                                println!("Error loading plugin {}: {}", path.filename_display(),
                                         L.describe(-1));
                                L.pop(2); // pop error, error handler
                                continue;
                            }
                        }
                        // call the plugin's chunk with a single argument, the name of the plugin
                        let name = str::from_utf8_lossy(path.filestem().unwrap());
                        L.pushstring(name.as_slice());
                        match L.pcall(1, 0, -3) {
                            Ok(()) => (),
                            Err(e) => {
                                println!("Error running plugin {}: {}: {}",
                                         path.filename_display(), e, L.describe(-1));
                                L.pop(2); // pop error, error handler
                                continue;
                            }
                        }
                        L.pop(1); // pop error handler
                    }
                }
            }
        }

        PluginManager { state: L }
    }

    /// Dispatches an IRC event
    pub fn dispatch_irc_event(&mut self, event: &irc::conn::Event) {
        self.state.getfield(lua::REGISTRYINDEX, ERROR_HANDLER);
        self.state.pushcfunction(irc::lua_dispatch_event);
        self.state.pushlightuserdata(event as *irc::conn::Event as *mut libc::c_void);
        match self.state.pcall(1, 0, -3) {
            Ok(()) => (),
            Err(e) => {
                println!("Error dispatching IRC event: {}: {}", e, self.state.describe(-1));
                self.state.pop(1);
            }
        }
        self.state.pop(1);
    }
}

extern "C" fn lua_setup_packages(L: *mut lua::raw::lua_State) -> libc::c_int {
    let mut L = unsafe { lua::State::from_lua_State(L) };

    // insert our package loaders into package.preload
    L.getglobal("package");
    L.getfield(-1, "preload");

    // irc
    L.pushcfunction(irc::lua_require);
    L.setfield(-2, "irc");

    L.pop(2);
    0
}

mod irc;
<|endoftext|>


<commit_before>fn main() {
    let list: ~[char] = ~['a', 'b', 'c'];
    println!("{:?}", list.last());
}
<commit_msg>Do Problem 01 without cheating<commit_after>fn last<'a, T>(list: &'a [T]) -> Option<&'a T> {
    match list {
        [] => None,
        [.., ref x] => Some(x)
    }
}

fn main() {
    let list: ~[char] = ~['a', 'b', 'c'];
    println!("{:?}", last(list));
    println!("{:?}", list.last()); // Cheat
}
<|endoftext|>


<commit_before>/// Traits required for parsing
pub use crate::types::parsing::traits;
use crate::{
    frame::*,
    protocol::{basic::parse_properties, *},
    types::parsing::*,
};
use nom::{
    bytes::streaming::{tag, take},
    combinator::{all_consuming, flat_map, map, map_opt, map_res},
    error::context,
    sequence::{pair, tuple},
};
use traits::ParsableInput;

/// Parse a channel id
pub fn parse_channel<I: ParsableInput>(i: I) -> ParserResult<I, AMQPChannel> {
    context("parse_channel", map(parse_id, From::from))(i)
}

/// Parse the protocol header
pub fn parse_protocol_header<I: ParsableInput>(i: I) -> ParserResult<I, ProtocolVersion> {
    context(
        "parse_protocol_header",
        map(
            tuple((
                tag(metadata::NAME.as_bytes()),
                tag(&[0][..]),
                parse_short_short_uint,
                parse_short_short_uint,
                parse_short_short_uint,
            )),
            |(_, _, major, minor, revision)| ProtocolVersion {
                major,
                minor,
                revision,
            },
        ),
    )(i)
}

/// Parse the frame type
pub fn parse_frame_type<I: ParsableInput>(i: I) -> ParserResult<I, AMQPFrameType> {
    context(
        "parse_frame_type",
        map_opt(parse_short_short_uint, |method| match method {
            constants::FRAME_METHOD => Some(AMQPFrameType::Method),
            constants::FRAME_HEADER => Some(AMQPFrameType::Header),
            constants::FRAME_BODY => Some(AMQPFrameType::Body),
            constants::FRAME_HEARTBEAT => Some(AMQPFrameType::Heartbeat),
            _ => None,
        }),
    )(i)
}

/// Parse a full AMQP Frame (with contents)
pub fn parse_frame<I: ParsableInput>(i: I) -> ParserResult<I, AMQPFrame> {
    context(
        "parse_frame",
        map_res(
            parse_raw_frame,
            |AMQPRawFrame {
                 channel_id,
                 frame_type,
                 payload,
             }: AMQPRawFrame<I>| match frame_type {
                AMQPFrameType::Method => all_consuming(parse_class)(payload)
                    .map(|(_, m)| AMQPFrame::Method(channel_id, m)),
                AMQPFrameType::Header => all_consuming(parse_content_header)(payload)
                    .map(|(_, h)| AMQPFrame::Header(channel_id, h.class_id, Box::new(h))),
                AMQPFrameType::Body => Ok(AMQPFrame::Body(
                    channel_id,
                    payload.iter_elements().collect(),
                )),
                AMQPFrameType::Heartbeat => Ok(AMQPFrame::Heartbeat(channel_id)),
            },
        ),
    )(i)
}

/// Parse a raw AMQP frame
pub fn parse_raw_frame<I: ParsableInput>(i: I) -> ParserResult<I, AMQPRawFrame<I>> {
    context(
        "parse_raw_frame",
        flat_map(
            tuple((parse_frame_type, parse_id, parse_long_uint)),
            move |(frame_type, channel_id, size)| {
                map(
                    pair(take(size), tag(&[constants::FRAME_END][..])),
                    move |(payload, _)| AMQPRawFrame {
                        frame_type,
                        channel_id,
                        payload,
                    },
                )
            },
        ),
    )(i)
}

/// Parse a content header frame
pub fn parse_content_header<I: ParsableInput>(i: I) -> ParserResult<I, AMQPContentHeader> {
    context(
        "parse_content_header",
        map(
            tuple((
                parse_id,
                parse_short_uint,
                parse_long_long_uint,
                context("parse_properties", parse_properties),
            )),
            |(class_id, weight, body_size, properties)| AMQPContentHeader {
                class_id,
                weight,
                body_size,
                properties,
            },
        ),
    )(i)
}
<commit_msg>hook up protocol header parsing inside parse_frame<commit_after>/// Traits required for parsing
pub use crate::types::parsing::traits;
use crate::{
    frame::*,
    protocol::{basic::parse_properties, *},
    types::parsing::*,
};
use nom::{
    branch::alt,
    bytes::streaming::{tag, take},
    combinator::{all_consuming, flat_map, map, map_opt, map_res},
    error::context,
    sequence::{pair, tuple},
};
use traits::ParsableInput;

/// Parse a channel id
pub fn parse_channel<I: ParsableInput>(i: I) -> ParserResult<I, AMQPChannel> {
    context("parse_channel", map(parse_id, From::from))(i)
}

/// Parse the protocol header
pub fn parse_protocol_header<I: ParsableInput>(i: I) -> ParserResult<I, ProtocolVersion> {
    context(
        "parse_protocol_header",
        map(
            tuple((
                tag(metadata::NAME.as_bytes()),
                tag(&[0][..]),
                parse_short_short_uint,
                parse_short_short_uint,
                parse_short_short_uint,
            )),
            |(_, _, major, minor, revision)| ProtocolVersion {
                major,
                minor,
                revision,
            },
        ),
    )(i)
}

/// Parse the frame type
pub fn parse_frame_type<I: ParsableInput>(i: I) -> ParserResult<I, AMQPFrameType> {
    context(
        "parse_frame_type",
        map_opt(parse_short_short_uint, |method| match method {
            constants::FRAME_METHOD => Some(AMQPFrameType::Method),
            constants::FRAME_HEADER => Some(AMQPFrameType::Header),
            constants::FRAME_BODY => Some(AMQPFrameType::Body),
            constants::FRAME_HEARTBEAT => Some(AMQPFrameType::Heartbeat),
            _ => None,
        }),
    )(i)
}

/// Parse a full AMQP Frame (with contents)
pub fn parse_frame<I: ParsableInput>(i: I) -> ParserResult<I, AMQPFrame> {
    context(
        "parse_frame",
        alt((
            map_res(
                parse_raw_frame,
                |AMQPRawFrame {
                     channel_id,
                     frame_type,
                     payload,
                 }: AMQPRawFrame<I>| match frame_type {
                    AMQPFrameType::Method => all_consuming(parse_class)(payload)
                        .map(|(_, m)| AMQPFrame::Method(channel_id, m)),
                    AMQPFrameType::Header => all_consuming(parse_content_header)(payload)
                        .map(|(_, h)| AMQPFrame::Header(channel_id, h.class_id, Box::new(h))),
                    AMQPFrameType::Body => Ok(AMQPFrame::Body(
                        channel_id,
                        payload.iter_elements().collect(),
                    )),
                    AMQPFrameType::Heartbeat => Ok(AMQPFrame::Heartbeat(channel_id)),
                },
            ),
            map(parse_protocol_header, AMQPFrame::ProtocolHeader),
        )),
    )(i)
}

/// Parse a raw AMQP frame
pub fn parse_raw_frame<I: ParsableInput>(i: I) -> ParserResult<I, AMQPRawFrame<I>> {
    context(
        "parse_raw_frame",
        flat_map(
            tuple((parse_frame_type, parse_id, parse_long_uint)),
            move |(frame_type, channel_id, size)| {
                map(
                    pair(take(size), tag(&[constants::FRAME_END][..])),
                    move |(payload, _)| AMQPRawFrame {
                        frame_type,
                        channel_id,
                        payload,
                    },
                )
            },
        ),
    )(i)
}

/// Parse a content header frame
pub fn parse_content_header<I: ParsableInput>(i: I) -> ParserResult<I, AMQPContentHeader> {
    context(
        "parse_content_header",
        map(
            tuple((
                parse_id,
                parse_short_uint,
                parse_long_long_uint,
                context("parse_properties", parse_properties),
            )),
            |(class_id, weight, body_size, properties)| AMQPContentHeader {
                class_id,
                weight,
                body_size,
                properties,
            },
        ),
    )(i)
}

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

    #[test]
    fn test_protocol_header() {
        assert_eq!(parse_frame(&['A' as u8, 'M' as u8, 'Q' as u8, 'P' as u8, 0, 0, 9, 1][..]), Ok((&[][..], AMQPFrame::ProtocolHeader(ProtocolVersion::amqp_0_9_1()))));
    }

    #[test]
    fn test_heartbeat() {
        assert_eq!(parse_frame(&[8, 0, 1, 0, 0, 0, 0, 206][..]), Ok((&[][..], AMQPFrame::Heartbeat(1))));
    }
}
<|endoftext|>


<commit_before>use types::{OscPacket, OscType, Result, OscMessage, OscMidiMessage, OscColor, OscBundle};
use errors::OscError;
use utils;

use std::{io, char};
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> Result<OscPacket> {
    if msg.len() == 0 {
        return Err(OscError::BadPacket("Empty packet."));
    }

    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.")),
    }
}

fn decode_message(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let bundle_tag = try!(read_osc_string(&mut cursor));
    if bundle_tag != "#bundle" {
        return Err(OscError::BadBundle(format!("Wrong bundle specifier: {}", bundle_tag)));
    }

    let time_tag = try!(read_time_tag(&mut cursor));
    let mut bundle: Vec<OscPacket> = Vec::new();
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut buf: Vec<u8> = Vec::with_capacity(size);
    let cnt: usize = try!(cursor.take(size as u64)
                                .read_to_end(&mut buf)
                                .map_err(OscError::ReadError));
    if cnt == size {
        try!(decode(&mut buf).map(|p| bundle.push(p)));
    } else {
        return Err(OscError::BadBundle("Bundle shorter than expected!".to_string()));
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> Result<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> Result<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        let arg: OscType = try!(read_osc_arg(cursor, tag));
        args.push(arg);
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> Result<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(OscType::Float)
                  .map_err(OscError::ByteOrderError)
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(OscType::Double)
                  .map_err(OscError::ByteOrderError)
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(OscType::Int)
                  .map_err(OscError::ByteOrderError)
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(OscType::Long)
                  .map_err(OscError::ByteOrderError)
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            read_time_tag(cursor)
        }
        'b' => {
            read_blob(cursor)
        }
        'r' => {
            read_osc_color(cursor)
        }
        'T' => {
            Ok(OscType::Bool(true))
        }
        'F' => {
            Ok(OscType::Bool(false))
        }
        'N' => {
            Ok(OscType::Nil)
        }
        'I' => {
            Ok(OscType::Inf)
        }
        'c' => {
            read_char(cursor)
        }
        'm' => {
            read_midi_message(cursor)
        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_char(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let opt_char = try!(cursor.read_u32::<BigEndian>()
                              .map(char::from_u32)
                              .map_err(OscError::ByteOrderError));
    match opt_char {
        Some(c) => Ok(OscType::Char(c)),
        None => Err(OscError::BadArg("Argument is not a char!".to_string())),
    }
}

fn read_blob(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut byte_buf: Vec<u8> = Vec::with_capacity(size);

    try!(cursor.take(size as u64)
               .read_to_end(&mut byte_buf)
               .map_err(OscError::ReadError));

    pad_cursor(cursor);

    Ok(OscType::Blob(byte_buf))
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let date = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));
    let frac = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));

    Ok(OscType::Time(date, frac))
}

fn read_midi_message(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Midi(OscMidiMessage {
        port: buf[0],
        status: buf[1],
        data1: buf[2],
        data2: buf[3],
    }))

}

fn read_osc_color(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Color(OscColor {
        red: buf[0],
        green: buf[1],
        blue: buf[2],
        alpha: buf[3],
    }))
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<commit_msg>Fix bundle decoding<commit_after>use types::{OscPacket, OscType, Result, OscMessage, OscMidiMessage, OscColor, OscBundle};
use errors::OscError;
use utils;

use std::{io, char};
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> Result<OscPacket> {
    if msg.len() == 0 {
        return Err(OscError::BadPacket("Empty packet."));
    }

    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.")),
    }
}

fn decode_message(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> Result<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let bundle_tag = try!(read_osc_string(&mut cursor));
    if bundle_tag != "#bundle" {
        return Err(OscError::BadBundle(format!("Wrong bundle specifier: {}", bundle_tag)));
    }

    let time_tag = try!(read_time_tag(&mut cursor));
    let mut bundle: Vec<OscPacket> = Vec::new();

    let mut elem_size = try!(read_bundle_element_size(&mut cursor));

    while msg.len() >= (cursor.position() as usize) + elem_size {
        let packet = try!(read_bundle_element(&mut cursor, elem_size));
        bundle.push(packet);

        if msg.len() == cursor.position() as usize {
            break;
        }

        elem_size = try!(read_bundle_element_size(&mut cursor));
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_bundle_element_size(cursor: &mut io::Cursor<&[u8]>) -> Result<usize> {
    cursor.read_u32::<BigEndian>()
          .map(|size| size as usize)
          .map_err(OscError::ByteOrderError)
}

fn read_bundle_element(cursor: &mut io::Cursor<&[u8]>, elem_size: usize) -> Result<OscPacket> {
    let mut buf: Vec<u8> = Vec::with_capacity(elem_size);

    let mut handle = cursor.take(elem_size as u64);

    let cnt = try!(handle.read_to_end(&mut buf)
                         .map_err(OscError::ReadError));

    if cnt == elem_size {
        decode(&mut buf)
    } else {
        return Err(OscError::BadBundle("Bundle shorter than expected!".to_string()));
    }
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> Result<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> Result<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        let arg: OscType = try!(read_osc_arg(cursor, tag));
        args.push(arg);
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> Result<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(OscType::Float)
                  .map_err(OscError::ByteOrderError)
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(OscType::Double)
                  .map_err(OscError::ByteOrderError)
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(OscType::Int)
                  .map_err(OscError::ByteOrderError)
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(OscType::Long)
                  .map_err(OscError::ByteOrderError)
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            read_time_tag(cursor)
        }
        'b' => {
            read_blob(cursor)
        }
        'r' => {
            read_osc_color(cursor)
        }
        'T' => {
            Ok(OscType::Bool(true))
        }
        'F' => {
            Ok(OscType::Bool(false))
        }
        'N' => {
            Ok(OscType::Nil)
        }
        'I' => {
            Ok(OscType::Inf)
        }
        'c' => {
            read_char(cursor)
        }
        'm' => {
            read_midi_message(cursor)
        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_char(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let opt_char = try!(cursor.read_u32::<BigEndian>()
                              .map(char::from_u32)
                              .map_err(OscError::ByteOrderError));
    match opt_char {
        Some(c) => Ok(OscType::Char(c)),
        None => Err(OscError::BadArg("Argument is not a char!".to_string())),
    }
}

fn read_blob(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut byte_buf: Vec<u8> = Vec::with_capacity(size);

    try!(cursor.take(size as u64)
               .read_to_end(&mut byte_buf)
               .map_err(OscError::ReadError));

    pad_cursor(cursor);

    Ok(OscType::Blob(byte_buf))
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let date = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));
    let frac = try!(cursor.read_u32::<BigEndian>()
                          .map_err(OscError::ByteOrderError));

    Ok(OscType::Time(date, frac))
}

fn read_midi_message(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Midi(OscMidiMessage {
        port: buf[0],
        status: buf[1],
        data1: buf[2],
        data2: buf[3],
    }))

}

fn read_osc_color(cursor: &mut io::Cursor<&[u8]>) -> Result<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Color(OscColor {
        red: buf[0],
        green: buf[1],
        blue: buf[2],
        alpha: buf[3],
    }))
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<|endoftext|>


<commit_before>use ast::*;
use buffered_iterator::*;
use scanning::*;

struct Parser<'a> {
	scanner: BufferedIterator<Token, Scanner<'a>>,
}

impl<'a> Parser<'a> {

	fn new(input: &String) -> Parser {
		let scanner = Scanner::new(input);
		let buf = BufferedIterator::new(scanner);

		Parser {
			scanner: buf
		}
	}

	fn get_token(&mut self) -> Option<Token> {
		return self.scanner.pop()
	}

	fn put_token(&mut self, t: Token) {
		self.scanner.push(t)
	}

	fn parse_ast(&mut self) -> Option<Ast> {
		trace!("parse_ast");

		if let Some(cmd) = self.parse_command() {
			return Some(Ast::Command(cmd));
		}

		if let Some(expr) = self.parse_expression() {
			return Some(Ast::Expression(expr));
		}

		return None;
	}

	fn parse_command(&mut self) -> Option<Command> {
		trace!("parse_command");

		let t = unwrap!(self.get_token(), {
			return None;
		});

		if let Token { token_type: TokenType::Identifier { ref str, .. }, .. } = t {
			match str.as_str() {
				"exit" | "quit" => return Some(Command::Exit),
				_ => {
					println!("Unexpected identifier '{}'", str);
					return None
				}
			}
		}

		self.put_token(t);

		return None
	} // parse_command

	fn parse_expression(&mut self) -> Option<Expression> {
		trace!("parse_expression");

		return self.parse_term();
	}

	fn parse_term(&mut self) -> Option<Expression> {
		trace!("parse_term");

		let mut expr = unwrap!(self.parse_factor(), {
			println!("Unexpected end of input @ {}:{}", file!(), line!());
			return None;
		});

		while let Some(t) = self.get_token() {
			let op;
			match t.token_type {
				TokenType::Plus => op = BinaryOp::Plus,
				TokenType::Minus => op = BinaryOp::Minus,
				_ => {
					self.put_token(t);
					break;
				}
			}

			if let Some(right) = self.parse_factor() {
				expr = Expression::Binary(Binary {
					left: Box::new(expr),
					op: op,
					right: Box::new(right)
				})
			} else {
				println!("Unexpected end of input @ {}:{}", file!(), line!());
				break;
			}
		}

		return Some(expr);
	}

	fn parse_factor(&mut self) -> Option<Expression> {
		trace!("parse_factor");

		let mut expr = unwrap!(self.parse_exponent(), {
			println!("Unexpected end of input @ {}:{}", file!(), line!());
			return None;
		});

		while let Some(t) = self.get_token() {
			let op;
			match t.token_type {
				TokenType::Star => op = BinaryOp::Multiply,
				TokenType::ForwardSlash => op = BinaryOp::Divide,
				_ => {
					self.put_token(t);
					break;
				}
			}

			if let Some(right) = self.parse_exponent() {
				expr = Expression::Binary(Binary {
					left: Box::new(expr),
					op: op,
					right: Box::new(right)
				});
			} else {
				println!("Unexpected end of input @ {}:{}", file!(), line!());
				break;
			}
		}

		return Some(expr);
	} // parse_factor

	fn parse_exponent(&mut self) -> Option<Expression> {
		trace!("parse_exponent");

		let mut expr = unwrap!(self.parse_unary(), {
			println!("Unexpected end of input @ {}:{}", file!(), line!());
			return None;
		});

		while let Some(t) = self.get_token() {
			let op;
			match t.token_type {
				TokenType::Caret => op = BinaryOp::Exponent,
				TokenType::StarStar => op = BinaryOp::Exponent,
				_ => {
					self.put_token(t);
					break;
				}
			}

			if let Some(right) = self.parse_unary() {
				expr = Expression::Binary(Binary {
					left: Box::new(expr),
					op: op,
					right: Box::new(right)
				});
			} else {
				println!("Unexpected end of input @ {}:{}", file!(), line!());
				break;
			}
		}

		return Some(expr);
	} // parse_exponent

	fn parse_unary(&mut self) -> Option<Expression> {
		trace!("parse_unary");

		let t = unwrap!(self.get_token(), {
			println!("Unexpected end of input @ {}:{}", file!(), line!());
			return None;
		});

		let op;
		match t.token_type {
			TokenType::Minus => op = UnaryOp::Negate,
			_ => {
				self.put_token(t);
				return self.parse_primary();
			}
		}

		return match self.parse_unary() {
			Some(right) => Some(Expression::Unary(Unary {
				op: op,
				right: Box::new(right)
			})),
			None => {
				println!("Unexpected end of input @ {}:{}", file!(), line!());
				None
			}
		};
	} // parse_unary

	fn parse_primary(&mut self) -> Option<Expression> {
		trace!("parse_primary");

		let t = unwrap!(self.get_token(), {
			println!("Unexpected end of input @ {}:{}", file!(), line!());
			return None;
		});

		return match t.token_type {
			TokenType::Number { str } => {
				match str.parse::<f64>() {
					Ok(f) => Some(Expression::Literal(Literal::Number(f))),
					Err(msg) => {
						println!("{}", msg);
						None
					}
				}
			},
			TokenType::LeftParen => {
				let expr = self.parse_expression();
				match self.get_token() {
					Some(Token { token_type: TokenType::RightParen, .. }) => return expr,
					Some(t) => {
						println!("Expected token RightParen, but found '{:?}' (line {}, col {})",
							t.token_type, t.line, t.column);
						return None;
					},
					None => {
						println!("Unexpected end of input @ {}:{}", file!(), line!());
						return None;
					},
				}
			},
			_ => {
				println!("Unexpected token '{:?}' (line {}, col {})",
					t.token_type, t.line, t.column);
				None
			}
		} // match
	} // parse_primary
} // Parser

pub fn parse<'a>(input: &'a String) -> Option<Ast> {
	Parser::new(input).parse_ast()
}
<commit_msg>Reduce the number of 'unexpected end of input' messages<commit_after>use ast::*;
use buffered_iterator::*;
use scanning::*;

struct Parser<'a> {
	scanner: BufferedIterator<Token, Scanner<'a>>,
}

impl<'a> Parser<'a> {

	fn new(input: &String) -> Parser {
		let scanner = Scanner::new(input);
		let buf = BufferedIterator::new(scanner);

		Parser {
			scanner: buf
		}
	}

	fn get_token(&mut self) -> Option<Token> {
		return self.scanner.pop()
	}

	fn put_token(&mut self, t: Token) {
		self.scanner.push(t)
	}

	fn expect_token(&mut self) -> Option<Token> {
		return match self.get_token() {
			Some(t) => Some(t),
			None => {
				println!("Unexpected end of input");
				None
			}
		}
	}

	fn parse_ast(&mut self) -> Option<Ast> {
		trace!("parse_ast");

		if let Some(cmd) = self.parse_command() {
			return Some(Ast::Command(cmd));
		}

		if let Some(expr) = self.parse_expression() {
			return Some(Ast::Expression(expr));
		}

		return None;
	}

	fn parse_command(&mut self) -> Option<Command> {
		trace!("parse_command");

		let t = unwrap!(self.get_token(), {
			return None;
		});

		if let Token { token_type: TokenType::Identifier { ref str, .. }, .. } = t {
			match str.as_str() {
				"exit" | "quit" => return Some(Command::Exit),
				_ => {
					println!("Unexpected identifier '{}'", str);
					return None
				}
			}
		}

		self.put_token(t);

		return None
	} // parse_command

	fn parse_expression(&mut self) -> Option<Expression> {
		trace!("parse_expression");

		return self.parse_term();
	}

	fn parse_term(&mut self) -> Option<Expression> {
		trace!("parse_term");

		let mut expr = unwrap!(self.parse_factor(), {
			return None;
		});

		while let Some(t) = self.get_token() {
			let op;
			match t.token_type {
				TokenType::Plus => op = BinaryOp::Plus,
				TokenType::Minus => op = BinaryOp::Minus,
				_ => {
					self.put_token(t);
					break;
				}
			}

			let right = unwrap!(self.parse_factor(), {
				break;
			});

			expr = Expression::Binary(Binary {
				left: Box::new(expr),
				op: op,
				right: Box::new(right)
			});
		} // while

		return Some(expr);
	}

	fn parse_factor(&mut self) -> Option<Expression> {
		trace!("parse_factor");

		let mut expr = unwrap!(self.parse_exponent(), {
			return None;
		});

		while let Some(t) = self.get_token() {
			let op;
			match t.token_type {
				TokenType::Star => op = BinaryOp::Multiply,
				TokenType::ForwardSlash => op = BinaryOp::Divide,
				_ => {
					self.put_token(t);
					break;
				}
			}

			let right = unwrap!(self.parse_exponent(), {
				break;
			});

			expr = Expression::Binary(Binary {
				left: Box::new(expr),
				op: op,
				right: Box::new(right)
			});
		} // while

		return Some(expr);
	} // parse_factor

	fn parse_exponent(&mut self) -> Option<Expression> {
		trace!("parse_exponent");

		let mut expr = unwrap!(self.parse_unary(), {
			return None;
		});

		while let Some(t) = self.get_token() {
			let op;
			match t.token_type {
				TokenType::Caret => op = BinaryOp::Exponent,
				TokenType::StarStar => op = BinaryOp::Exponent,
				_ => {
					self.put_token(t);
					break;
				}
			}

			let right = unwrap!(self.parse_unary(), {
				break;
			});

			expr = Expression::Binary(Binary {
				left: Box::new(expr),
				op: op,
				right: Box::new(right)
			});
		} // while

		return Some(expr);
	} // parse_exponent

	fn parse_unary(&mut self) -> Option<Expression> {
		trace!("parse_unary");

		let t = unwrap!(self.expect_token(), {
			return None;
		});

		let op;
		match t.token_type {
			TokenType::Minus => op = UnaryOp::Negate,
			_ => {
				self.put_token(t);
				return self.parse_primary();
			}
		}

		return match self.parse_unary() {
			Some(right) => Some(Expression::Unary(Unary {
				op: op,
				right: Box::new(right)
			})),
			None => None,
		};
	} // parse_unary

	fn parse_primary(&mut self) -> Option<Expression> {
		trace!("parse_primary");

		let t = unwrap!(self.expect_token(), {
			return None;
		});

		return match t.token_type {
			TokenType::Number { str } => {
				match str.parse::<f64>() {
					Ok(f) => Some(Expression::Literal(Literal::Number(f))),
					Err(msg) => {
						println!("{}", msg);
						None
					}
				}
			},
			TokenType::LeftParen => {
				let expr = self.parse_expression();
				match self.expect_token() {
					Some(Token { token_type: TokenType::RightParen, .. }) => expr,
					Some(t) => {
						println!("Expected token RightParen, but found '{:?}' (line {}, col {})",
							t.token_type, t.line, t.column);
						None
					},
					None => None,
				}
			},
			_ => {
				println!("Unexpected token '{:?}' (line {}, col {})",
					t.token_type, t.line, t.column);
				None
			}
		} // match
	} // parse_primary
} // Parser

pub fn parse<'a>(input: &'a String) -> Option<Ast> {
	Parser::new(input).parse_ast()
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for serializing the dep-graph and reloading it.

#![crate_name = "rustc_incremental"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]
#![cfg_attr(not(stage0), deny(warnings))]

#![feature(rustc_private)]
#![feature(staged_api)]

extern crate graphviz;
extern crate rbml;
extern crate rustc;
extern crate rustc_data_structures;
extern crate serialize as rustc_serialize;

#[macro_use] extern crate log;
#[macro_use] extern crate syntax;

mod assert_dep_graph;
mod calculate_svh;
mod persist;

pub use assert_dep_graph::assert_dep_graph;
pub use calculate_svh::SvhCalculate;
pub use persist::load_dep_graph;
pub use persist::save_dep_graph;
<commit_msg>rebase: get `bug!` macro<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Support for serializing the dep-graph and reloading it.

#![crate_name = "rustc_incremental"]
#![unstable(feature = "rustc_private", issue = "27812")]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]
#![cfg_attr(not(stage0), deny(warnings))]

#![feature(rustc_private)]
#![feature(staged_api)]

extern crate graphviz;
extern crate rbml;
#[macro_use] extern crate rustc;
extern crate rustc_data_structures;
extern crate serialize as rustc_serialize;

#[macro_use] extern crate log;
#[macro_use] extern crate syntax;

mod assert_dep_graph;
mod calculate_svh;
mod persist;

pub use assert_dep_graph::assert_dep_graph;
pub use calculate_svh::SvhCalculate;
pub use persist::load_dep_graph;
pub use persist::save_dep_graph;
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{self, Read, BufRead, BufReader};
use num_complex::Complex64;
use nalgebra_sparse::coo::CooMatrix;

#[derive(Clone, Debug)]
enum DataType {
    Real(Vec<f64>),
    Complex(Vec<Complex64>),
    Integer(Vec<isize>),
}

pub struct MatrixMarketReader {
    rows: usize,
    cols: usize,
    //data: DataType,
}

fn filename_to_string(s: &str) -> io::Result<String> {
    let mut file = File::open(s).expect("file not found");
    let mut s = String::new();
    file.read_to_string(&mut s)?;
    Ok(s)
}

fn words_by_line<'a>(s: &'a str) -> Vec<Vec<&'a str>> {
    s.lines().map(|line| { line.split_whitespace().collect() }).collect()
}

impl MatrixMarketReader {
    pub fn new(fname: &str) -> Result<Self, String> {
        //let file = File::open(fname).expect("file not found!");
        //let mut f = BufReader::new(file);
        let whole_file = filename_to_string(fname).unwrap();
        let wbyl = &words_by_line(&whole_file);
        let mm_header = &wbyl[0];
        let (banner, mtx, coord, dtype, storage) = (mm_header[0],
                                                    mm_header[1],
                                                    mm_header[2],
                                                    mm_header[3],
                                                    mm_header[4]);
        //if banner.ne("%%MatrixMarket") { panic!("no banner"); }
        if banner.ne("%%MatrixMarket") { return Err(String::from("no banner")); }
        if mtx.ne("matrix") { return Err(String::from("not a matrix")); }
        let is_symmetric = match storage {
                             "symmetric" => true,
                             "general"   => false,
                              _          => return Err(String::from("unsupported storage type"))};
        let is_sparse = match coord {
                          "coordinate"   => true,
                          "array"        => false,
                           _             => return Err(String::from("unsupported coordinate type"))};
        let mut data : DataType = match dtype {
                           "real"        => DataType::Real(Vec::new()),
                           "complex"     => DataType::Complex(Vec::new()),
                           "integer"     => DataType::Integer(Vec::new()),
                           _             => return Err(String::from("unsupported data type"))};

        //let mut (rows, cols, nnz) = (0, 0, 0)
        let mut rows = 0;
        let mut cols = 0;
        let mut nnz  = 0;
        let mut row = Vec::<usize>::new();
        let mut col = Vec::<usize>::new();
        for words in wbyl {
            if words[0].starts_with('%') { // skip comments that starts with %
                //println!("words: {:?}", words);
            } else {
                // read triples, the 1st one contains (rows, cols, nnz) the others - (i, j, val)
                macro_rules! parse_word {
                    ($t:ty, $i:expr) => {
                        words[$i].parse::<$t>().unwrap()
                    };
                    ($i:expr) => { // `$t` defaulted to `i32`
                        parse_word!(isize, $i)
                    };
                }
                let parse_vals = move |data: DataType, i: usize| match data {
                    DataType::Real(mut v)    => { v.push(parse_word!(f64,   i));
                                                  DataType::Real(v)},
                    DataType::Integer(mut v) => { v.push(parse_word!(isize, i));
                                                  DataType::Integer(v)},
                    DataType::Complex(mut v) => { v.push(Complex64::new(parse_word!(f64, i),
                                                                        parse_word!(f64, i + 1)));
                                                  DataType::Complex(v)},
                };
                if rows == 0 {
                    rows = parse_word!(0);
                    cols = parse_word!(1);
                    nnz  = parse_word!(2);
                    if is_symmetric { nnz *= 2; }

                    //println!("rows: {} cols: {} nnz: {}", rows, cols, nnz);
                } else {
                    let x = parse_word!(0);
                    let y = parse_word!(1);
                    //let v: f64 = parse_word!(f64, 2);
                    data = parse_vals(data, 2);
                    //println!("x: {} y: {} v: {:10.4e}", x, y, v);
                }
            }
            //println!("words: {:?}", words);
        }

        println!("wbyl[0]: {:?}", mm_header);
        println!("data: {:?}", data);
        Ok(Self { rows: rows as usize, cols: cols as usize, /*data: data,*/ })
    }
}

fn use_it(fname: &str) {
    let mm = MatrixMarketReader::new("xxx");
}

<commit_msg>reserve space for Vecs<commit_after>use std::fs::File;
use std::io::{self, Read, BufRead};
use num_complex::Complex64;
use nalgebra_sparse::coo::CooMatrix;

#[derive(Clone, Debug)]
enum DataType {
    Real(Vec<f64>),
    Complex(Vec<Complex64>),
    Integer(Vec<isize>),
}

pub struct MatrixMarketReader {
    rows: usize,
    cols: usize,
    row: Vec<usize>,
    col: Vec<usize>,
    data: DataType,
}

fn filename_to_string(s: &str) -> io::Result<String> {
    let mut file = File::open(s).expect("file not found");
    let mut s = String::new();
    file.read_to_string(&mut s)?;
    Ok(s)
}

fn words_by_line<'a>(s: &'a str) -> Vec<Vec<&'a str>> {
    s.lines().map(|line| { line.split_whitespace().collect() }).collect()
}

impl MatrixMarketReader {
    pub fn new(fname: &str) -> Result<Self, String> {
        let whole_file = filename_to_string(fname).unwrap();
        let wbyl = &words_by_line(&whole_file);
        let mm_header = &wbyl[0];
        let (banner, mtx, coord, dtype, storage) = (mm_header[0],
                                                    mm_header[1],
                                                    mm_header[2],
                                                    mm_header[3],
                                                    mm_header[4]);
        if banner.ne("%%MatrixMarket") { return Err(String::from("no banner")); }
        if mtx.ne("matrix") { return Err(String::from("not a matrix")); }
        let is_symmetric = match storage {
                             "symmetric" => true,
                             "general"   => false,
                              _          => return Err(String::from("unsupported storage type"))};
        let is_sparse = match coord {
                          "coordinate"   => true,
                          "array"        => false,
                           _             => return Err(String::from("unsupported coordinate type"))};
        let mut data : DataType = match dtype {
                           "real"        => DataType::Real(Vec::new()),
                           "complex"     => DataType::Complex(Vec::new()),
                           "integer"     => DataType::Integer(Vec::new()),
                           _             => return Err(String::from("unsupported data type"))};

        let mut rows = 0usize;
        let mut cols = 0usize;
        let mut nnz  = 0usize;
        let mut row = Vec::<usize>::new();
        let mut col = Vec::<usize>::new();
        for words in wbyl {
            if words[0].starts_with('%') { // skip comments that starts with %
                //println!("words: {:?}", words);
            } else {
                // read triples, the 1st one contains (rows, cols, nnz) the others - (i, j, val)
                macro_rules! parse_word {
                    ($t:ty, $i:expr) => {
                        words[$i].parse::<$t>().unwrap()
                    };
                    ($i:expr) => { // `$t` defaulted to `i32`
                        parse_word!(usize, $i)
                    };
                }
                let reserve_data_vals = move |data: DataType, nnz: usize| match data {
                    DataType::Real(mut v)    => { v.reserve(nnz); DataType::Real(v)},
                    DataType::Integer(mut v) => { v.reserve(nnz); DataType::Integer(v)},
                    DataType::Complex(mut v) => { v.reserve(nnz); DataType::Complex(v)},
                };
                let parse_data_vals = move |data: DataType, i: usize| match data {
                    DataType::Real(mut v)    => { v.push(parse_word!(f64,   i));
                                                  DataType::Real(v)},
                    DataType::Integer(mut v) => { v.push(parse_word!(isize, i));
                                                  DataType::Integer(v)},
                    DataType::Complex(mut v) => { v.push(Complex64::new(parse_word!(f64, i),
                                                                        parse_word!(f64, i + 1)));
                                                  DataType::Complex(v)},
                };
                if rows == 0 {
                    rows = parse_word!(0);
                    cols = parse_word!(1);
                    nnz  = parse_word!(2);
                    if is_symmetric { nnz *= 2; }
                    row.reserve(nnz);
                    col.reserve(nnz);
                    data = reserve_data_vals(data, nnz);
                    //println!("rows: {} cols: {} nnz: {}", rows, cols, nnz);
                } else {
                    let x = parse_word!(0);
                    let y = parse_word!(1);
                    row.push(x);
                    col.push(y);
                    data = parse_data_vals(data, 2);
                    //println!("x: {} y: {} v: {:10.4e}", x, y, v);
                }
            }
            //println!("words: {:?}", words);
        }

        println!("wbyl[0]: {:?}", mm_header);
        //println!("data: {:?}", data);
        Ok(Self { rows: rows, cols: cols, row: row, col: col, data: data, })
    }
}

fn use_it(fname: &str) {
    let mm = MatrixMarketReader::new("xxx");
}

<|endoftext|>