<commit_before>extern crate dns_parser;
extern crate resolv_conf;

use std::time::{Duration, Instant};
use std::io::{self, Read};
use std::fs::File;
use std::net::{IpAddr, SocketAddr, UdpSocket};
use std::collections::HashMap;

pub struct Resolver {
    server: SocketAddr,
    cache: HashMap<String, CacheEntry>,
    queries: HashMap<u16, Query>,
    responses: HashMap<String, Vec<usize>>,
    buf: Vec<u8>,
    qnum: u16,
}

struct Query {
    resps: u8,
    domain: String,
    deadline: Instant,
}

struct CacheEntry {
    ip: IpAddr,
    deadline: Instant,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Response {
    pub id: usize,
    pub result: Result<IpAddr, Error>,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Error {
    NotFound,
    Timeout,
}

impl Resolver {
    pub fn new(server: SocketAddr) -> Resolver {
        let mut buf = Vec::with_capacity(512);
        unsafe {
            buf.set_len(512);
        }
        Resolver {
            server,
            queries: HashMap::new(),
            responses: HashMap::new(),
            cache: HashMap::new(),
            buf,
            qnum: 0,
        }
    }

    pub fn purge(&mut self) {
        self.cache.clear();
    }

    pub fn from_resolv() -> io::Result<Resolver> {
        let mut buf = Vec::with_capacity(512);
        unsafe {
            buf.set_len(512);
        }

        let mut conf = Vec::with_capacity(4096);
        let mut f = File::open("/etc/resolv.conf")?;
        f.read_to_end(&mut conf)?;
        let cfg = resolv_conf::Config::parse(&conf).map_err(|e| {
            io::Error::new(io::ErrorKind::Other, format!("invalid resolv.conf: {}", e))
        })?;
        let server = match cfg.nameservers.first().cloned() {
            Some(resolv_conf::ScopedIp::V4(ip)) => SocketAddr::new(IpAddr::V4(ip), 53),
            Some(resolv_conf::ScopedIp::V6(ip, _)) => SocketAddr::new(IpAddr::V6(ip), 53),
            None => {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    "No nameservers found in resolv.conf!",
                ))
            }
        };

        Ok(Resolver {
            server,
            queries: HashMap::new(),
            responses: HashMap::new(),
            cache: HashMap::new(),
            buf,
            qnum: 0,
        })
    }

    pub fn query(
        &mut self,
        sock: &mut UdpSocket,
        id: usize,
        domain: &str,
    ) -> io::Result<Option<IpAddr>> {
        if let Some(entry) = self.cache.get(domain) {
            return Ok(Some(entry.ip));
        }
        if self.responses.get(domain).is_none() {
            let qn = self.qnum;
            self.qnum.wrapping_add(1);
            let mut query = dns_parser::Builder::new_query(qn, true);
            query.add_question(domain, dns_parser::QueryType::A, dns_parser::QueryClass::IN);
            let packet = query.build().unwrap_or_else(|d| d);
            sock.send_to(&packet, self.server)?;

            let mut query = dns_parser::Builder::new_query(qn, true);
            query.add_question(
                domain,
                dns_parser::QueryType::AAAA,
                dns_parser::QueryClass::IN,
            );
            let packet = query.build().unwrap_or_else(|d| d);
            sock.send_to(&packet, self.server)?;

            self.responses.insert(domain.to_string(), vec![]);
            self.queries.insert(
                qn,
                Query {
                    resps: 0,
                    domain: domain.to_string(),
                    deadline: Instant::now() + Duration::from_secs(3),
                },
            );
        }
        self.responses.get_mut(domain).unwrap().push(id);
        Ok(None)
    }

    pub fn read<F: FnMut(Response)>(&mut self, sock: &mut UdpSocket, mut f: F) -> io::Result<()> {
        'process: loop {
            match sock.recv_from(&mut self.buf) {
                Ok((amnt, _)) => {
                    match dns_parser::Packet::parse(&self.buf[..amnt]) {
                        Ok(packet) => {
                            let qn = packet.header.id;
                            let (domain, mut resps, deadline) = match self.queries.remove(&qn) {
                                Some(q) => (q.domain, q.resps, q.deadline),
                                // This could happen if timeout is exceeeded but we eventually get
                                // a response, ignore.
                                None => continue,
                            };
                            let now = Instant::now();
                            for answer in packet.answers {
                                match answer.data {
                                    dns_parser::RRData::A(addr) => {
                                        for id in self.responses.remove(&domain).unwrap() {
                                            f(Response {
                                                id,
                                                result: Ok(addr.into()),
                                            });
                                        }
                                        self.cache.insert(
                                            domain,
                                            CacheEntry {
                                                ip: addr.into(),
                                                deadline: now
                                                    + Duration::from_secs(answer.ttl.into()),
                                            },
                                        );
                                        continue 'process;
                                    }
                                    dns_parser::RRData::AAAA(addr) => {
                                        for id in self.responses.remove(&domain).unwrap() {
                                            f(Response {
                                                id,
                                                result: Ok(addr.into()),
                                            });
                                        }
                                        self.cache.insert(
                                            domain,
                                            CacheEntry {
                                                ip: addr.into(),
                                                deadline: now
                                                    + Duration::from_secs(answer.ttl.into()),
                                            },
                                        );
                                        continue 'process;
                                    }
                                    _ => continue,
                                }
                            }
                            if resps == 0 {
                                self.queries.insert(
                                    qn,
                                    Query {
                                        domain,
                                        resps: resps + 1,
                                        deadline,
                                    },
                                );
                            } else {
                                for id in self.responses.remove(&domain).unwrap() {
                                    f(Response {
                                        id,
                                        result: Err(Error::NotFound),
                                    });
                                }
                            }
                        }
                        Err(e) => {
                            return Err(io::Error::new(
                                io::ErrorKind::Other,
                                format!("malformed dns packet received: {}", e),
                            ));
                        }
                    }
                }
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => return Ok(()),
                Err(e) => return Err(e),
            }
        }
    }

    pub fn tick<F: FnMut(Response)>(&mut self, mut f: F) {
        let now = Instant::now();
        let responses = &mut self.responses;
        self.queries.retain(|_, query| {
            if now > query.deadline {
                for id in responses.remove(&query.domain).unwrap() {
                    f(Response {
                        id,
                        result: Err(Error::Timeout),
                    });
                }
                false
            } else {
                true
            }
        });
        self.cache.retain(|_, entry| now < entry.deadline);
    }
}

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

    #[test]
    fn test_google() {
        let mut resolver = Resolver::new("8.8.8.8:53".parse().unwrap());
        let mut sock = UdpSocket::bind("0.0.0.0:0").unwrap();
        sock.set_nonblocking(true).unwrap();

        assert_eq!(resolver.query(&mut sock, 0, "google.com").unwrap(), None);
        assert_eq!(resolver.query(&mut sock, 1, "google.com").unwrap(), None);
        assert_eq!(resolver.responses.get("google.com").unwrap().len(), 2);
        std::thread::sleep(Duration::from_millis(100));
        resolver.tick(|_| panic!("timeout should not have occured yet!"));
        let mut count = 0;
        resolver
            .read(&mut sock, |resp| {
                count += 1;
                assert!(resp.result.is_ok());
            })
            .unwrap();
        assert_eq!(count, 2);

        assert!(
            resolver
                .query(&mut sock, 0, "google.com")
                .unwrap()
                .is_some()
        );

        resolver
            .query(&mut sock, 0, "thiswebsiteshouldexit12589t69.com")
            .unwrap();
        std::thread::sleep(Duration::from_millis(200));
        let mut processed = false;
        resolver
            .read(&mut sock, |resp| {
                processed = true;
                assert_eq!(resp.result, Err(Error::NotFound))
            })
            .unwrap();
        #[cfg(not(target_os = "macos"))]
        assert!(processed);
    }
}
<commit_msg>Resolve IP addresses immediately<commit_after>extern crate dns_parser;
extern crate resolv_conf;

use std::time::{Duration, Instant};
use std::io::{self, Read};
use std::fs::File;
use std::net::{IpAddr, SocketAddr, UdpSocket};
use std::collections::HashMap;

pub struct Resolver {
    server: SocketAddr,
    cache: HashMap<String, CacheEntry>,
    queries: HashMap<u16, Query>,
    responses: HashMap<String, Vec<usize>>,
    buf: Vec<u8>,
    qnum: u16,
}

struct Query {
    resps: u8,
    domain: String,
    deadline: Instant,
}

struct CacheEntry {
    ip: IpAddr,
    deadline: Instant,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Response {
    pub id: usize,
    pub result: Result<IpAddr, Error>,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Error {
    NotFound,
    Timeout,
}

impl Resolver {
    pub fn new(server: SocketAddr) -> Resolver {
        let mut buf = Vec::with_capacity(512);
        unsafe {
            buf.set_len(512);
        }
        Resolver {
            server,
            queries: HashMap::new(),
            responses: HashMap::new(),
            cache: HashMap::new(),
            buf,
            qnum: 0,
        }
    }

    pub fn purge(&mut self) {
        self.cache.clear();
    }

    pub fn from_resolv() -> io::Result<Resolver> {
        let mut buf = Vec::with_capacity(512);
        unsafe {
            buf.set_len(512);
        }

        let mut conf = Vec::with_capacity(4096);
        let mut f = File::open("/etc/resolv.conf")?;
        f.read_to_end(&mut conf)?;
        let cfg = resolv_conf::Config::parse(&conf).map_err(|e| {
            io::Error::new(io::ErrorKind::Other, format!("invalid resolv.conf: {}", e))
        })?;
        let server = match cfg.nameservers.first().cloned() {
            Some(resolv_conf::ScopedIp::V4(ip)) => SocketAddr::new(IpAddr::V4(ip), 53),
            Some(resolv_conf::ScopedIp::V6(ip, _)) => SocketAddr::new(IpAddr::V6(ip), 53),
            None => {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    "No nameservers found in resolv.conf!",
                ))
            }
        };

        Ok(Resolver {
            server,
            queries: HashMap::new(),
            responses: HashMap::new(),
            cache: HashMap::new(),
            buf,
            qnum: 0,
        })
    }

    pub fn query(
        &mut self,
        sock: &mut UdpSocket,
        id: usize,
        domain: &str,
    ) -> io::Result<Option<IpAddr>> {
        if let Some(entry) = self.cache.get(domain) {
            return Ok(Some(entry.ip));
        }
        if let Ok(entry) = domain.parse() {
            return Ok(Some(entry));
        }
        if self.responses.get(domain).is_none() {
            let qn = self.qnum;
            self.qnum.wrapping_add(1);
            let mut query = dns_parser::Builder::new_query(qn, true);
            query.add_question(domain, dns_parser::QueryType::A, dns_parser::QueryClass::IN);
            let packet = query.build().unwrap_or_else(|d| d);
            sock.send_to(&packet, self.server)?;

            let mut query = dns_parser::Builder::new_query(qn, true);
            query.add_question(
                domain,
                dns_parser::QueryType::AAAA,
                dns_parser::QueryClass::IN,
            );
            let packet = query.build().unwrap_or_else(|d| d);
            sock.send_to(&packet, self.server)?;

            self.responses.insert(domain.to_string(), vec![]);
            self.queries.insert(
                qn,
                Query {
                    resps: 0,
                    domain: domain.to_string(),
                    deadline: Instant::now() + Duration::from_secs(3),
                },
            );
        }
        self.responses.get_mut(domain).unwrap().push(id);
        Ok(None)
    }

    pub fn read<F: FnMut(Response)>(&mut self, sock: &mut UdpSocket, mut f: F) -> io::Result<()> {
        'process: loop {
            match sock.recv_from(&mut self.buf) {
                Ok((amnt, _)) => {
                    match dns_parser::Packet::parse(&self.buf[..amnt]) {
                        Ok(packet) => {
                            let qn = packet.header.id;
                            let (domain, mut resps, deadline) = match self.queries.remove(&qn) {
                                Some(q) => (q.domain, q.resps, q.deadline),
                                // This could happen if timeout is exceeeded but we eventually get
                                // a response, ignore.
                                None => continue,
                            };
                            let now = Instant::now();
                            for answer in packet.answers {
                                match answer.data {
                                    dns_parser::RRData::A(addr) => {
                                        for id in self.responses.remove(&domain).unwrap() {
                                            f(Response {
                                                id,
                                                result: Ok(addr.into()),
                                            });
                                        }
                                        self.cache.insert(
                                            domain,
                                            CacheEntry {
                                                ip: addr.into(),
                                                deadline: now
                                                    + Duration::from_secs(answer.ttl.into()),
                                            },
                                        );
                                        continue 'process;
                                    }
                                    dns_parser::RRData::AAAA(addr) => {
                                        for id in self.responses.remove(&domain).unwrap() {
                                            f(Response {
                                                id,
                                                result: Ok(addr.into()),
                                            });
                                        }
                                        self.cache.insert(
                                            domain,
                                            CacheEntry {
                                                ip: addr.into(),
                                                deadline: now
                                                    + Duration::from_secs(answer.ttl.into()),
                                            },
                                        );
                                        continue 'process;
                                    }
                                    _ => continue,
                                }
                            }
                            if resps == 0 {
                                self.queries.insert(
                                    qn,
                                    Query {
                                        domain,
                                        resps: resps + 1,
                                        deadline,
                                    },
                                );
                            } else {
                                for id in self.responses.remove(&domain).unwrap() {
                                    f(Response {
                                        id,
                                        result: Err(Error::NotFound),
                                    });
                                }
                            }
                        }
                        Err(e) => {
                            return Err(io::Error::new(
                                io::ErrorKind::Other,
                                format!("malformed dns packet received: {}", e),
                            ));
                        }
                    }
                }
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => return Ok(()),
                Err(e) => return Err(e),
            }
        }
    }

    pub fn tick<F: FnMut(Response)>(&mut self, mut f: F) {
        let now = Instant::now();
        let responses = &mut self.responses;
        self.queries.retain(|_, query| {
            if now > query.deadline {
                for id in responses.remove(&query.domain).unwrap() {
                    f(Response {
                        id,
                        result: Err(Error::Timeout),
                    });
                }
                false
            } else {
                true
            }
        });
        self.cache.retain(|_, entry| now < entry.deadline);
    }
}

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

    #[test]
    fn test_google() {
        let mut resolver = Resolver::new("8.8.8.8:53".parse().unwrap());
        let mut sock = UdpSocket::bind("0.0.0.0:0").unwrap();
        sock.set_nonblocking(true).unwrap();

        assert_eq!(resolver.query(&mut sock, 0, "google.com").unwrap(), None);
        assert_eq!(resolver.query(&mut sock, 1, "google.com").unwrap(), None);
        assert_eq!(resolver.responses.get("google.com").unwrap().len(), 2);
        std::thread::sleep(Duration::from_millis(100));
        resolver.tick(|_| panic!("timeout should not have occured yet!"));
        let mut count = 0;
        resolver
            .read(&mut sock, |resp| {
                count += 1;
                assert!(resp.result.is_ok());
            })
            .unwrap();
        assert_eq!(count, 2);

        assert!(
            resolver
                .query(&mut sock, 0, "google.com")
                .unwrap()
                .is_some()
        );

        resolver
            .query(&mut sock, 0, "thiswebsiteshouldexit12589t69.com")
            .unwrap();
        std::thread::sleep(Duration::from_millis(200));
        let mut processed = false;
        resolver
            .read(&mut sock, |resp| {
                processed = true;
                assert_eq!(resp.result, Err(Error::NotFound))
            })
            .unwrap();
        #[cfg(not(target_os = "macos"))]
        assert!(processed);
    }
}
<|endoftext|>


<commit_before>/// Simple ivf muxer
///

use bitstream_io::{BitWriter, LittleEndian};
use std::io;

pub fn write_ivf_header(
  output_file: &mut dyn io::Write, width: usize, height: usize,
  framerate_num: usize,
  framerate_den: usize
) {
  let mut bw = BitWriter::endian(output_file, LittleEndian);
  bw.write_bytes(b"DKIF").unwrap();
  bw.write(16, 0).unwrap(); // version
  bw.write(16, 32).unwrap(); // version
  bw.write_bytes(b"AV01").unwrap();
  bw.write(16, width as u16).unwrap();
  bw.write(16, height as u16).unwrap();
  bw.write(32, framerate_num as u32).unwrap();
  bw.write(32, framerate_den as u32).unwrap();
  bw.write(32, 0).unwrap();
  bw.write(32, 0).unwrap();
}

pub fn write_ivf_frame(
  output_file: &mut dyn io::Write, pts: u64, data: &[u8]
) {
  let mut bw = BitWriter::endian(output_file, LittleEndian);
  bw.write(32, data.len() as u32).unwrap();
  bw.write(64, pts).unwrap();
  bw.write_bytes(data).unwrap();
}
<commit_msg>Add a ivf reader<commit_after>/// Simple ivf muxer
///

use bitstream_io::{BitReader, BitWriter, LittleEndian};
use std::io;

pub fn write_ivf_header(
  output_file: &mut dyn io::Write, width: usize, height: usize,
  framerate_num: usize,
  framerate_den: usize
) {
  let mut bw = BitWriter::endian(output_file, LittleEndian);
  bw.write_bytes(b"DKIF").unwrap();
  bw.write(16, 0).unwrap(); // version
  bw.write(16, 32).unwrap(); // version
  bw.write_bytes(b"AV01").unwrap();
  bw.write(16, width as u16).unwrap();
  bw.write(16, height as u16).unwrap();
  bw.write(32, framerate_num as u32).unwrap();
  bw.write(32, framerate_den as u32).unwrap();
  bw.write(32, 0).unwrap();
  bw.write(32, 0).unwrap();
}

pub fn write_ivf_frame(
  output_file: &mut dyn io::Write, pts: u64, data: &[u8]
) {
  let mut bw = BitWriter::endian(output_file, LittleEndian);
  bw.write(32, data.len() as u32).unwrap();
  bw.write(64, pts).unwrap();
  bw.write_bytes(data).unwrap();
}

#[derive(Debug, PartialEq)]
pub struct Header {
  pub tag: [u8; 4],
  pub w: u16,
  pub h: u16,
  pub timebase_num: u32,
  pub timebase_den: u32
}

pub fn read_header(r: &mut dyn io::Read) -> io::Result<Header> {
  let mut br = BitReader::endian(r, LittleEndian);

  let mut signature = [0u8; 4];
  let mut tag = [0u8; 4];

  br.read_bytes(&mut signature)?;

  if &signature != b"DKIF" {
    return Err(io::ErrorKind::InvalidData.into())
  }

  let _v0: u16 = br.read(16)?;
  let _v1: u16 = br.read(16)?;
  br.read_bytes(&mut tag)?;

  let w: u16 = br.read(16)?;
  let h: u16 = br.read(16)?;

  let timebase_den: u32 = br.read(32)?;
  let timebase_num: u32 = br.read(32)?;

  let _: u32 = br.read(32)?;
  let _: u32 = br.read(32)?;

  Ok(Header { tag, w, h, timebase_num, timebase_den })
}

pub struct Packet {
  pub data: Box<[u8]>,
  pub pts: u64
}

pub fn read_packet(r: &mut dyn io::Read) -> io::Result<Packet> {
  let mut br = BitReader::endian(r, LittleEndian);

  let len: u32 = br.read(32)?;
  let pts: u64 = br.read(64)?;
  let mut buf = vec![0u8; len as usize];

  br.read_bytes(&mut buf)?;

  Ok(Packet { data: buf.into_boxed_slice(), pts })
}
<|endoftext|>


<commit_before>//! # crateinfo
//!
//! Loads crate information.
//!

#[cfg(test)]
#[path = "crateinfo_test.rs"]
mod crateinfo_test;

use crate::types::{CrateDependency, CrateInfo};
use cargo_metadata::camino::Utf8PathBuf;
use cargo_metadata::MetadataCommand;
use fsio;
use glob::glob;
use std::env;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};

fn expand_glob_members(glob_member: &str) -> Vec<String> {
    match glob(glob_member) {
        Ok(entries) => {
            let mut members = vec![];

            for entry in entries {
                match entry {
                    Ok(path) => {
                        let mut updated_path = path.to_str().unwrap().to_string();
                        updated_path = updated_path.replace("\\", "/");
                        members.push(updated_path);
                    }
                    _ => (),
                };
            }

            members
        }
        _ => vec![],
    }
}

fn normalize_members(crate_info: &mut CrateInfo) {
    match crate_info.workspace {
        Some(ref mut workspace) => {
            match workspace.members {
                Some(ref mut members) => {
                    let existing_members = members.clone();

                    let mut index = 0;
                    for member in existing_members.iter() {
                        // glob
                        if member.contains("*") {
                            let mut expanded_members = expand_glob_members(&member);

                            members.remove(index);
                            members.append(&mut expanded_members);
                        } else {
                            index = index + 1;
                        }
                    }
                }
                None => (),
            };
        }
        None => (), //not a workspace
    }
}

fn get_members_from_dependencies(crate_info: &CrateInfo) -> Vec<String> {
    let mut members = vec![];

    match crate_info.dependencies {
        Some(ref dependencies) => {
            for value in dependencies.values() {
                match *value {
                    CrateDependency::Info(ref info) => match info.path {
                        Some(ref path) => {
                            if path.starts_with("./") {
                                let member_path =
                                    path.chars().skip(2).take(path.len() - 2).collect();
                                members.push(member_path);
                            }
                        }
                        None => (),
                    },
                    _ => (),
                };
            }
        }
        None => (),
    };

    members
}

fn add_members(crate_info: &mut CrateInfo, new_members: Vec<String>) {
    if new_members.len() > 0 {
        match crate_info.workspace {
            Some(ref mut workspace) => match workspace.members {
                Some(ref mut members) => {
                    for new_member in new_members.iter() {
                        let member_string = new_member.to_string();

                        match members.iter().position(|member| *member == member_string) {
                            None => members.push(member_string),
                            _ => (),
                        }
                    }
                }
                None => workspace.members = Some(new_members),
            },
            None => (), //not a workspace
        }
    }
}

fn remove_excludes(crate_info: &mut CrateInfo) -> bool {
    let mut removed = false;

    match crate_info.workspace {
        Some(ref mut workspace) => match workspace.exclude {
            Some(ref excludes) => match workspace.members {
                Some(ref mut members) => {
                    for exclude in excludes.iter() {
                        let exclude_string = exclude.to_string();

                        let result = members.iter().position(|member| *member == exclude_string);
                        match result {
                            Some(index) => {
                                members.remove(index);

                                removed = true;

                                ()
                            }
                            None => (),
                        };
                    }
                }
                None => (),
            },
            None => (),
        },
        None => (), //not a workspace
    };

    removed
}

fn load_workspace_members(crate_info: &mut CrateInfo) {
    if crate_info.workspace.is_some() {
        normalize_members(crate_info);

        let dependencies = get_members_from_dependencies(&crate_info);

        add_members(crate_info, dependencies);

        remove_excludes(crate_info);
    }
}

/// Loads the crate info based on the Cargo.toml found in the current working directory.
pub(crate) fn load() -> CrateInfo {
    load_from(Path::new("Cargo.toml").to_path_buf())
}

pub(crate) fn load_from(file_path: PathBuf) -> CrateInfo {
    if file_path.exists() {
        debug!("Reading file: {:#?}", &file_path);
        let crate_info_string = match fsio::file::read_text_file(&file_path) {
            Ok(content) => content,
            Err(error) => panic!("Unable to open Cargo.toml, error: {}", error),
        };

        let mut crate_info: CrateInfo = match toml::from_str(&crate_info_string) {
            Ok(value) => value,
            Err(error) => panic!("Unable to parse Cargo.toml, {}", error),
        };

        load_workspace_members(&mut crate_info);

        debug!("Loaded Cargo.toml: {:#?}", &crate_info);

        crate_info
    } else {
        CrateInfo::new()
    }
}

#[derive(Debug, Deserialize)]
struct CargoConfig {
    build: Option<CargoConfigBuild>,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "kebab-case")]
struct CargoConfigBuild {
    target: Option<RustTarget>,
    target_dir: Option<PathBuf>,
}

#[derive(Debug, Deserialize)]
#[serde(from = "PathBuf")]
struct RustTarget(PathBuf);

impl RustTarget {
    fn name(&self) -> &str {
        self.0.file_stem().unwrap().to_str().unwrap()
    }
}

impl From<PathBuf> for RustTarget {
    fn from(buf: PathBuf) -> Self {
        Self(buf)
    }
}

impl AsRef<OsStr> for RustTarget {
    fn as_ref(&self) -> &OsStr {
        self.0.as_ref()
    }
}

fn get_cargo_config(home: Option<PathBuf>) -> Option<CargoConfig> {
    let path = env::current_dir().ok()?;

    let config_file = path
        .ancestors()
        .map(|ancestor| ancestor.join(".cargo"))
        .chain(home)
        .map(|config_file| config_file.join("config"))
        .filter_map(|config_file| {
            let config_file_with_extension = config_file.with_extension("toml");

            if config_file.exists() {
                Some(config_file)
            } else if config_file_with_extension.exists() {
                Some(config_file_with_extension)
            } else {
                None
            }
        })
        .next()?;

    let config_file = fsio::file::read_text_file(&config_file).ok()?;
    toml::from_str(&config_file).ok()
}

pub(crate) fn crate_target_triple(
    default_target_triple: Option<String>,
    home: Option<PathBuf>,
) -> Option<String> {
    get_cargo_config(home)
        .and_then(|config| config.build)
        .and_then(|build| build.target)
        .map(|target| target.name().to_string())
        .or(default_target_triple)
}

#[derive(Debug, PartialEq, Eq)]
pub(crate) struct CrateTargetDirs {
    pub(crate) host: Utf8PathBuf,
    pub(crate) custom: Option<Utf8PathBuf>,
}

pub(crate) fn crate_target_dirs(home: Option<PathBuf>) -> CrateTargetDirs {
    let metadata = MetadataCommand::new()
        .exec()
        .map_err(|err| debug!("Unable to extract cargo metadata, error: {}", err))
        .ok();
    let host = metadata
        .map(|metadata| metadata.target_directory)
        .unwrap_or_else(|| "target".into());
    let custom = get_cargo_config(home)
        .and_then(|config| config.build)
        .and_then(|build| build.target)
        .map(|target_triple| host.join(target_triple.name()));
    CrateTargetDirs { host, custom }
}

pub(crate) fn search_workspace_root() -> Option<String> {
    if envmnt::is("CARGO_MAKE_WORKSPACE_EMULATION") {
        search_workspace_root_for_emulation()
    } else {
        search_workspace_root_via_metadata()
    }
}

fn search_workspace_root_for_emulation() -> Option<String> {
    let path_value = envmnt::get_any(
        &vec![
            "CARGO_MAKE_WORKSPACE_EMULATION_ROOT_DIRECTORY",
            "CARGO_MAKE_WORKING_DIRECTORY",
        ],
        "",
    );

    if path_value.is_empty() {
        None
    } else {
        Some(path_value)
    }
}

fn search_workspace_root_via_metadata() -> Option<String> {
    debug!("Getting cargo metadata.");

    MetadataCommand::new()
        .exec()
        .map(|metadata| metadata.workspace_root.to_string())
        .map_err(|err| debug!("Unable to extract cargo metadata, error: {:#?}", err))
        .ok()
}
<commit_msg>remove dead code<commit_after>//! # crateinfo
//!
//! Loads crate information.
//!

#[cfg(test)]
#[path = "crateinfo_test.rs"]
mod crateinfo_test;

use crate::types::{CrateDependency, CrateInfo};
use cargo_metadata::camino::Utf8PathBuf;
use cargo_metadata::MetadataCommand;
use fsio;
use glob::glob;
use std::env;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};

fn expand_glob_members(glob_member: &str) -> Vec<String> {
    match glob(glob_member) {
        Ok(entries) => {
            let mut members = vec![];

            for entry in entries {
                match entry {
                    Ok(path) => {
                        let mut updated_path = path.to_str().unwrap().to_string();
                        updated_path = updated_path.replace("\\", "/");
                        members.push(updated_path);
                    }
                    _ => (),
                };
            }

            members
        }
        _ => vec![],
    }
}

fn normalize_members(crate_info: &mut CrateInfo) {
    match crate_info.workspace {
        Some(ref mut workspace) => {
            match workspace.members {
                Some(ref mut members) => {
                    let existing_members = members.clone();

                    let mut index = 0;
                    for member in existing_members.iter() {
                        // glob
                        if member.contains("*") {
                            let mut expanded_members = expand_glob_members(&member);

                            members.remove(index);
                            members.append(&mut expanded_members);
                        } else {
                            index = index + 1;
                        }
                    }
                }
                None => (),
            };
        }
        None => (), //not a workspace
    }
}

fn get_members_from_dependencies(crate_info: &CrateInfo) -> Vec<String> {
    let mut members = vec![];

    match crate_info.dependencies {
        Some(ref dependencies) => {
            for value in dependencies.values() {
                match *value {
                    CrateDependency::Info(ref info) => match info.path {
                        Some(ref path) => {
                            if path.starts_with("./") {
                                let member_path =
                                    path.chars().skip(2).take(path.len() - 2).collect();
                                members.push(member_path);
                            }
                        }
                        None => (),
                    },
                    _ => (),
                };
            }
        }
        None => (),
    };

    members
}

fn add_members(crate_info: &mut CrateInfo, new_members: Vec<String>) {
    if new_members.len() > 0 {
        match crate_info.workspace {
            Some(ref mut workspace) => match workspace.members {
                Some(ref mut members) => {
                    for new_member in new_members.iter() {
                        let member_string = new_member.to_string();

                        match members.iter().position(|member| *member == member_string) {
                            None => members.push(member_string),
                            _ => (),
                        }
                    }
                }
                None => workspace.members = Some(new_members),
            },
            None => (), //not a workspace
        }
    }
}

fn remove_excludes(crate_info: &mut CrateInfo) -> bool {
    let mut removed = false;

    match crate_info.workspace {
        Some(ref mut workspace) => match workspace.exclude {
            Some(ref excludes) => match workspace.members {
                Some(ref mut members) => {
                    for exclude in excludes.iter() {
                        let exclude_string = exclude.to_string();

                        let result = members.iter().position(|member| *member == exclude_string);
                        match result {
                            Some(index) => {
                                members.remove(index);

                                removed = true;

                                ()
                            }
                            None => (),
                        };
                    }
                }
                None => (),
            },
            None => (),
        },
        None => (), //not a workspace
    };

    removed
}

fn load_workspace_members(crate_info: &mut CrateInfo) {
    if crate_info.workspace.is_some() {
        normalize_members(crate_info);

        let dependencies = get_members_from_dependencies(&crate_info);

        add_members(crate_info, dependencies);

        remove_excludes(crate_info);
    }
}

/// Loads the crate info based on the Cargo.toml found in the current working directory.
pub(crate) fn load() -> CrateInfo {
    load_from(Path::new("Cargo.toml").to_path_buf())
}

pub(crate) fn load_from(file_path: PathBuf) -> CrateInfo {
    if file_path.exists() {
        debug!("Reading file: {:#?}", &file_path);
        let crate_info_string = match fsio::file::read_text_file(&file_path) {
            Ok(content) => content,
            Err(error) => panic!("Unable to open Cargo.toml, error: {}", error),
        };

        let mut crate_info: CrateInfo = match toml::from_str(&crate_info_string) {
            Ok(value) => value,
            Err(error) => panic!("Unable to parse Cargo.toml, {}", error),
        };

        load_workspace_members(&mut crate_info);

        debug!("Loaded Cargo.toml: {:#?}", &crate_info);

        crate_info
    } else {
        CrateInfo::new()
    }
}

#[derive(Debug, Deserialize)]
struct CargoConfig {
    build: Option<CargoConfigBuild>,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "kebab-case")]
struct CargoConfigBuild {
    target: Option<RustTarget>,
}

#[derive(Debug, Deserialize)]
#[serde(from = "PathBuf")]
struct RustTarget(PathBuf);

impl RustTarget {
    fn name(&self) -> &str {
        self.0.file_stem().unwrap().to_str().unwrap()
    }
}

impl From<PathBuf> for RustTarget {
    fn from(buf: PathBuf) -> Self {
        Self(buf)
    }
}

impl AsRef<OsStr> for RustTarget {
    fn as_ref(&self) -> &OsStr {
        self.0.as_ref()
    }
}

fn get_cargo_config(home: Option<PathBuf>) -> Option<CargoConfig> {
    let path = env::current_dir().ok()?;

    let config_file = path
        .ancestors()
        .map(|ancestor| ancestor.join(".cargo"))
        .chain(home)
        .map(|config_file| config_file.join("config"))
        .filter_map(|config_file| {
            let config_file_with_extension = config_file.with_extension("toml");

            if config_file.exists() {
                Some(config_file)
            } else if config_file_with_extension.exists() {
                Some(config_file_with_extension)
            } else {
                None
            }
        })
        .next()?;

    let config_file = fsio::file::read_text_file(&config_file).ok()?;
    toml::from_str(&config_file).ok()
}

pub(crate) fn crate_target_triple(
    default_target_triple: Option<String>,
    home: Option<PathBuf>,
) -> Option<String> {
    get_cargo_config(home)
        .and_then(|config| config.build)
        .and_then(|build| build.target)
        .map(|target| target.name().to_string())
        .or(default_target_triple)
}

#[derive(Debug, PartialEq, Eq)]
pub(crate) struct CrateTargetDirs {
    pub(crate) host: Utf8PathBuf,
    pub(crate) custom: Option<Utf8PathBuf>,
}

pub(crate) fn crate_target_dirs(home: Option<PathBuf>) -> CrateTargetDirs {
    let metadata = MetadataCommand::new()
        .exec()
        .map_err(|err| debug!("Unable to extract cargo metadata, error: {}", err))
        .ok();
    let host = metadata
        .map(|metadata| metadata.target_directory)
        .unwrap_or_else(|| "target".into());
    let custom = get_cargo_config(home)
        .and_then(|config| config.build)
        .and_then(|build| build.target)
        .map(|target_triple| host.join(target_triple.name()));
    CrateTargetDirs { host, custom }
}

pub(crate) fn search_workspace_root() -> Option<String> {
    if envmnt::is("CARGO_MAKE_WORKSPACE_EMULATION") {
        search_workspace_root_for_emulation()
    } else {
        search_workspace_root_via_metadata()
    }
}

fn search_workspace_root_for_emulation() -> Option<String> {
    let path_value = envmnt::get_any(
        &vec![
            "CARGO_MAKE_WORKSPACE_EMULATION_ROOT_DIRECTORY",
            "CARGO_MAKE_WORKING_DIRECTORY",
        ],
        "",
    );

    if path_value.is_empty() {
        None
    } else {
        Some(path_value)
    }
}

fn search_workspace_root_via_metadata() -> Option<String> {
    debug!("Getting cargo metadata.");

    MetadataCommand::new()
        .exec()
        .map(|metadata| metadata.workspace_root.to_string())
        .map_err(|err| debug!("Unable to extract cargo metadata, error: {:#?}", err))
        .ok()
}
<|endoftext|>


<commit_before>use exonum::crypto::Hash;

storage_value! {
/// Represents transaction. If `execution_status` equals to `true`, then the transaction
/// was successful.
    struct TxMetaRecord {
        const SIZE = 33;

        field tx_hash:                &Hash  [00 => 32]
        field execution_status:       bool   [32 => 33]
    }
}

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

    #[derive(Serialize)]
    struct TxMetaRecordTestData {
        json: TxMetaRecord,
        hash: Hash,
        raw: Vec<u8>,
    }

    impl TxMetaRecordTestData {
        fn new(data: TxMetaRecord) -> TxMetaRecordTestData {
            let hash = data.hash();
            let raw = StorageValue::serialize(data.clone());
            TxMetaRecordTestData {
                json: data,
                hash: hash,
                raw: raw,
            }
        }
    }

    #[test]
    fn test_tx_meta_record() {
        let hash = Hash::new([2; 32]);
        let status = false;
        let datum = TxMetaRecord::new(&hash, status);

        let datum = datum.clone();
        assert_eq!(datum.tx_hash(), &hash);
        assert_eq!(datum.execution_status(), status);
    }

    #[test]
    fn test_tx_meta_record_serde() {
        use serde_json;
        use rand::{thread_rng, Rng};
        use exonum::crypto::HASH_SIZE;

        let mut rng = thread_rng();
        let generator = move |_| {
            let mut hash_bytes = [0; HASH_SIZE];
            rng.fill_bytes(&mut hash_bytes);
            let hash = Hash::new(hash_bytes);
            let status = rng.gen_weighted_bool(2);
            TxMetaRecord::new(&hash, status)
        };
        let data = (0..50).map(generator).collect::<Vec<_>>();
        for datum in data {
            let json_str = serde_json::to_string(&datum).unwrap();
            let datum_round_trip: TxMetaRecord = serde_json::from_str(&json_str).unwrap();
            assert_eq!(datum, datum_round_trip);
            println!("TxMetaRecord test data: {}",
                     serde_json::to_string(&TxMetaRecordTestData::new(datum)).unwrap());
        }
    }
}<commit_msg>Fix code formatting<commit_after>use exonum::crypto::Hash;

storage_value! {
/// Represents transaction. If `execution_status` equals to `true`, then the transaction
/// was successful.
    struct TxMetaRecord {
        const SIZE = 33;

        field tx_hash:                &Hash  [00 => 32]
        field execution_status:       bool   [32 => 33]
    }
}

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

    #[derive(Serialize)]
    struct TxMetaRecordTestData {
        json: TxMetaRecord,
        hash: Hash,
        raw: Vec<u8>,
    }

    impl TxMetaRecordTestData {
        fn new(data: TxMetaRecord) -> TxMetaRecordTestData {
            let hash = data.hash();
            let raw = StorageValue::serialize(data.clone());
            TxMetaRecordTestData {
                json: data,
                hash: hash,
                raw: raw,
            }
        }
    }

    #[test]
    fn test_tx_meta_record() {
        let hash = Hash::new([2; 32]);
        let status = false;
        let datum = TxMetaRecord::new(&hash, status);

        let datum = datum.clone();
        assert_eq!(datum.tx_hash(), &hash);
        assert_eq!(datum.execution_status(), status);
    }

    #[test]
    fn test_tx_meta_record_serde() {
        use serde_json;
        use rand::{thread_rng, Rng};
        use exonum::crypto::HASH_SIZE;

        let mut rng = thread_rng();
        let generator = move |_| {
            let mut hash_bytes = [0; HASH_SIZE];
            rng.fill_bytes(&mut hash_bytes);
            let hash = Hash::new(hash_bytes);
            let status = rng.gen_weighted_bool(2);
            TxMetaRecord::new(&hash, status)
        };
        let data = (0..50).map(generator).collect::<Vec<_>>();
        for datum in data {
            let json_str = serde_json::to_string(&datum).unwrap();
            let datum_round_trip: TxMetaRecord = serde_json::from_str(&json_str).unwrap();
            assert_eq!(datum, datum_round_trip);
            println!("TxMetaRecord test data: {}",
                     serde_json::to_string(&TxMetaRecordTestData::new(datum)).unwrap());
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Added print example. Ended at example - http://rustbyexample.com/hello/print/print_debug.html<commit_after><|endoftext|>


<commit_before>/*
 * Implemenation of a bitfield as a vec. Only
 * supports bytes (Vec<u8>) as the underlying
 * storage.
 *
 * A future implementation should be more efficient,
 * this is just to get the job done for now.
 */
extern crate ssz;

use std::cmp::max;

#[derive(Eq, Clone, Default, Debug)]
pub struct BooleanBitfield{
    len: usize,
    vec: Vec<u8>
}

impl BooleanBitfield {
    /// Create a new bitfield with a length of zero.
    pub fn new() -> Self {
        Self {
            len: 0,
            vec: vec![0]
        }
    }

    /// Create a new bitfield of a certain capacity
    pub fn with_capacity(capacity: usize) -> Self {
        let mut vec = Vec::with_capacity(capacity / 8 + 1);
        vec.push(0);
        Self {
            len: 0,
            vec
        }
    }

    /// Read the value of a bit.
    ///
    /// Will return `true` if the bit has been set to `true`
    /// without then being set to `False`.
    pub fn get_bit(&self, i: usize) -> bool {
        let bit = |i: usize| i % 8;
        let byte = |i: usize| i / 8;

        if byte(i) >= self.vec.len() {
            false
        } else {
             self.vec[byte(i)] & (1 << (bit(i) as u8)) != 0
        }
    }

    /// Set the value of a bit.
    ///
    /// If this bit is larger than the length of the underlying byte
    /// array it will be extended.
    pub fn set_bit(&mut self, i: usize, to: bool) {
        let bit = |i: usize| i % 8;
        let byte = |i: usize| i / 8;

        self.len = max(self.len, i + 1);

        if byte(i) >= self.vec.len() {
            self.vec.resize(byte(i) + 1, 0);
        }
        if to {
            self.vec[byte(i)] =
                self.vec[byte(i)] |  (1 << (bit(i) as u8))
        } else {
            self.vec[byte(i)] =
                self.vec[byte(i)] & !(1 << (bit(i) as u8))
        }
    }

    /// Return the "length" of this bitfield. Length is defined as
    /// the highest bit that has been set.
    ///
    /// Note: this is distinct from the length of the underlying
    /// vector.
    pub fn len(&self) -> usize { self.len }

    /// True if no bits have ever been set. A bit that is set and then
    /// unset will still count to the length of the bitfield.
    ///
    /// Note: this is distinct from the length of the underlying
    /// vector.
    pub fn is_empty(&self) -> bool { self.len == 0 }

    /// The number of bytes required to represent the bitfield.
    pub fn num_bytes(&self) -> usize { self.vec.len() }

    /// Iterate through the underlying vector and count the number of
    /// true bits.
    pub fn num_true_bits(&self) -> u64 {
        let mut count: u64 = 0;
        for byte in &self.vec {
            for bit in 0..8 {
                if byte & (1 << (bit as u8)) != 0 {
                    count += 1;
                }
            }
        }
        count
    }

    /// Iterate through the underlying vector and find the highest
    /// set bit. Useful for instantiating a new instance from
    /// some set of bytes.
    pub fn compute_length(bytes: &[u8]) -> usize {
        for byte in (0..bytes.len()).rev() {
            for bit in (0..8).rev() {
                if byte & (1 << (bit as u8)) != 0 {
                    return (byte * 8) + bit
                }
            }
        }
        0
    }

    /// Get the byte at a position, assuming big-endian encoding.
    pub fn get_byte(&self, n: usize) -> Option<&u8> {
        self.vec.get(n)
    }

    /// Clone and return the underlying byte array (`Vec<u8>`).
    pub fn to_be_vec(&self) -> Vec<u8> {
        let mut o = self.vec.clone();
        o.reverse();
        o
    }
}

impl<'a> From<&'a [u8]> for BooleanBitfield {
    fn from(input: &[u8]) -> Self {
        let mut vec = input.to_vec();
        vec.reverse();
        BooleanBitfield {
            vec,
            len: BooleanBitfield::compute_length(input)
        }
    }
}

impl PartialEq for BooleanBitfield {
    fn eq(&self, other: &BooleanBitfield) -> bool {
        (self.vec == other.vec) &
            (self.len == other.len)
    }
}

impl ssz::Encodable for BooleanBitfield {
    fn ssz_append(&self, s: &mut ssz::SszStream) {
        s.append_vec(&self.to_be_vec());
    }
}

impl ssz::Decodable for BooleanBitfield {
    fn ssz_decode(bytes: &[u8], index: usize)
        -> Result<(Self, usize), ssz::DecodeError>
    {
        let len = ssz::decode::decode_length(
            bytes,
            index,
            ssz::LENGTH_BYTES)?;
        if (ssz::LENGTH_BYTES + len) > bytes.len() {
            return Err(ssz::DecodeError::TooShort);
        }
        if len == 0 {
            Ok((BooleanBitfield::new(),
                index + ssz::LENGTH_BYTES))
        } else {
            let b = BooleanBitfield::
                from(&bytes[(index + 4)..(index + len + 4)]);
            let index = index + ssz::LENGTH_BYTES + len;
            Ok((b, index))
        }
    }
}

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

    #[test]
    fn test_ssz_encoding() {
        let mut b = BooleanBitfield::new();
        b.set_bit(8, true);

        let mut stream = ssz::SszStream::new();
        stream.append(&b);

        assert_eq!(stream.drain(), vec![0, 0, 0, 2, 1, 0]);
    }

    #[test]
    fn test_ssz_decoding() {
        /*
         * Correct input
         */
        let input = vec![0, 0, 0, 2, 1, 0];
        let (b, i) = BooleanBitfield::ssz_decode(&input, 0).unwrap();
        assert_eq!(i, 6);
        assert_eq!(b.num_true_bits(), 1);
        assert_eq!(b.get_bit(8), true);

        /*
         * Input too long
         */
        let mut input = vec![0, 0, 0, 2, 1, 0];
        input.push(42);
        let (b, i) = BooleanBitfield::ssz_decode(&input, 0).unwrap();
        assert_eq!(i, 6);
        assert_eq!(b.num_true_bits(), 1);
        assert_eq!(b.get_bit(8), true);

        /*
         * Input too short
         */
        let input = vec![0, 0, 0, 2, 1];
        let res = BooleanBitfield::ssz_decode(&input, 0);
        assert_eq!(res, Err(ssz::DecodeError::TooShort));
    }

    #[test]
    fn test_new_bitfield_len() {
        let b = BooleanBitfield::new();
        assert_eq!(b.len(), 0);
        assert_eq!(b.to_be_vec(), vec![0]);

        let b = BooleanBitfield::with_capacity(100);
        assert_eq!(b.len(), 0);
        assert_eq!(b.to_be_vec(), vec![0]);
    }

    #[test]
    fn test_new_bitfield_len() {
        let b = BooleanBitfield::new();
        assert_eq!(b.len(), 0);
        assert_eq!(b.to_be_vec(), vec![0]);

        let b = BooleanBitfield::with_capacity(100);
        assert_eq!(b.len(), 0);
        assert_eq!(b.to_be_vec(), vec![0]);
    }

    #[test]
    fn test_bitfield_set() {
        let mut b = BooleanBitfield::new();
        b.set_bit(0, false);
        assert_eq!(b.to_be_vec(), [0]);

        b = BooleanBitfield::new();
        b.set_bit(7, true);
        assert_eq!(b.to_be_vec(), [128]);
        b.set_bit(7, false);
        assert_eq!(b.to_be_vec(), [0]);
        assert_eq!(b.len(), 8);

        b = BooleanBitfield::new();
        b.set_bit(7, true);
        b.set_bit(0, true);
        assert_eq!(b.to_be_vec(), [129]);
        b.set_bit(7, false);
        assert_eq!(b.to_be_vec(), [1]);
        assert_eq!(b.len(), 8);

        b = BooleanBitfield::new();
        b.set_bit(8, true);
        assert_eq!(b.to_be_vec(), [1, 0]);
        assert_eq!(b.len(), 9);
        b.set_bit(8, false);
        assert_eq!(b.to_be_vec(), [0, 0]);
        assert_eq!(b.len(), 9);

        b = BooleanBitfield::new();
        b.set_bit(15, true);
        assert_eq!(b.to_be_vec(), [128, 0]);
        b.set_bit(15, false);
        assert_eq!(b.to_be_vec(), [0, 0]);
        assert_eq!(b.len(), 16);

        b = BooleanBitfield::new();
        b.set_bit(8, true);
        b.set_bit(15, true);
        assert_eq!(b.to_be_vec(), [129, 0]);
        b.set_bit(15, false);
        assert_eq!(b.to_be_vec(), [1, 0]);
        assert_eq!(b.len(), 16);
    }

    #[test]
    fn test_bitfield_get() {
        let test_nums = vec![0, 8, 15, 42, 1337];
        for i in test_nums {
            let mut b = BooleanBitfield::new();
            assert_eq!(b.get_bit(i), false);
            b.set_bit(i, true);
            assert_eq!(b.get_bit(i), true);
            b.set_bit(i, true);
        }
    }

    #[test]
    fn test_bitfield_num_true_bits() {
        let mut b = BooleanBitfield::new();
        assert_eq!(b.num_true_bits(), 0);
        b.set_bit(15, true);
        assert_eq!(b.num_true_bits(), 1);
        b.set_bit(15, false);
        assert_eq!(b.num_true_bits(), 0);
        b.set_bit(0, true);
        b.set_bit(7, true);
        b.set_bit(8, true);
        b.set_bit(1337, true);
        assert_eq!(b.num_true_bits(), 4);
    }
}
<commit_msg>Change bitfield serialization to little-endian<commit_after>/*
 * Implemenation of a bitfield as a vec. Only
 * supports bytes (Vec<u8>) as the underlying
 * storage.
 *
 * A future implementation should be more efficient,
 * this is just to get the job done for now.
 */
extern crate ssz;

use std::cmp::max;

#[derive(Eq, Clone, Default, Debug)]
pub struct BooleanBitfield{
    len: usize,
    vec: Vec<u8>
}

impl BooleanBitfield {
    /// Create a new bitfield with a length of zero.
    pub fn new() -> Self {
        Self {
            len: 0,
            vec: vec![0]
        }
    }

    /// Create a new bitfield of a certain capacity
    pub fn with_capacity(capacity: usize) -> Self {
        let mut vec = Vec::with_capacity(capacity / 8 + 1);
        vec.push(0);
        Self {
            len: 0,
            vec
        }
    }

    /// Read the value of a bit.
    ///
    /// Will return `true` if the bit has been set to `true`
    /// without then being set to `False`.
    pub fn get_bit(&self, i: usize) -> bool {
        let bit = |i: usize| i % 8;
        let byte = |i: usize| i / 8;

        if byte(i) >= self.vec.len() {
            false
        } else {
             self.vec[byte(i)] & (1 << (bit(i) as u8)) != 0
        }
    }

    /// Set the value of a bit.
    ///
    /// If this bit is larger than the length of the underlying byte
    /// array it will be extended.
    pub fn set_bit(&mut self, i: usize, to: bool) {
        let bit = |i: usize| i % 8;
        let byte = |i: usize| i / 8;

        self.len = max(self.len, i + 1);

        if byte(i) >= self.vec.len() {
            self.vec.resize(byte(i) + 1, 0);
        }
        if to {
            self.vec[byte(i)] =
                self.vec[byte(i)] |  (1 << (bit(i) as u8))
        } else {
            self.vec[byte(i)] =
                self.vec[byte(i)] & !(1 << (bit(i) as u8))
        }
    }

    /// Return the "length" of this bitfield. Length is defined as
    /// the highest bit that has been set.
    ///
    /// Note: this is distinct from the length of the underlying
    /// vector.
    pub fn len(&self) -> usize { self.len }

    /// True if no bits have ever been set. A bit that is set and then
    /// unset will still count to the length of the bitfield.
    ///
    /// Note: this is distinct from the length of the underlying
    /// vector.
    pub fn is_empty(&self) -> bool { self.len == 0 }

    /// The number of bytes required to represent the bitfield.
    pub fn num_bytes(&self) -> usize { self.vec.len() }

    /// Iterate through the underlying vector and count the number of
    /// true bits.
    pub fn num_true_bits(&self) -> u64 {
        let mut count: u64 = 0;
        for byte in &self.vec {
            for bit in 0..8 {
                if byte & (1 << (bit as u8)) != 0 {
                    count += 1;
                }
            }
        }
        count
    }

    /// Iterate through the underlying vector and find the highest
    /// set bit. Useful for instantiating a new instance from
    /// some set of bytes.
    pub fn compute_length(bytes: &[u8]) -> usize {
        for byte in (0..bytes.len()).rev() {
            for bit in (0..8).rev() {
                if byte & (1 << (bit as u8)) != 0 {
                    return (byte * 8) + bit
                }
            }
        }
        0
    }

    /// Get the byte at a position, assuming big-endian encoding.
    pub fn get_byte(&self, n: usize) -> Option<&u8> {
        self.vec.get(n)
    }

    /// Clone and return the underlying byte array (`Vec<u8>`).
    pub fn to_vec(&self) -> Vec<u8> {
        self.vec.clone()
    }

    /// Clone and return the underlying byte array (`Vec<u8>`) in big-endinan format.
    pub fn to_be_vec(&self) -> Vec<u8> {
        let mut o = self.vec.clone();
        o.reverse();
        o
    }
}

impl<'a> From<&'a [u8]> for BooleanBitfield {
    fn from(input: &[u8]) -> Self {
        let mut vec = input.to_vec();
        vec.reverse();
        BooleanBitfield {
            vec,
            len: BooleanBitfield::compute_length(input)
        }
    }
}

impl PartialEq for BooleanBitfield {
    fn eq(&self, other: &BooleanBitfield) -> bool {
        (self.vec == other.vec) &
            (self.len == other.len)
    }
}

impl ssz::Encodable for BooleanBitfield {
    fn ssz_append(&self, s: &mut ssz::SszStream) {
        s.append_vec(&self.to_vec());
    }
}

impl ssz::Decodable for BooleanBitfield {
    fn ssz_decode(bytes: &[u8], index: usize)
        -> Result<(Self, usize), ssz::DecodeError>
    {
        let len = ssz::decode::decode_length(
            bytes,
            index,
            ssz::LENGTH_BYTES)?;
        if (ssz::LENGTH_BYTES + len) > bytes.len() {
            return Err(ssz::DecodeError::TooShort);
        }
        if len == 0 {
            Ok((BooleanBitfield::new(),
                index + ssz::LENGTH_BYTES))
        } else {
            let b = BooleanBitfield::
                from(&bytes[(index + 4)..(index + len + 4)]);
            let index = index + ssz::LENGTH_BYTES + len;
            Ok((b, index))
        }
    }
}

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

    #[test]
    fn test_ssz_encoding() {
        let mut b = BooleanBitfield::new();
        b.set_bit(8, true);

        let mut stream = ssz::SszStream::new();
        stream.append(&b);

        assert_eq!(stream.drain(), vec![0, 0, 0, 2, 0, 1]);
    }

    #[test]
    fn test_ssz_decoding() {
        /*
         * Correct input
         */
        let input = vec![0, 0, 0, 2, 0, 1];
        let (b, i) = BooleanBitfield::ssz_decode(&input, 0).unwrap();
        assert_eq!(i, 6);
        assert_eq!(b.num_true_bits(), 1);
        assert_eq!(b.get_bit(8), true);

        /*
         * Input too long
         */
        let mut input = vec![0, 0, 0, 2, 0, 1];
        input.push(42);
        let (b, i) = BooleanBitfield::ssz_decode(&input, 0).unwrap();
        assert_eq!(i, 6);
        assert_eq!(b.num_true_bits(), 1);
        assert_eq!(b.get_bit(8), true);

        /*
         * Input too short
         */
        let input = vec![0, 0, 0, 2, 1];
        let res = BooleanBitfield::ssz_decode(&input, 0);
        assert_eq!(res, Err(ssz::DecodeError::TooShort));
    }

    #[test]
    fn test_new_bitfield_len() {
        let b = BooleanBitfield::new();
        assert_eq!(b.len(), 0);
        assert_eq!(b.to_be_vec(), vec![0]);

        let b = BooleanBitfield::with_capacity(100);
        assert_eq!(b.len(), 0);
        assert_eq!(b.to_be_vec(), vec![0]);
    }

    #[test]
    fn test_bitfield_set() {
        let mut b = BooleanBitfield::new();
        b.set_bit(0, false);
        assert_eq!(b.to_be_vec(), [0]);

        b = BooleanBitfield::new();
        b.set_bit(7, true);
        assert_eq!(b.to_be_vec(), [128]);
        b.set_bit(7, false);
        assert_eq!(b.to_be_vec(), [0]);
        assert_eq!(b.len(), 8);

        b = BooleanBitfield::new();
        b.set_bit(7, true);
        b.set_bit(0, true);
        assert_eq!(b.to_be_vec(), [129]);
        b.set_bit(7, false);
        assert_eq!(b.to_be_vec(), [1]);
        assert_eq!(b.len(), 8);

        b = BooleanBitfield::new();
        b.set_bit(8, true);
        assert_eq!(b.to_be_vec(), [1, 0]);
        assert_eq!(b.len(), 9);
        b.set_bit(8, false);
        assert_eq!(b.to_be_vec(), [0, 0]);
        assert_eq!(b.len(), 9);

        b = BooleanBitfield::new();
        b.set_bit(15, true);
        assert_eq!(b.to_be_vec(), [128, 0]);
        b.set_bit(15, false);
        assert_eq!(b.to_be_vec(), [0, 0]);
        assert_eq!(b.len(), 16);

        b = BooleanBitfield::new();
        b.set_bit(8, true);
        b.set_bit(15, true);
        assert_eq!(b.to_be_vec(), [129, 0]);
        b.set_bit(15, false);
        assert_eq!(b.to_be_vec(), [1, 0]);
        assert_eq!(b.len(), 16);
    }

    #[test]
    fn test_bitfield_get() {
        let test_nums = vec![0, 8, 15, 42, 1337];
        for i in test_nums {
            let mut b = BooleanBitfield::new();
            assert_eq!(b.get_bit(i), false);
            b.set_bit(i, true);
            assert_eq!(b.get_bit(i), true);
            b.set_bit(i, true);
        }
    }

    #[test]
    fn test_bitfield_num_true_bits() {
        let mut b = BooleanBitfield::new();
        assert_eq!(b.num_true_bits(), 0);
        b.set_bit(15, true);
        assert_eq!(b.num_true_bits(), 1);
        b.set_bit(15, false);
        assert_eq!(b.num_true_bits(), 0);
        b.set_bit(0, true);
        b.set_bit(7, true);
        b.set_bit(8, true);
        b.set_bit(1337, true);
        assert_eq!(b.num_true_bits(), 4);
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
extern crate webrtc_sdp;

fn main() {
    let filename = match env::args().nth(1) {
        None => {
            println!("Missing file name argument!");
            return;
        }
        Some(x) => x,
    };
    let path = Path::new(filename.as_str());
    let display = path.display();

    let mut file = match File::open(&path) {
        Err(why) => panic!("Failed to open {}: {}", display, why.description()),
        Ok(file) => file,
    };

    let mut s = String::new();
    match file.read_to_string(&mut s) {
        Err(why) => panic!("couldn't read {}: {}", display, why.description()),
        Ok(s) => s,
    };

    assert!(webrtc_sdp::parse_sdp(&s, true).is_ok());
}
<commit_msg>print parser error at the end of example parser client<commit_after>use std::env;
use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
extern crate webrtc_sdp;

fn main() {
    let filename = match env::args().nth(1) {
        None => {
            println!("Missing file name argument!");
            return;
        }
        Some(x) => x,
    };
    let path = Path::new(filename.as_str());
    let display = path.display();

    let mut file = match File::open(&path) {
        Err(why) => panic!("Failed to open {}: {}", display, why.description()),
        Ok(file) => file,
    };

    let mut s = String::new();
    match file.read_to_string(&mut s) {
        Err(why) => panic!("couldn't read {}: {}", display, why.description()),
        Ok(s) => s,
    };

    let res = webrtc_sdp::parse_sdp(&s, true);
    if res.is_ok() {
        println!("successfully parsed SDP.");
    } else {
        println!("FAILURE: {}", res.err().unwrap());
    }
}
<|endoftext|>


<commit_before>use nom::{self, IResult};

use std::str;

pub fn list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

pub fn quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

pub fn resp_specials(c: u8) -> bool {
    c == b']'
}

pub fn atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || list_wildcards(c)
        || quoted_specials(c)
        || resp_specials(c)
}

pub fn atom_char(c: u8) -> bool {
    !atom_specials(c)
}

pub fn astring_char(c: u8) -> bool {
    atom_char(c) || resp_specials(c)
}

pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

named!(pub quoted<&[u8]>, do_parse!(
    tag_s!("\"") >>
    data: quoted_data >>
    tag_s!("\"") >>
    (data)
));

named!(pub literal<&[u8]>, do_parse!(
    tag_s!("{") >>
    len: number >>
    tag_s!("}") >>
    tag_s!("\r\n") >>
    data: take!(len) >>
    (data)
));

named!(pub string<&[u8]>, alt!(quoted | literal));

named!(pub nstring<Option<&[u8]>>, map!(
    alt!(tag_s!("NIL") | string),
    |s| if s == b"NIL" { None } else { Some(s) }
));

named!(pub number<u32>, map_res!(
    map_res!(nom::digit, str::from_utf8),
    str::parse
));

named!(pub number_64<u64>, map_res!(
    map_res!(nom::digit, str::from_utf8),
    str::parse
));

named!(pub atom<&str>, map_res!(take_while1_s!(atom_char),
    str::from_utf8
));

named!(pub astring<&[u8]>, alt!(
    take_while1!(astring_char) |
    string
));

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

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, "XYZ".as_bytes());
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, "text".as_bytes());
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<commit_msg>ABNF definitions from IMAP RFC<commit_after>use nom::{self, IResult};

use std::str;

/// list-wildcards = "%" / "*"
pub fn list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

/// quoted-specials = DQUOTE / "\"
pub fn quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

/// resp-specials = "]"
pub fn resp_specials(c: u8) -> bool {
    c == b']'
}

/// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || list_wildcards(c)
        || quoted_specials(c)
        || resp_specials(c)
}

/// ATOM-CHAR = <any CHAR except atom-specials>
pub fn atom_char(c: u8) -> bool {
    !atom_specials(c)
}

/// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn astring_char(c: u8) -> bool {
    atom_char(c) || resp_specials(c)
}

/// QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

/// quoted = DQUOTE *QUOTED-CHAR DQUOTE
named!(pub quoted<&[u8]>, do_parse!(
    tag_s!("\"") >>
    data: quoted_data >>
    tag_s!("\"") >>
    (data)
));

/// literal = "{" number "}" CRLF *CHAR8
///            ; Number represents the number of CHAR8s
named!(pub literal<&[u8]>, do_parse!(
    tag_s!("{") >>
    len: number >>
    tag_s!("}") >>
    tag_s!("\r\n") >>
    data: take!(len) >>
    (data)
));

/// string = quoted / literal
named!(pub string<&[u8]>, alt!(quoted | literal));

/// nstring = string / nil
named!(pub nstring<Option<&[u8]>>, map!(
    alt!(tag_s!("NIL") | string),
    |s| if s == b"NIL" { None } else { Some(s) }
));

/// number          = 1*DIGIT
///                    ; Unsigned 32-bit integer
///                    ; (0 <= n < 4,294,967,296)
named!(pub number<u32>, map_res!(
    map_res!(nom::digit, str::from_utf8),
    str::parse
));

/// same as `number` but 64-bit
named!(pub number_64<u64>, map_res!(
    map_res!(nom::digit, str::from_utf8),
    str::parse
));

/// atom = 1*ATOM-CHAR
named!(pub atom<&str>, map_res!(take_while1_s!(atom_char),
    str::from_utf8
));

/// astring = 1*ASTRING-CHAR / string
named!(pub astring<&[u8]>, alt!(
    take_while1!(astring_char) |
    string
));

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

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, "XYZ".as_bytes());
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, "text".as_bytes());
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<|endoftext|>


<commit_before>#![crate_id="CSVProvider#0.1-pre"]
#![crate_type="dylib"]

// why doesn't "lib" work?

// rustc 0.11.0-pre (b47f2226a25654c5b781d27a91f2fa5274b3a347 2014-06-28 14:31:37 +0000)

#![feature(globs, macro_rules, quote, managed_boxes, plugin_registrar)]

#![allow(unused_imports)]
#![allow(unused_variable)]

extern crate syntax;
extern crate rustc;

use syntax::ast::{Name,
                  TokenTree,
                  Expr,
                  ExprLit,
                  ExprVec,
                  LitStr,
                  DUMMY_NODE_ID,
                  MutImmutable};
use syntax::codemap::Span;
use syntax::ext::base::{SyntaxExtension,
                        BasicMacroExpander,
                        ExtCtxt,
                        MacResult,
                        MacPat,
                        MacItem,
                        DummyResult,
                        MacExpr,
                        NormalTT};
use std::gc::Gc;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{InternedString, COMMA, EOF};

use std::io;
use std::io::fs;
use std::os;
use std::str;
use std::io::Process;
use syntax::ast;
use syntax::ast::Name;

use syntax::util::small_vector::SmallVector;

use std::collections::HashMap;
use std::gc::{Gc, GC};

use rustc::plugin::Registry;

#[plugin_registrar]
pub fn macro_registrar(reg: &mut Registry) {
    reg.register_macro("ProvideCSV_labels", provide_csv_given_labels);
}

#[deriving(Clone)]
struct Entry {
    str: InternedString,
    expr: Gc<Expr>
}

// see https://github.com/sfackler/syntax-ext-talk/blob/gh-pages/simple-ext/lib.rs
fn parse_entries(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<Vec<Entry>> {
    let mut parser = parse::new_parser_from_tts(
         cx.parse_sess(),
         cx.cfg(),
         tts.iter()
            .map(|x| (*x).clone())
            .collect()
    );

    let mut entries: Vec<Entry> = Vec::new();

    let mut error = false;
    while parser.token != EOF {
        let entry = parser.parse_expr();

        let entry_str = match entry.node {
            ExprLit(lit) => {
                match lit.node {
                    LitStr(ref s, _) => s.clone(),
                    _ => {
                        cx.span_err(entry.span, "expected string literal");
                        error = true;
                        InternedString::new("")
                    }
                }
            }
            _ => {
                cx.span_err(entry.span, "expected string literal");
                error = true;
                InternedString::new("")
            }
        };

        entries.push(Entry { str: entry_str, expr: entry });

        if !parser.eat(&COMMA) && parser.token != EOF {
            cx.span_err(parser.span, "expected `,`");
            return None;
        }
    }

    if error {
        return None;
    }

    Some(entries)
}

/// A convenience type for macros that return a single item.
pub struct MacItems {
    items: Vec<Gc<ast::Item>>
}

impl MacItems {
    pub fn new(items: Vec<Gc<ast::Item>>) -> Box<MacResult> {
        box MacItems { items: items } as Box<MacResult>
    }
}
impl MacResult for MacItems {
    fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
        Some(SmallVector::many(self.items.clone()))
    }
}

fn provide_csv_given_labels(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult> {
   let mut entries = match parse_entries(cx, tts) {
      Some(entries) => entries,
      None => return DummyResult::expr(sp),
   };

   let name   = entries.shift().expect("should be given a type name").str;
   let path   = entries.shift().expect("should be given a CSV file path").str;
   let labels = entries.shift().expect("should be given column labels").str;

   println!("provide_csv_given_labels: name:   {}", name);
   println!("provide_csv_given_labels: path:   {}", path);
   println!("provide_csv_given_labels: labels: {}", labels);

   // PENDING
   // read the CSV and try to get the type of data in it
   // create a type with
   //  * this name,
   //  * these labeled columns,
   //  * discovered type of data
   //  * a constructor which reads the whole file

/* OLD
   let banana = "YAY! BANANA!";
   return MacExpr::new(quote_expr!(cx, {let x: $banana = 44}));
 */

   fn define_my_csv(cx0: &mut ExtCtxt) -> Option<Gc<syntax::ast::Item>> {
      let item1: Option<Gc<syntax::ast::Item>>  = quote_item!(cx0,
         pub struct MyCSV {
            pub data: Vec<(String)>,
         }
      );
      return item1;
   }

   let item1 = define_my_csv(cx);  // Why is this necessary?

   let item2: Option<Gc<syntax::ast::Item>>  = quote_item!(cx,
      impl MyCSV {
         pub fn new() -> MyCSV {  // BUG: note removing the { leads to goofy error messsages
            println!("HMMMMMM.");
            return MyCSV {
               data: (vec!["zero".to_string(), "one".to_string(), "two".to_string()]),
            };
         }
      }
   );

   let items = vec![item1.expect("Should be able to construct MyCSV."),
                    item2.expect("Should be able to construct MyCSV.")];
   return MacItems::new(items);
}

<commit_msg>next problem...<commit_after>#![crate_id="CSVProvider#0.1-pre"]
#![crate_type="dylib"]

// why doesn't "lib" work?

// rustc 0.11.0-pre (b47f2226a25654c5b781d27a91f2fa5274b3a347 2014-06-28 14:31:37 +0000)

#![feature(globs, macro_rules, quote, managed_boxes, plugin_registrar)]

#![allow(unused_imports)]
#![allow(unused_variable)]

extern crate syntax;
extern crate rustc;

use syntax::ast::{Name,
                  TokenTree,
                  Expr,
                  ExprLit,
                  ExprVec,
                  LitStr,
                  DUMMY_NODE_ID,
                  MutImmutable};
use syntax::codemap::Span;
use syntax::ext::base::{SyntaxExtension,
                        BasicMacroExpander,
                        ExtCtxt,
                        MacResult,
                        MacPat,
                        MacItem,
                        DummyResult,
                        MacExpr,
                        NormalTT};
use std::gc::Gc;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::{InternedString, COMMA, EOF};

use std::io;
use std::io::fs;
use std::os;
use std::str;
use std::io::Process;
use syntax::ast;
use syntax::ast::Name;

use syntax::util::small_vector::SmallVector;

use std::collections::HashMap;
use std::gc::{Gc, GC};

use rustc::plugin::Registry;

#[plugin_registrar]
pub fn macro_registrar(reg: &mut Registry) {
    reg.register_macro("ProvideCSV_labels", provide_csv_given_labels);
}

#[deriving(Clone)]
struct Entry {
    str: InternedString,
    expr: Gc<Expr>
}

// see https://github.com/sfackler/syntax-ext-talk/blob/gh-pages/simple-ext/lib.rs
fn parse_entries(cx: &mut ExtCtxt, tts: &[TokenTree]) -> Option<Vec<Entry>> {
    let mut parser = parse::new_parser_from_tts(
         cx.parse_sess(),
         cx.cfg(),
         tts.iter()
            .map(|x| (*x).clone())
            .collect()
    );

    let mut entries: Vec<Entry> = Vec::new();

    let mut error = false;
    while parser.token != EOF {
        let entry = parser.parse_expr();

        let entry_str = match entry.node {
            ExprLit(lit) => {
                match lit.node {
                    LitStr(ref s, _) => s.clone(),
                    _ => {
                        cx.span_err(entry.span, "expected string literal");
                        error = true;
                        InternedString::new("")
                    }
                }
            }
            _ => {
                cx.span_err(entry.span, "expected string literal");
                error = true;
                InternedString::new("")
            }
        };

        entries.push(Entry { str: entry_str, expr: entry });

        if !parser.eat(&COMMA) && parser.token != EOF {
            cx.span_err(parser.span, "expected `,`");
            return None;
        }
    }

    if error {
        return None;
    }

    Some(entries)
}

/// A convenience type for macros that return a single item.
pub struct MacItems {
    items: Vec<Gc<ast::Item>>
}

impl MacItems {
    pub fn new(items: Vec<Gc<ast::Item>>) -> Box<MacResult> {
        box MacItems { items: items } as Box<MacResult>
    }
}
impl MacResult for MacItems {
    fn make_items(&self) -> Option<SmallVector<Gc<ast::Item>>> {
        Some(SmallVector::many(self.items.clone()))
    }
}

fn provide_csv_given_labels(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult> {
   let mut entries = match parse_entries(cx, tts) {
      Some(entries) => entries,
      None => return DummyResult::expr(sp),
   };

   let name   = entries.shift().expect("should be given a type name").str;
   let path   = entries.shift().expect("should be given a CSV file path").str;
   let labels = entries.shift().expect("should be given column labels").str;

   println!("provide_csv_given_labels: name:   {}", name);
   println!("provide_csv_given_labels: path:   {}", path);
   println!("provide_csv_given_labels: labels: {}", labels);

   // PENDING
   // read the CSV and try to get the type of data in it
   // create a type with
   //  * this name,
   //  * these labeled columns,
   //  * discovered type of data
   //  * a constructor which reads the whole file

/* OLD
   let banana = "YAY! BANANA!";
   return MacExpr::new(quote_expr!(cx, {let x: $banana = 44}));
 */

   fn define_my_csv(cx0: &mut ExtCtxt) -> Option<Gc<syntax::ast::Item>> {
      let item1: Option<Gc<syntax::ast::Item>>  = quote_item!(cx0,
         pub struct MyCSV {
            pub data: Vec<(String)>,
         }
      );
      return item1;
   }

   let item1 = define_my_csv(cx);  // Why is this necessary?

   let item2: Option<Gc<syntax::ast::Item>>  = quote_item!(cx,
      impl $name {
         pub fn new() -> MyCSV {  // BUG: note removing the { leads to goofy error messsages
            println!("HMMMMMM.");
            return MyCSV {
               data: (vec!["zero".to_string(), "one".to_string(), "two".to_string()]),
            };
         }
      }
   );

   let items = vec![item1.expect("Should be able to construct MyCSV."),
                    item2.expect("Should be able to construct MyCSV.")];
   return MacItems::new(items);
}

<|endoftext|>