<commit_before>
mod error;
mod pair;
mod parser;
mod token;
mod scanner;

pub use error::*;
pub use pair::*;

use parser::*;
use scanner::*;

use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::error::Error;

/// Parses a file using the given filename.
///
/// Examples:
///
/// ```
/// let config = nccl::parse_file("examples/config.nccl").unwrap();
/// let ports = config["server"]["port"].keys_as::<i32>().unwrap();
/// assert_eq!(ports, vec![80, 443]);
/// ```
pub fn parse_file(filename: &str) -> Result<Pair, Vec<Box<Error>>> {
    if let Ok(mut file) = File::open(Path::new(filename)) {
        let mut data = String::new();
        file.read_to_string(&mut data).unwrap();
        Parser::new(Scanner::new(data).scan_tokens()?).parse()
    } else {
        Err(vec![Box::new(NcclError::new(ErrorKind::FileError, "Could not find file.", 0))])
    }
}

/// Parses a file, merging the results with the supplied pair. Allows for a
/// kind of inheritance of configuration.
///
/// Examples:
///
/// ```
/// let schemas = nccl::parse_file("examples/inherit.nccl").unwrap();
/// let user = nccl::parse_file_with("examples/inherit2.nccl", schemas).unwrap();
/// assert_eq!(user["sandwich"]["meat"].keys().len(), 3);
/// assert_eq!(user["hello"]["world"].keys().len(), 3);
/// ```
pub fn parse_file_with(filename: &str, pair: Pair) -> Result<Pair, Vec<Box<Error>>> {
    if let Ok(mut file) = File::open(Path::new(filename)) {
        let mut data = String::new();
        file.read_to_string(&mut data).unwrap();
        Parser::new_with(Scanner::new(data).scan_tokens()?, pair).parse()
    } else {
        Err(vec![Box::new(NcclError::new(ErrorKind::FileError, "Could not find file.", 0))])
    }
}

/// Parses raw string data.
///
/// Examples:
///
/// ```
/// let raw = nccl::parse_string("hello\n\tworld!").unwrap();
/// assert_eq!(raw["hello"].value().unwrap(), "world!");
/// ```
pub fn parse_string(data: &str) -> Result<Pair, Vec<Box<Error>>> {
    Parser::new(Scanner::new(data.to_owned()).scan_tokens()?).parse()
}

#[cfg(test)]
mod tests {
    #[test]
    fn pair_keys() {
        let mut p = ::Pair::new("top");
        p.add("numbers");
        p["numbers"].add("1");
        p["numbers"].add("2");
        p["numbers"].add("3");
        p["numbers"].add("4");
        p["numbers"].add("5");
        assert_eq!(p["numbers"].keys(), vec!["1", "2", "3", "4", "5"]);
    }

    #[test]
    fn pair_value_parse() {
        let mut p = ::Pair::new("top");
        p.add("bools");
        p["bools"].add("true");
        assert!(p["bools"].value_as::<bool>().unwrap());
    }

    #[test]
    fn scanner_literal() {
        let mut s = ::Scanner::new("\"this: is neato\": burrito 64\n    yes.".into());
        s.scan_tokens().unwrap();
    }

    #[test]
    fn error_key_not_found() {
        let mut p = ::Pair::new("jjj");
        assert!(p.get("jwiofiojwaef jio").is_err());
    }

    #[test]
    fn scan_file() {
        assert!(::parse_file("examples/config.nccl").is_ok());
    }

    #[test]
    fn dos_unix_lines() {
        assert!(::parse_file("examples/config.nccl").is_ok());
        assert!(::parse_file("examples/config_dos.nccl").is_ok());
    }

    #[test]
    fn string_escape() {
        let mut s = ::Scanner::new("\"\\\"hello\\\"\\n\"".into());
        assert_eq!(s.scan_tokens().unwrap()[0].lexeme, "\"hello\"\n");
    }

    #[test]
    fn add_pair() {
        // create a new pair
         let mut p1 = ::Pair::new("happy birthday");

         p1.add("Bobby");
         p1["Bobby"].add("Today!");

         // we think Ron's birthday is the 3rd...
         p1.add("Ron");
         p1["Ron"].add("March 3rd");

         // whoops, we were wrong
         let mut p2 = ::Pair::new("Ron");
         p2.add("March 2nd");

         // there you go Ron, happy belated birthday
         p1.add_pair(p2);
    }

    #[test]
    fn traverse_path() {
        let mut p = ::Pair::new("top");
        p.add_slice(&["a".into(), "b".into(), "c".into()]);
        p.traverse_path(&["a".into(), "b".into()]).add("happy");
        assert_eq!(p.traverse_path(&["a".into(), "b".into(), "happy".into()]), &mut ::Pair::new("happy"));
    }

    #[test]
    fn add_slice() {
        let mut config = ::Pair::new("top_level");
        config.add("server");
        config["server"].add("domain");
        config["server"].add("port");
        config["server"].add("root");
        config["server"]["domain"].add("example.com");
        config["server"]["domain"].add("www.example.com");
        config["server"]["port"].add("80");
        config["server"]["port"].add("443");
        config["server"]["root"].add("/var/www/html");

        config.add_slice(&["server".into(), "port".into(), "22".into()]);
        assert_eq!(config["server"]["port"].keys(), vec!["80", "443", "22"]);
    }

    #[test]
    fn multiple_errors() {
        let mut s = ::Scanner::new("hey: momma\n   test\n\tjeii\n    oh no!\n".into());
        assert!(s.scan_tokens().is_err());
    }

    #[test]
    fn add_vec() {
        let mut p = ::Pair::new("__top_level__");
        p.add("a");
        p.add_slice(&["a".into(), "hello".into(), "world".into()]);
        p.add_slice(&["a".into(), "hello".into(), "world".into()]);
        assert_eq!(p["a"]["hello"].keys().len(), 1);
    }

    #[test]
    fn long() {
        let oh_dear = ::parse_file("examples/long.nccl").unwrap();
        oh_dear.pretty_print();
    }

    #[test]
    fn inherit2() {
        let schemas = ::parse_file("examples/inherit.nccl").unwrap();
        let user = ::parse_file_with("examples/inherit2.nccl", schemas).unwrap();
        assert_eq!(user["sandwich"]["meat"].keys().len(), 3);
        assert_eq!(user["hello"]["world"].keys().len(), 3);
    }

    #[test]
    fn tabs() {
        assert!(::parse_file("examples/tabs.nccl").is_err());
    }

    #[test]
    fn spaces() {
        assert!(::parse_file("examples/spaces").is_err());
    }

    #[test]
    fn comments() {
        assert!(::parse_file("examples/comments.nccl").is_ok());
    }

    #[test]
    fn indent() {
        assert!(::parse_file("examples/indent.nccl").is_ok());
    }

    #[test]
    fn readme() {
        let config = ::parse_file("examples/config.nccl").unwrap();
        let ports = config["server"]["port"].keys_as::<u32>().unwrap();
        assert_eq!(ports, vec![80, 443]);
    }
}

<commit_msg>add crate-level doc<commit_after>
//! Nccl is an easy way to add minimal configuration to your crate without
//! having to deal with complicated interfaces, obnoxious syntax, or outdated
//! languages. Nccl makes it easy for a user to pick up your configuration.
//! It's as easy as five cents.
//!
//! Nccl was motivated by the fact that other configuration languages are too
//! complicated for end-users. Strict enforcement of data types is a hassle for
//! people who just want stuff to do things. In nccl's case, not having data
//! types is motivated by the fact that a lot of configuration isn't based on
//! numbers, dates, or booleans, but strings. In the case where a more
//! complicated format is required, it's as simple as a call to `.value_as()` or
//! `.keys_as()`.

mod error;
mod pair;
mod parser;
mod token;
mod scanner;

pub use error::*;
pub use pair::*;

use parser::*;
use scanner::*;

use std::path::Path;
use std::fs::File;
use std::io::Read;
use std::error::Error;

/// Parses a file using the given filename.
///
/// Examples:
///
/// ```
/// let config = nccl::parse_file("examples/config.nccl").unwrap();
/// let ports = config["server"]["port"].keys_as::<i32>().unwrap();
/// assert_eq!(ports, vec![80, 443]);
/// ```
pub fn parse_file(filename: &str) -> Result<Pair, Vec<Box<Error>>> {
    if let Ok(mut file) = File::open(Path::new(filename)) {
        let mut data = String::new();
        file.read_to_string(&mut data).unwrap();
        Parser::new(Scanner::new(data).scan_tokens()?).parse()
    } else {
        Err(vec![Box::new(NcclError::new(ErrorKind::FileError, "Could not find file.", 0))])
    }
}

/// Parses a file, merging the results with the supplied pair. Allows for a
/// kind of inheritance of configuration.
///
/// Examples:
///
/// ```
/// let schemas = nccl::parse_file("examples/inherit.nccl").unwrap();
/// let user = nccl::parse_file_with("examples/inherit2.nccl", schemas).unwrap();
/// assert_eq!(user["sandwich"]["meat"].keys().len(), 3);
/// assert_eq!(user["hello"]["world"].keys().len(), 3);
/// ```
pub fn parse_file_with(filename: &str, pair: Pair) -> Result<Pair, Vec<Box<Error>>> {
    if let Ok(mut file) = File::open(Path::new(filename)) {
        let mut data = String::new();
        file.read_to_string(&mut data).unwrap();
        Parser::new_with(Scanner::new(data).scan_tokens()?, pair).parse()
    } else {
        Err(vec![Box::new(NcclError::new(ErrorKind::FileError, "Could not find file.", 0))])
    }
}

/// Parses raw string data.
///
/// Examples:
///
/// ```
/// let raw = nccl::parse_string("hello\n\tworld!").unwrap();
/// assert_eq!(raw["hello"].value().unwrap(), "world!");
/// ```
pub fn parse_string(data: &str) -> Result<Pair, Vec<Box<Error>>> {
    Parser::new(Scanner::new(data.to_owned()).scan_tokens()?).parse()
}

#[cfg(test)]
mod tests {
    #[test]
    fn pair_keys() {
        let mut p = ::Pair::new("top");
        p.add("numbers");
        p["numbers"].add("1");
        p["numbers"].add("2");
        p["numbers"].add("3");
        p["numbers"].add("4");
        p["numbers"].add("5");
        assert_eq!(p["numbers"].keys(), vec!["1", "2", "3", "4", "5"]);
    }

    #[test]
    fn pair_value_parse() {
        let mut p = ::Pair::new("top");
        p.add("bools");
        p["bools"].add("true");
        assert!(p["bools"].value_as::<bool>().unwrap());
    }

    #[test]
    fn scanner_literal() {
        let mut s = ::Scanner::new("\"this: is neato\": burrito 64\n    yes.".into());
        s.scan_tokens().unwrap();
    }

    #[test]
    fn error_key_not_found() {
        let mut p = ::Pair::new("jjj");
        assert!(p.get("jwiofiojwaef jio").is_err());
    }

    #[test]
    fn scan_file() {
        assert!(::parse_file("examples/config.nccl").is_ok());
    }

    #[test]
    fn dos_unix_lines() {
        assert!(::parse_file("examples/config.nccl").is_ok());
        assert!(::parse_file("examples/config_dos.nccl").is_ok());
    }

    #[test]
    fn string_escape() {
        let mut s = ::Scanner::new("\"\\\"hello\\\"\\n\"".into());
        assert_eq!(s.scan_tokens().unwrap()[0].lexeme, "\"hello\"\n");
    }

    #[test]
    fn add_pair() {
        // create a new pair
         let mut p1 = ::Pair::new("happy birthday");

         p1.add("Bobby");
         p1["Bobby"].add("Today!");

         // we think Ron's birthday is the 3rd...
         p1.add("Ron");
         p1["Ron"].add("March 3rd");

         // whoops, we were wrong
         let mut p2 = ::Pair::new("Ron");
         p2.add("March 2nd");

         // there you go Ron, happy belated birthday
         p1.add_pair(p2);
    }

    #[test]
    fn traverse_path() {
        let mut p = ::Pair::new("top");
        p.add_slice(&["a".into(), "b".into(), "c".into()]);
        p.traverse_path(&["a".into(), "b".into()]).add("happy");
        assert_eq!(p.traverse_path(&["a".into(), "b".into(), "happy".into()]), &mut ::Pair::new("happy"));
    }

    #[test]
    fn add_slice() {
        let mut config = ::Pair::new("top_level");
        config.add("server");
        config["server"].add("domain");
        config["server"].add("port");
        config["server"].add("root");
        config["server"]["domain"].add("example.com");
        config["server"]["domain"].add("www.example.com");
        config["server"]["port"].add("80");
        config["server"]["port"].add("443");
        config["server"]["root"].add("/var/www/html");

        config.add_slice(&["server".into(), "port".into(), "22".into()]);
        assert_eq!(config["server"]["port"].keys(), vec!["80", "443", "22"]);
    }

    #[test]
    fn multiple_errors() {
        let mut s = ::Scanner::new("hey: momma\n   test\n\tjeii\n    oh no!\n".into());
        assert!(s.scan_tokens().is_err());
    }

    #[test]
    fn add_vec() {
        let mut p = ::Pair::new("__top_level__");
        p.add("a");
        p.add_slice(&["a".into(), "hello".into(), "world".into()]);
        p.add_slice(&["a".into(), "hello".into(), "world".into()]);
        assert_eq!(p["a"]["hello"].keys().len(), 1);
    }

    #[test]
    fn long() {
        let oh_dear = ::parse_file("examples/long.nccl").unwrap();
        oh_dear.pretty_print();
    }

    #[test]
    fn inherit2() {
        let schemas = ::parse_file("examples/inherit.nccl").unwrap();
        let user = ::parse_file_with("examples/inherit2.nccl", schemas).unwrap();
        assert_eq!(user["sandwich"]["meat"].keys().len(), 3);
        assert_eq!(user["hello"]["world"].keys().len(), 3);
    }

    #[test]
    fn tabs() {
        assert!(::parse_file("examples/tabs.nccl").is_err());
    }

    #[test]
    fn spaces() {
        assert!(::parse_file("examples/spaces").is_err());
    }

    #[test]
    fn comments() {
        assert!(::parse_file("examples/comments.nccl").is_ok());
    }

    #[test]
    fn indent() {
        assert!(::parse_file("examples/indent.nccl").is_ok());
    }

    #[test]
    fn readme() {
        let config = ::parse_file("examples/config.nccl").unwrap();
        let ports = config["server"]["port"].keys_as::<u32>().unwrap();
        assert_eq!(ports, vec![80, 443]);
    }
}

<|endoftext|>


<commit_before>extern crate byteorder;
use byteorder::{LittleEndian, ReadBytesExt};

use std::collections::HashMap;
use std::io::{self, BufRead};

#[derive(Debug)]
pub struct BigArchive {
    pub format: Format,
    pub size: u32,

    _entries: HashMap<String, BigEntry>,
}

#[derive(Debug)]
pub enum ReadError {
    StdIoError(io::Error),
    UnknownFormat(Vec<u8>),
}

impl From<io::Error> for ReadError {
    fn from(e: io::Error) -> Self {
        ReadError::StdIoError(e)
    }
}

impl BigArchive {
    pub fn new(mut data: &mut BufRead) -> Result<BigArchive, ReadError> {
        let format = read_format(&mut data).expect("Failed to read format");

        if let Format::Unknown(bytes) = format {
            return Err(ReadError::UnknownFormat(bytes));
        }

        let size = try!(data.read_u32::<LittleEndian>());
        let size = invert_endianness(size);

        let num_entries = try!(data.read_u32::<LittleEndian>());
        let num_entries = invert_endianness(num_entries);

        // Offset to the first entry, I think.
        let _ = data.read_u32::<LittleEndian>();

        let mut entries = HashMap::new();

        for i in 0..num_entries {
            let entry_num = i + 1;
            let offset = try!(data.read_u32::<LittleEndian>());
            let offset = invert_endianness(offset);

            let size = try!(data.read_u32::<LittleEndian>());
            let size = invert_endianness(size);

            let mut buf = Vec::new();
            data.read_until(b'\0', &mut buf)
                .expect(&format!("Failed to read name for entry {}", entry_num));

            let name = String::from_utf8_lossy(&buf[..buf.len() - 1]);

            let entry = BigEntry {
                offset: offset,
                size: size,
                name: name.to_string(),
            };

            entries.insert(entry.name.clone(), entry);
        }

        Ok(BigArchive {
            format: format,
            size: size,
            _entries: entries,
        })
    }

    pub fn get_entry(&self, entry_name: &str) -> Option<&BigEntry> {
        self._entries.get(entry_name)
    }

    pub fn get_entry_mut(&mut self, entry_name: &str) -> Option<&mut BigEntry> {
        self._entries.get_mut(entry_name)
    }

    pub fn get_all_entry_names(&self) -> std::collections::hash_map::Keys<String, BigEntry> {
        self._entries.keys()
    }
}

#[derive(Debug)]
pub struct BigEntry {
    pub offset: u32,
    pub size: u32,
    pub name: String,
}

#[derive(Debug, PartialEq)]
pub enum Format {
    Unknown(Vec<u8>),
    Big4,
    BigF,
}

impl<'a> From<&'a mut BufRead> for Format {
    fn from(data: &'a mut BufRead) -> Self {
        let mut buf = [0; 4];
        let _ = data.read_exact(&mut buf);
        match &buf {
            b"BIG4" => Format::Big4,
            b"BIGf" => Format::BigF,
            _ => Format::Unknown(Vec::from(&buf[..])),
        }
    }
}

fn read_format(data: &mut BufRead) -> Result<Format, io::Error> {
    Ok(Format::from(data))
}

fn invert_endianness(v: u32) -> u32 {
    (v << 24) | (v << 8 & 0xff0000) | (v >> 8 & 0xff00) | (v >> 24)
}

#[cfg(test)]
mod tests {
    const TEST_BYTES: &'static [u8] = include_bytes!("../test.big");

    use std::io::BufReader;
    use super::{read_format, Format, BigArchive};

    #[test]
    fn is_big4() {
        let mut reader = BufReader::new(TEST_BYTES);
        assert_eq!(read_format(&mut reader).expect("Failed to load file"),
                   Format::Big4);
    }

    #[test]
    fn has_two_entries() {
        let mut reader = BufReader::new(TEST_BYTES);
        let archive = BigArchive::new(&mut reader).unwrap();
        assert_eq!(archive.get_all_entry_names().len(), 2);
    }
}
<commit_msg>Add a comment to the use of String::from_utf8_lossy<commit_after>extern crate byteorder;
use byteorder::{LittleEndian, ReadBytesExt};

use std::collections::HashMap;
use std::io::{self, BufRead};

#[derive(Debug)]
pub struct BigArchive {
    pub format: Format,
    pub size: u32,

    _entries: HashMap<String, BigEntry>,
}

#[derive(Debug)]
pub enum ReadError {
    StdIoError(io::Error),
    UnknownFormat(Vec<u8>),
}

impl From<io::Error> for ReadError {
    fn from(e: io::Error) -> Self {
        ReadError::StdIoError(e)
    }
}

impl BigArchive {
    pub fn new(mut data: &mut BufRead) -> Result<BigArchive, ReadError> {
        let format = read_format(&mut data).expect("Failed to read format");

        if let Format::Unknown(bytes) = format {
            return Err(ReadError::UnknownFormat(bytes));
        }

        let size = try!(data.read_u32::<LittleEndian>());
        let size = invert_endianness(size);

        let num_entries = try!(data.read_u32::<LittleEndian>());
        let num_entries = invert_endianness(num_entries);

        // Offset to the first entry, I think.
        let _ = data.read_u32::<LittleEndian>();

        let mut entries = HashMap::new();

        for i in 0..num_entries {
            let offset = try!(data.read_u32::<LittleEndian>());
            let offset = invert_endianness(offset);

            let size = try!(data.read_u32::<LittleEndian>());
            let size = invert_endianness(size);

            let mut buf = Vec::new();
            data.read_until(b'\0', &mut buf)
                .expect(&format!("Failed to read name for entry {}", i + 1));

            // Remove the trailing \0
            let name = String::from_utf8_lossy(&buf[..buf.len() - 1]);

            let entry = BigEntry {
                offset: offset,
                size: size,
                name: name.to_string(),
            };

            entries.insert(entry.name.clone(), entry);
        }

        Ok(BigArchive {
            format: format,
            size: size,
            _entries: entries,
        })
    }

    pub fn get_entry(&self, entry_name: &str) -> Option<&BigEntry> {
        self._entries.get(entry_name)
    }

    pub fn get_entry_mut(&mut self, entry_name: &str) -> Option<&mut BigEntry> {
        self._entries.get_mut(entry_name)
    }

    pub fn get_all_entry_names(&self) -> std::collections::hash_map::Keys<String, BigEntry> {
        self._entries.keys()
    }
}

#[derive(Debug)]
pub struct BigEntry {
    pub offset: u32,
    pub size: u32,
    pub name: String,
}

#[derive(Debug, PartialEq)]
pub enum Format {
    Unknown(Vec<u8>),
    Big4,
    BigF,
}

impl<'a> From<&'a mut BufRead> for Format {
    fn from(data: &'a mut BufRead) -> Self {
        let mut buf = [0; 4];
        let _ = data.read_exact(&mut buf);
        match &buf {
            b"BIG4" => Format::Big4,
            b"BIGf" => Format::BigF,
            _ => Format::Unknown(Vec::from(&buf[..])),
        }
    }
}

fn read_format(data: &mut BufRead) -> Result<Format, io::Error> {
    Ok(Format::from(data))
}

fn invert_endianness(v: u32) -> u32 {
    (v << 24) | (v << 8 & 0xff0000) | (v >> 8 & 0xff00) | (v >> 24)
}

#[cfg(test)]
mod tests {
    const TEST_BYTES: &'static [u8] = include_bytes!("../test.big");

    use std::io::BufReader;
    use super::{read_format, Format, BigArchive};

    #[test]
    fn is_big4() {
        let mut reader = BufReader::new(TEST_BYTES);
        assert_eq!(read_format(&mut reader).expect("Failed to load file"),
                   Format::Big4);
    }

    #[test]
    fn has_two_entries() {
        let mut reader = BufReader::new(TEST_BYTES);
        let archive = BigArchive::new(&mut reader).unwrap();
        assert_eq!(archive.get_all_entry_names().len(), 2);
    }
}
<|endoftext|>


<commit_before>extern crate ascii;

mod pascal_str;
mod pascal_string;

const PASCAL_STRING_BUF_SIZE: usize = 255;

pub use pascal_str::{Chars, CharsMut, PascalStr};
pub use pascal_string::{PascalString, PascalStringAppendError, PascalStringCreateError, AsciiError};

#[cfg(test)]
mod tests {
    use super::*;
    use ascii::*;
    use std::borrow::Cow;
    use std::ffi::{CStr, CString};

    #[test]
    fn test_string_creation() {
        let test = "Hello, my world!".to_owned();
        let test_pascal = PascalString::from(&test).unwrap();
        assert_eq!(&test, test_pascal.as_str());

        let too_many_bytes = vec![12u8; 256];
        assert!(match PascalString::from(&too_many_bytes) {
            Err(PascalStringCreateError::InputTooLong) => true,
            _ => false
        });
    }

    #[test]
    fn test_character_append() {
        let mut string = PascalString::new();
        assert!(string.try_push('h').is_ok());
        string.push('e');
        string.push(76u8);
        string.push('l');
        string.push(AsciiChar::L);
        string.push('o');
        string.push(AsciiChar::Null);

        println!("{}", string);
        assert_eq!(string.as_str(), "heLlLo\0");
    }

    #[test]
    fn test_string_append() {
        let mut string = PascalString::new();
        string.push_str("Hola, ");
        string.push_str("Senor!");
        assert_eq!(string.as_str(), "Hola, Senor!");
    }

    #[test]
    fn test_string_indexing_and_char_iteration() {
        {
            let string = PascalString::from("q").unwrap();
            assert_eq!(string[0u8], AsciiChar::q);
        }

        {
            let string2 = PascalString::from("WASD").unwrap();
            let mut iter = string2.chars();
            assert_eq!(iter.next(), Some(&AsciiChar::W));
            assert_eq!(iter.next(), Some(&AsciiChar::A));
            assert_eq!(iter.next(), Some(&AsciiChar::S));
            assert_eq!(iter.next(), Some(&AsciiChar::D));
        }
    }

    #[test]
    fn test_as_cstr() {
        {
            let msg = "I am your favourite cookie monster >:-)\0";
            let pstr = PascalString::from(&msg).unwrap();
            let cstr = CStr::from_bytes_with_nul(msg.as_bytes()).unwrap();
            let pstr_as_cstr = pstr.as_cstr().unwrap();
            assert!(match pstr_as_cstr {
                Cow::Borrowed(_) => true,
                _ => false
            });
            assert_eq!(&*pstr_as_cstr, cstr);
        }

        {
            let oversized = ['l'; 255];
            let string_oversized = {
                let mut s = String::new();
                for i in 0..oversized.len() {
                    s.push(oversized[i]);
                }
                s
            };
            let pstr_oversized = PascalString::from_fixed_ascii_array(255, oversized).unwrap();
            println!("oversized: {}", pstr_oversized.is_full());
            let cstr_from_pstr_oversized = pstr_oversized.as_cstr().unwrap();
            let cstr_from_string_oversized = CString::new(string_oversized).unwrap();
            assert!(match cstr_from_pstr_oversized {
                Cow::Owned(_) => true,
                _ => false
            });
            assert_eq!(cstr_from_pstr_oversized.into_owned(), cstr_from_string_oversized);
        }

        {
            let has_interior_null = "lol\0hi";
            let pstr = PascalString::from(&has_interior_null).unwrap();
            let err = match pstr.as_cstr() {
                Err(err) => err,
                _ => panic!("incorrect result")
            };
            assert_eq!(err.interior_null_index(), 3);
        }
    }
}
<commit_msg>Remove a bunch of useless println!s from the tests<commit_after>extern crate ascii;

mod pascal_str;
mod pascal_string;

const PASCAL_STRING_BUF_SIZE: usize = 255;

pub use pascal_str::{Chars, CharsMut, PascalStr};
pub use pascal_string::{PascalString, PascalStringAppendError, PascalStringCreateError, AsciiError};

#[cfg(test)]
mod tests {
    use super::*;
    use ascii::*;
    use std::borrow::Cow;
    use std::ffi::{CStr, CString};

    #[test]
    fn test_string_creation() {
        let test = "Hello, my world!".to_owned();
        let test_pascal = PascalString::from(&test).unwrap();
        assert_eq!(&test, test_pascal.as_str());

        let too_many_bytes = vec![12u8; 256];
        assert!(match PascalString::from(&too_many_bytes) {
            Err(PascalStringCreateError::InputTooLong) => true,
            _ => false
        });
    }

    #[test]
    fn test_character_append() {
        let mut string = PascalString::new();
        assert!(string.try_push('h').is_ok());
        string.push('e');
        string.push(76u8);
        string.push('l');
        string.push(AsciiChar::L);
        string.push('o');
        string.push(AsciiChar::Null);

        assert_eq!(string.as_str(), "heLlLo\0");
    }

    #[test]
    fn test_string_append() {
        let mut string = PascalString::new();
        string.push_str("Hola, ");
        string.push_str("Senor!");
        assert_eq!(string.as_str(), "Hola, Senor!");
    }

    #[test]
    fn test_string_indexing_and_char_iteration() {
        {
            let string = PascalString::from("q").unwrap();
            assert_eq!(string[0u8], AsciiChar::q);
        }

        {
            let string2 = PascalString::from("WASD").unwrap();
            let mut iter = string2.chars();
            assert_eq!(iter.next(), Some(&AsciiChar::W));
            assert_eq!(iter.next(), Some(&AsciiChar::A));
            assert_eq!(iter.next(), Some(&AsciiChar::S));
            assert_eq!(iter.next(), Some(&AsciiChar::D));
        }
    }

    #[test]
    fn test_as_cstr() {
        {
            let msg = "I am your favourite cookie monster >:-)\0";
            let pstr = PascalString::from(&msg).unwrap();
            let cstr = CStr::from_bytes_with_nul(msg.as_bytes()).unwrap();
            let pstr_as_cstr = pstr.as_cstr().unwrap();
            assert!(match pstr_as_cstr {
                Cow::Borrowed(_) => true,
                _ => false
            });
            assert_eq!(&*pstr_as_cstr, cstr);
        }

        {
            let oversized = ['l'; 255];
            let string_oversized = {
                let mut s = String::new();
                for i in 0..oversized.len() {
                    s.push(oversized[i]);
                }
                s
            };
            let pstr_oversized = PascalString::from_fixed_ascii_array(255, oversized).unwrap();
            let cstr_from_pstr_oversized = pstr_oversized.as_cstr().unwrap();
            let cstr_from_string_oversized = CString::new(string_oversized).unwrap();
            assert!(match cstr_from_pstr_oversized {
                Cow::Owned(_) => true,
                _ => false
            });
            assert_eq!(cstr_from_pstr_oversized.into_owned(), cstr_from_string_oversized);
        }

        {
            let has_interior_null = "lol\0hi";
            let pstr = PascalString::from(&has_interior_null).unwrap();
            let err = match pstr.as_cstr() {
                Err(err) => err,
                _ => panic!("incorrect result")
            };
            assert_eq!(err.interior_null_index(), 3);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#![crate_name = "string_cache"]
#![crate_type = "rlib"]

#![feature(plugin, old_orphan_check)]
#![feature(core, collections, alloc, hash)]
#![deny(warnings)]

#[cfg(test)]
extern crate test;

#[plugin] #[no_link]
extern crate phf_mac;
extern crate phf;

#[macro_use]
extern crate lazy_static;

extern crate xxhash;

#[plugin] #[no_link] #[macro_use]
extern crate string_cache_macros;

#[cfg(feature = "log-events")]
extern crate serialize;

pub use atom::Atom;
pub use namespace::{Namespace, QualName};

#[cfg(feature = "log-events")]
pub mod event;

pub mod atom;
pub mod namespace;

// A private module so that macro-expanded idents like
// `::string_cache::atom::Atom` will also work in this crate.
//
// `libstd` uses the same trick.
#[doc(hidden)]
mod string_cache {
    pub use atom;
    pub use namespace;
}
<commit_msg>Fix warnings during `cargo test` too<commit_after>// Copyright 2014 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

#![crate_name = "string_cache"]
#![crate_type = "rlib"]

#![feature(plugin, old_orphan_check)]
#![feature(core, collections, alloc, hash)]
#![deny(warnings)]
#![cfg_attr(test, feature(test, std_misc))]

#[cfg(test)]
extern crate test;

#[plugin] #[no_link]
extern crate phf_mac;
extern crate phf;

#[macro_use]
extern crate lazy_static;

extern crate xxhash;

#[plugin] #[no_link] #[macro_use]
extern crate string_cache_macros;

#[cfg(feature = "log-events")]
extern crate serialize;

pub use atom::Atom;
pub use namespace::{Namespace, QualName};

#[cfg(feature = "log-events")]
pub mod event;

pub mod atom;
pub mod namespace;

// A private module so that macro-expanded idents like
// `::string_cache::atom::Atom` will also work in this crate.
//
// `libstd` uses the same trick.
#[doc(hidden)]
mod string_cache {
    pub use atom;
    pub use namespace;
}
<|endoftext|>


<commit_before>#![feature(rustc_private)]
#![feature(plugin_registrar, quote)]
extern crate rustc;
extern crate syntax;

use rustc::plugin::Registry;
use syntax::ast::{self, TokenTree};
use syntax::codemap::DUMMY_SP;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacEager, MacResult};
use syntax::ext::build::AstBuilder;
use syntax::parse::tts_to_parser;
use syntax::util::small_vector::SmallVector;

use generator::Generate;

mod block;
mod parser;
mod generator;

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

fn expand_speculate(cx: &mut ExtCtxt, _sp: Span, tokens: &[TokenTree]) -> Box<MacResult + 'static> {
    let mut parser = tts_to_parser(cx.parse_sess(), tokens.to_vec(), cx.cfg());
    let block = parser::parse(&mut parser);
    let item = block.generate(cx, None);

    let attrs = vec![quote_attr!(cx, #[allow(non_snake_case)])];

    let pub_use_super_star = cx.item_use_glob(DUMMY_SP,
                                              ast::Visibility::Public,
                                              vec![cx.ident_of("super")]);

    let module = cx.item_mod(DUMMY_SP, DUMMY_SP, cx.ident_of("sup"),
                             attrs, vec![pub_use_super_star, item]);

    MacEager::items(SmallVector::one(module))
}
<commit_msg>Refactor `expand_speculate` using `quote_item!`.<commit_after>#![feature(rustc_private)]
#![feature(plugin_registrar, quote)]
extern crate rustc;
extern crate syntax;

use rustc::plugin::Registry;
use syntax::ast::TokenTree;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacEager, MacResult};
use syntax::parse::tts_to_parser;
use syntax::util::small_vector::SmallVector;

use generator::Generate;

mod block;
mod parser;
mod generator;

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

fn expand_speculate(cx: &mut ExtCtxt, _sp: Span, tokens: &[TokenTree]) -> Box<MacResult + 'static> {
    let mut parser = tts_to_parser(cx.parse_sess(), tokens.to_vec(), cx.cfg());
    let block = parser::parse(&mut parser);
    let item = block.generate(cx, None);

    let module = quote_item!(cx,
                             #[allow(non_snake_case)]
                             mod sup {
                                 pub use super::*;
                                 $item
                             }).unwrap();

    MacEager::items(SmallVector::one(module))
}
<|endoftext|>


<commit_before>#![feature(const_fn)]
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

extern crate serde;
extern crate serde_json;

use serde::Deserialize;
use std::fmt;
use std::io::{self, Read};
use std::convert;
use std::collections::HashMap;
use std::net::{
    TcpListener,
    TcpStream,
    SocketAddr,
};
use std::sync::{
    self,
    Mutex,
    Arc,
};
use std::sync::mpsc::{
    channel,
    Sender,
    TryRecvError,
};
use std::thread::{
    self,
    JoinHandle,
};

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Json(serde_json::Error),
    Sender,
    Unimplemented,
}

impl convert::From<serde_json::Error> for Error {
    fn from(err: serde_json::Error) -> Error {
        match err {
            serde_json::Error::IoError(err) => Error::Io(err),
            err => Error::Json(err),
        }
    }
}

impl convert::From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl<T> convert::From<sync::mpsc::SendError<T>> for Error {
    fn from(_: sync::mpsc::SendError<T>) -> Error {
        Error::Sender
    }
}

pub type Result<T> = std::result::Result<T, Error>;

pub fn handle_conn<F, Request, Reply>(stream: TcpStream, f: F) -> Result<()>
    where Request: 'static + fmt::Debug + Send + serde::de::Deserialize + serde::ser::Serialize,
          Reply: 'static + fmt::Debug + serde::ser::Serialize,
          F: 'static + Clone + Serve<Request, Reply>
{
    let read_stream = try!(stream.try_clone());
    let mut de = serde_json::Deserializer::new(read_stream.bytes());
    let stream = Arc::new(Mutex::new(stream));
    loop {
        let request_packet: Packet<Request> = try!(Packet::deserialize(&mut de));
        match request_packet {
            Packet::Shutdown => {
                let stream = stream.clone();
                let mut my_stream = stream.lock().unwrap();
                try!(serde_json::to_writer(&mut *my_stream, &request_packet));
                break;
            },
            Packet::Message(id, message) => {
                let f = f.clone();
                let arc_stream = stream.clone();
                thread::spawn(move || {
                    let reply = f.serve(&message).unwrap();
                    let reply_packet = Packet::Message(id, reply);
                    let mut my_stream = arc_stream.lock().unwrap();
                    serde_json::to_writer(&mut *my_stream, &reply_packet).unwrap();
                });
            },
        }
    }
    Ok(())
}

pub struct Shutdown {
    tx: Sender<()>,
    join_handle: JoinHandle<()>,
    addr: SocketAddr,
}

impl Shutdown {
    pub fn wait(self) {
        self.join_handle.join().unwrap();
    }

    pub fn shutdown(self) {
        self.tx.send(()).expect(&line!().to_string());
        TcpStream::connect(&self.addr).unwrap();
        self.join_handle.join().expect(&line!().to_string());
    }
}

pub fn serve_async<F, Request, Reply>(addr: &SocketAddr, f: F) -> io::Result<Shutdown>
    where Request: 'static + fmt::Debug + Send + serde::de::Deserialize + fmt::Debug + serde::ser::Serialize,
          Reply: 'static + fmt::Debug + serde::ser::Serialize,
          F: 'static + Clone + Serve<Request, Reply>,
{
    let listener = try!(TcpListener::bind(addr));
    let (die_tx, die_rx) = channel();
    let join_handle = thread::spawn(move || {
        for conn in listener.incoming() {
            match die_rx.try_recv() {
                Ok(_) => break,
                Err(TryRecvError::Disconnected) => {
                    println!("serve: sender disconnected ");
                    break;
                },
                _ => (),
            }
            let conn = match conn {
                Err(err) => {
                    println!("I couldn't unwrap the connection :( {:?}", err);
                    return;
                },
                Ok(c) => c,
            };
            let f = f.clone();
            thread::spawn(move || {
                if let Err(err) = handle_conn(conn, f) {
                    println!("error handling connection: {:?}", err);
                }
            });
        }
    });
    Ok(Shutdown{
        tx: die_tx,
        join_handle: join_handle,
        addr: addr.clone(),
    })
}

pub trait Serve<Request, Reply>: Send + Sync {
    fn serve(&self, request: &Request) -> io::Result<Reply>;
}

impl<Request, Reply, S> Serve<Request, Reply> for Arc<S>
    where S: Serve<Request, Reply>
{
    fn serve(&self, request: &Request) -> io::Result<Reply> {
        S::serve(self, request)
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
enum Packet<T> {
    Message(u64, T),
    Shutdown,
}

fn reader<Reply>(
    stream: TcpStream,
    requests: Arc<Mutex<HashMap<u64, Sender<Reply>>>>)
    where Reply: serde::Deserialize
{
    let mut de = serde_json::Deserializer::new(stream.bytes());
    loop {
        match Packet::deserialize(&mut de) {
            Ok(Packet::Message(id, reply)) => {
                let mut requests = requests.lock().unwrap();
                let reply_tx = requests.remove(&id).unwrap();
                reply_tx.send(reply).unwrap();
            },
            Ok(Packet::Shutdown) => {
                break;
            }
            // TODO: This shutdown logic is janky.. What's the right way to do this?
            Err(err) => panic!("unexpected error while parsing!: {:?}", err),
        }
    }
}

fn increment(cur_id: &mut u64) -> u64 {
    let id = *cur_id;
    *cur_id += 1;
    id
}

struct SyncedClientState {
    next_id: u64,
    stream: TcpStream,
}

pub struct Client<Reply> {
    synced_state: Mutex<SyncedClientState>,
    requests: Arc<Mutex<HashMap<u64, Sender<Reply>>>>,
    reader_guard: thread::JoinHandle<()>,
}

impl<Reply> Client<Reply>
    where Reply: serde::de::Deserialize + Send + 'static
{
    pub fn new(stream: TcpStream) -> Result<Self> {
        let requests = Arc::new(Mutex::new(HashMap::new()));
        let reader_stream = try!(stream.try_clone());
        let reader_requests = requests.clone();
        let reader_guard =
            thread::spawn(move || reader(reader_stream, reader_requests));
        Ok(Client{
            synced_state: Mutex::new(SyncedClientState{
                next_id: 0,
                stream: stream,
            }),
            requests: requests,
            reader_guard: reader_guard,
        })
    }

    pub fn rpc<Request>(&self, request: &Request) -> Result<Reply>
        where Request: serde::ser::Serialize + Clone + Send + 'static
    {
        let (tx, rx) = channel();
        let mut state = self.synced_state.lock().unwrap();
        let id = increment(&mut state.next_id);
        {
            let mut requests = self.requests.lock().unwrap();
            requests.insert(id, tx);
        }
        let packet = Packet::Message(id, request.clone());
        try!(serde_json::to_writer(&mut state.stream, &packet));
        drop(state);
        Ok(rx.recv().unwrap())
    }

    pub fn disconnect<Request: serde::Serialize>(self) -> Result<()> {
        {
            let mut state = self.synced_state.lock().unwrap();
            let packet: Packet<Request> = Packet::Shutdown;
            try!(serde_json::to_writer(&mut state.stream, &packet));
        }
        self.reader_guard.join().unwrap();
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use serde;
    use super::*;
    use std::fmt;
    use std::io;
    use std::net::{TcpStream, SocketAddr, ToSocketAddrs};
    use std::sync::{Arc, Mutex, Barrier};
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::thread;

    const PORT: AtomicUsize = AtomicUsize::new(10000);

    fn next_addr() -> SocketAddr {
        let addr = format!("127.0.0.1:{}", PORT.fetch_add(1, Ordering::SeqCst));
        addr.to_socket_addrs().unwrap().next().unwrap()
        //ToSocketAddrs::to_socket_addrs(addr.as_ref()).unwrap().next().unwrap()
    }

    #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
    enum Request {
        Increment
    }

    #[derive(Debug, PartialEq, Serialize, Deserialize)]
    enum Reply {
        Increment(u64)
    }

    struct Server {
        counter: Mutex<u64>,
    }

    impl Serve<Request, Reply> for Server {
        fn serve(&self, _: &Request) -> io::Result<Reply> {
            let mut counter = self.counter.lock().unwrap();
            let reply = Reply::Increment(*counter);
            *counter += 1;
            Ok(reply)
        }
    }

    impl Server {
        fn new() -> Server {
            Server{counter: Mutex::new(0)}
        }

        fn count(&self) -> u64 {
            *self.counter.lock().unwrap()
        }
    }

    fn wtf<F, Request, Reply>(server: F) -> (SocketAddr, Shutdown)
        where Request: 'static + fmt::Debug + Send + serde::de::Deserialize + fmt::Debug + serde::ser::Serialize,
              Reply: 'static + fmt::Debug + Send + serde::ser::Serialize,
              F: 'static + Clone + Serve<Request, Reply>
    {
        let mut addr;
        let mut shutdown;
        while let &Err(_) = {shutdown = serve_async({addr = next_addr(); &addr}, server.clone()); &shutdown} { }
        (addr, shutdown.unwrap())
    }

    #[test]
    fn test_handle() {
        let server = Arc::new(Server::new());
        let (addr, shutdown) = wtf(server.clone());
        let client_stream = TcpStream::connect(&addr).unwrap();
        let client: Client<Reply> = Client::new(client_stream).expect(&line!().to_string());
        client.disconnect::<Request>().unwrap();
        shutdown.shutdown();
    }

    #[test]
    fn test() {
        let server = Arc::new(Server::new());
        let (addr, shutdown) = wtf(server.clone());
        let client_stream = TcpStream::connect(&addr).unwrap();
        let client = Client::new(client_stream).unwrap();
        assert_eq!(Reply::Increment(0), client.rpc(&Request::Increment).unwrap());
        assert_eq!(1, server.count());
        assert_eq!(Reply::Increment(1), client.rpc(&Request::Increment).unwrap());
        assert_eq!(2, server.count());
        client.disconnect::<Request>().unwrap();
        shutdown.shutdown();
    }

    struct BarrierServer {
        barrier: Barrier,
        inner: Server,
    }

    impl Serve<Request, Reply> for BarrierServer {
        fn serve(&self, request: &Request) -> io::Result<Reply> {
            self.barrier.wait();
            let reply = try!(self.inner.serve(request));
            Ok(reply)
        }
    }

    impl BarrierServer {
        fn new(n: usize) -> BarrierServer {
            BarrierServer{barrier: Barrier::new(n), inner: Server::new()}
        }

        fn count(&self) -> u64 {
            self.inner.count()
        }
    }

    #[test]
    fn test_concurrent() {
        let server = Arc::new(BarrierServer::new(10));
        let (addr, shutdown) = wtf(server.clone());
        let client_stream = TcpStream::connect(&addr).unwrap();
        let client: Arc<Client<Reply>> = Arc::new(Client::new(client_stream).unwrap());
        let mut join_handles = vec![];
        for _ in 0..10 {
            let my_client = client.clone();
            join_handles.push(thread::spawn(move || my_client.rpc(&Request::Increment).unwrap()));
        }
        for handle in join_handles.into_iter() {
            handle.join().unwrap();
        }
        assert_eq!(10, server.count());
        let client = match Arc::try_unwrap(client) {
            Err(_) => panic!("couldn't unwrap arc"),
            Ok(c) => c,
        };
        client.disconnect::<Request>().unwrap();
        shutdown.shutdown();
    }
}
<commit_msg>Remove commented code<commit_after>#![feature(const_fn)]
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]

extern crate serde;
extern crate serde_json;

use serde::Deserialize;
use std::fmt;
use std::io::{self, Read};
use std::convert;
use std::collections::HashMap;
use std::net::{
    TcpListener,
    TcpStream,
    SocketAddr,
};
use std::sync::{
    self,
    Mutex,
    Arc,
};
use std::sync::mpsc::{
    channel,
    Sender,
    TryRecvError,
};
use std::thread::{
    self,
    JoinHandle,
};

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Json(serde_json::Error),
    Sender,
    Unimplemented,
}

impl convert::From<serde_json::Error> for Error {
    fn from(err: serde_json::Error) -> Error {
        match err {
            serde_json::Error::IoError(err) => Error::Io(err),
            err => Error::Json(err),
        }
    }
}

impl convert::From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl<T> convert::From<sync::mpsc::SendError<T>> for Error {
    fn from(_: sync::mpsc::SendError<T>) -> Error {
        Error::Sender
    }
}

pub type Result<T> = std::result::Result<T, Error>;

pub fn handle_conn<F, Request, Reply>(stream: TcpStream, f: F) -> Result<()>
    where Request: 'static + fmt::Debug + Send + serde::de::Deserialize + serde::ser::Serialize,
          Reply: 'static + fmt::Debug + serde::ser::Serialize,
          F: 'static + Clone + Serve<Request, Reply>
{
    let read_stream = try!(stream.try_clone());
    let mut de = serde_json::Deserializer::new(read_stream.bytes());
    let stream = Arc::new(Mutex::new(stream));
    loop {
        let request_packet: Packet<Request> = try!(Packet::deserialize(&mut de));
        match request_packet {
            Packet::Shutdown => {
                let stream = stream.clone();
                let mut my_stream = stream.lock().unwrap();
                try!(serde_json::to_writer(&mut *my_stream, &request_packet));
                break;
            },
            Packet::Message(id, message) => {
                let f = f.clone();
                let arc_stream = stream.clone();
                thread::spawn(move || {
                    let reply = f.serve(&message).unwrap();
                    let reply_packet = Packet::Message(id, reply);
                    let mut my_stream = arc_stream.lock().unwrap();
                    serde_json::to_writer(&mut *my_stream, &reply_packet).unwrap();
                });
            },
        }
    }
    Ok(())
}

pub struct Shutdown {
    tx: Sender<()>,
    join_handle: JoinHandle<()>,
    addr: SocketAddr,
}

impl Shutdown {
    pub fn wait(self) {
        self.join_handle.join().unwrap();
    }

    pub fn shutdown(self) {
        self.tx.send(()).expect(&line!().to_string());
        TcpStream::connect(&self.addr).unwrap();
        self.join_handle.join().expect(&line!().to_string());
    }
}

pub fn serve_async<F, Request, Reply>(addr: &SocketAddr, f: F) -> io::Result<Shutdown>
    where Request: 'static + fmt::Debug + Send + serde::de::Deserialize + fmt::Debug + serde::ser::Serialize,
          Reply: 'static + fmt::Debug + serde::ser::Serialize,
          F: 'static + Clone + Serve<Request, Reply>,
{
    let listener = try!(TcpListener::bind(addr));
    let (die_tx, die_rx) = channel();
    let join_handle = thread::spawn(move || {
        for conn in listener.incoming() {
            match die_rx.try_recv() {
                Ok(_) => break,
                Err(TryRecvError::Disconnected) => {
                    println!("serve: sender disconnected ");
                    break;
                },
                _ => (),
            }
            let conn = match conn {
                Err(err) => {
                    println!("I couldn't unwrap the connection :( {:?}", err);
                    return;
                },
                Ok(c) => c,
            };
            let f = f.clone();
            thread::spawn(move || {
                if let Err(err) = handle_conn(conn, f) {
                    println!("error handling connection: {:?}", err);
                }
            });
        }
    });
    Ok(Shutdown{
        tx: die_tx,
        join_handle: join_handle,
        addr: addr.clone(),
    })
}

pub trait Serve<Request, Reply>: Send + Sync {
    fn serve(&self, request: &Request) -> io::Result<Reply>;
}

impl<Request, Reply, S> Serve<Request, Reply> for Arc<S>
    where S: Serve<Request, Reply>
{
    fn serve(&self, request: &Request) -> io::Result<Reply> {
        S::serve(self, request)
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
enum Packet<T> {
    Message(u64, T),
    Shutdown,
}

fn reader<Reply>(
    stream: TcpStream,
    requests: Arc<Mutex<HashMap<u64, Sender<Reply>>>>)
    where Reply: serde::Deserialize
{
    let mut de = serde_json::Deserializer::new(stream.bytes());
    loop {
        match Packet::deserialize(&mut de) {
            Ok(Packet::Message(id, reply)) => {
                let mut requests = requests.lock().unwrap();
                let reply_tx = requests.remove(&id).unwrap();
                reply_tx.send(reply).unwrap();
            },
            Ok(Packet::Shutdown) => {
                break;
            }
            // TODO: This shutdown logic is janky.. What's the right way to do this?
            Err(err) => panic!("unexpected error while parsing!: {:?}", err),
        }
    }
}

fn increment(cur_id: &mut u64) -> u64 {
    let id = *cur_id;
    *cur_id += 1;
    id
}

struct SyncedClientState {
    next_id: u64,
    stream: TcpStream,
}

pub struct Client<Reply> {
    synced_state: Mutex<SyncedClientState>,
    requests: Arc<Mutex<HashMap<u64, Sender<Reply>>>>,
    reader_guard: thread::JoinHandle<()>,
}

impl<Reply> Client<Reply>
    where Reply: serde::de::Deserialize + Send + 'static
{
    pub fn new(stream: TcpStream) -> Result<Self> {
        let requests = Arc::new(Mutex::new(HashMap::new()));
        let reader_stream = try!(stream.try_clone());
        let reader_requests = requests.clone();
        let reader_guard =
            thread::spawn(move || reader(reader_stream, reader_requests));
        Ok(Client{
            synced_state: Mutex::new(SyncedClientState{
                next_id: 0,
                stream: stream,
            }),
            requests: requests,
            reader_guard: reader_guard,
        })
    }

    pub fn rpc<Request>(&self, request: &Request) -> Result<Reply>
        where Request: serde::ser::Serialize + Clone + Send + 'static
    {
        let (tx, rx) = channel();
        let mut state = self.synced_state.lock().unwrap();
        let id = increment(&mut state.next_id);
        {
            let mut requests = self.requests.lock().unwrap();
            requests.insert(id, tx);
        }
        let packet = Packet::Message(id, request.clone());
        try!(serde_json::to_writer(&mut state.stream, &packet));
        drop(state);
        Ok(rx.recv().unwrap())
    }

    pub fn disconnect<Request: serde::Serialize>(self) -> Result<()> {
        {
            let mut state = self.synced_state.lock().unwrap();
            let packet: Packet<Request> = Packet::Shutdown;
            try!(serde_json::to_writer(&mut state.stream, &packet));
        }
        self.reader_guard.join().unwrap();
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use serde;
    use super::*;
    use std::fmt;
    use std::io;
    use std::net::{TcpStream, SocketAddr, ToSocketAddrs};
    use std::sync::{Arc, Mutex, Barrier};
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::thread;

    const PORT: AtomicUsize = AtomicUsize::new(10000);

    fn next_addr() -> SocketAddr {
        let addr = format!("127.0.0.1:{}", PORT.fetch_add(1, Ordering::SeqCst));
        addr.to_socket_addrs().unwrap().next().unwrap()
    }

    #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
    enum Request {
        Increment
    }

    #[derive(Debug, PartialEq, Serialize, Deserialize)]
    enum Reply {
        Increment(u64)
    }

    struct Server {
        counter: Mutex<u64>,
    }

    impl Serve<Request, Reply> for Server {
        fn serve(&self, _: &Request) -> io::Result<Reply> {
            let mut counter = self.counter.lock().unwrap();
            let reply = Reply::Increment(*counter);
            *counter += 1;
            Ok(reply)
        }
    }

    impl Server {
        fn new() -> Server {
            Server{counter: Mutex::new(0)}
        }

        fn count(&self) -> u64 {
            *self.counter.lock().unwrap()
        }
    }

    fn wtf<F, Request, Reply>(server: F) -> (SocketAddr, Shutdown)
        where Request: 'static + fmt::Debug + Send + serde::de::Deserialize + fmt::Debug + serde::ser::Serialize,
              Reply: 'static + fmt::Debug + Send + serde::ser::Serialize,
              F: 'static + Clone + Serve<Request, Reply>
    {
        let mut addr;
        let mut shutdown;
        while let &Err(_) = {shutdown = serve_async({addr = next_addr(); &addr}, server.clone()); &shutdown} { }
        (addr, shutdown.unwrap())
    }

    #[test]
    fn test_handle() {
        let server = Arc::new(Server::new());
        let (addr, shutdown) = wtf(server.clone());
        let client_stream = TcpStream::connect(&addr).unwrap();
        let client: Client<Reply> = Client::new(client_stream).expect(&line!().to_string());
        client.disconnect::<Request>().unwrap();
        shutdown.shutdown();
    }

    #[test]
    fn test() {
        let server = Arc::new(Server::new());
        let (addr, shutdown) = wtf(server.clone());
        let client_stream = TcpStream::connect(&addr).unwrap();
        let client = Client::new(client_stream).unwrap();
        assert_eq!(Reply::Increment(0), client.rpc(&Request::Increment).unwrap());
        assert_eq!(1, server.count());
        assert_eq!(Reply::Increment(1), client.rpc(&Request::Increment).unwrap());
        assert_eq!(2, server.count());
        client.disconnect::<Request>().unwrap();
        shutdown.shutdown();
    }

    struct BarrierServer {
        barrier: Barrier,
        inner: Server,
    }

    impl Serve<Request, Reply> for BarrierServer {
        fn serve(&self, request: &Request) -> io::Result<Reply> {
            self.barrier.wait();
            let reply = try!(self.inner.serve(request));
            Ok(reply)
        }
    }

    impl BarrierServer {
        fn new(n: usize) -> BarrierServer {
            BarrierServer{barrier: Barrier::new(n), inner: Server::new()}
        }

        fn count(&self) -> u64 {
            self.inner.count()
        }
    }

    #[test]
    fn test_concurrent() {
        let server = Arc::new(BarrierServer::new(10));
        let (addr, shutdown) = wtf(server.clone());
        let client_stream = TcpStream::connect(&addr).unwrap();
        let client: Arc<Client<Reply>> = Arc::new(Client::new(client_stream).unwrap());
        let mut join_handles = vec![];
        for _ in 0..10 {
            let my_client = client.clone();
            join_handles.push(thread::spawn(move || my_client.rpc(&Request::Increment).unwrap()));
        }
        for handle in join_handles.into_iter() {
            handle.join().unwrap();
        }
        assert_eq!(10, server.count());
        let client = match Arc::try_unwrap(client) {
            Err(_) => panic!("couldn't unwrap arc"),
            Ok(c) => c,
        };
        client.disconnect::<Request>().unwrap();
        shutdown.shutdown();
    }
}
<|endoftext|>


<commit_before>#![no_std]

#[doc(hidden)]
pub extern crate core as _core;

/// Asserts at compile-time that the types have equal sizes.
///
/// # Example
///
/// ```
/// #[macro_use]
/// extern crate static_assertions;
///
/// struct Byte(u8);
///
/// fn main() {
///     assert_eq_size!(Byte, u8);
///     // assert_eq_size!(Byte, u16); // Fails to compile
///
///     // Supports unlimited arguments:
///     assert_eq_size!([Byte; 4], [u16; 2], u32);
/// }
/// ```
#[macro_export]
macro_rules! assert_eq_size {
    ($x:ty, $($xs:ty),+) => {
        #[allow(unused_unsafe)]
        unsafe {
            use $crate::_core::mem::{forget, transmute, uninitialized};
            $(forget::<$xs>(transmute(uninitialized::<$x>()));)+
        }
    }
}

/// Asserts at compile-time that the values have equal sizes.
#[macro_export]
macro_rules! assert_eq_size_val {
    ($x:expr, $($xs:expr),+) => {
        #[allow(unused_unsafe)]
        unsafe {
            use $crate::_core::{mem, ptr};
            let mut copy = ptr::read(&$x);
            $(ptr::write(&mut copy, mem::transmute(ptr::read(&$xs)));)+
            mem::forget(copy);
        }
    }
}
<commit_msg>Add to assert_eq_size doc<commit_after>#![no_std]

#[doc(hidden)]
pub extern crate core as _core;

/// Asserts at compile-time that the types have equal sizes.
///
/// This especially is useful for when coercing pointers between different types
/// and ensuring the underlying values are the same size.
///
/// # Example
///
/// ```
/// #[macro_use]
/// extern crate static_assertions;
///
/// struct Byte(u8);
///
/// fn main() {
///     assert_eq_size!(Byte, u8);
///     // assert_eq_size!(Byte, u16); // Fails to compile
///
///     // Supports unlimited arguments:
///     assert_eq_size!([Byte; 4], [u16; 2], u32);
/// }
/// ```
#[macro_export]
macro_rules! assert_eq_size {
    ($x:ty, $($xs:ty),+) => {
        #[allow(unused_unsafe)]
        unsafe {
            use $crate::_core::mem::{forget, transmute, uninitialized};
            $(forget::<$xs>(transmute(uninitialized::<$x>()));)+
        }
    }
}

/// Asserts at compile-time that the values have equal sizes.
#[macro_export]
macro_rules! assert_eq_size_val {
    ($x:expr, $($xs:expr),+) => {
        #[allow(unused_unsafe)]
        unsafe {
            use $crate::_core::{mem, ptr};
            let mut copy = ptr::read(&$x);
            $(ptr::write(&mut copy, mem::transmute(ptr::read(&$xs)));)+
            mem::forget(copy);
        }
    }
}
<|endoftext|>


<commit_before>use super::DELIMITER;
use super::super::ledger::request::ProtocolVersion;

use ursa::cl::{
    CredentialPrimaryPublicKey,
    CredentialRevocationPublicKey,
    CredentialPrivateKey,
    CredentialKeyCorrectnessProof
};

use std::collections::HashMap;
use named_type::NamedType;

pub const CL_SIGNATURE_TYPE: &str = "CL";
pub const CRED_DEF_MARKER: &str = "3";

#[derive(Deserialize, Debug, Serialize, PartialEq, Clone)]
pub enum SignatureType {
    CL
}

impl SignatureType {
    pub fn to_str(&self) -> &'static str {
        match *self {
            SignatureType::CL => CL_SIGNATURE_TYPE
        }
    }
}

fn default_false() -> bool { false }

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CredentialDefinitionConfig {
    #[serde(default = "default_false")]
    pub support_revocation: bool
}

impl Default for CredentialDefinitionConfig {
    fn default() -> Self {
        CredentialDefinitionConfig {
            support_revocation: false
        }
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CredentialDefinitionData {
    pub primary: CredentialPrimaryPublicKey,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub revocation: Option<CredentialRevocationPublicKey>
}

#[derive(Deserialize, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CredentialDefinitionV1 {
    pub id: String,
    pub schema_id: String,
    #[serde(rename = "type")]
    pub signature_type: SignatureType,
    pub tag: String,
    pub value: CredentialDefinitionData
}

#[derive(Debug, Serialize, Deserialize, NamedType)]
#[serde(tag = "ver")]
pub enum CredentialDefinition {
    #[serde(rename = "1.0")]
    CredentialDefinitionV1(CredentialDefinitionV1)
}

impl CredentialDefinition {
    pub fn cred_def_id(did: &str, schema_id: &str, signature_type: &str, tag: &str) -> String {
        if ProtocolVersion::is_node_1_3(){
            format!("{}{}{}{}{}{}{}", did, DELIMITER, CRED_DEF_MARKER, DELIMITER, signature_type, DELIMITER, schema_id)
        } else {
            format!("{}{}{}{}{}{}{}{}{}", did, DELIMITER, CRED_DEF_MARKER, DELIMITER, signature_type, DELIMITER, schema_id, DELIMITER, tag)
        }
    }

    pub fn issuer_did(cred_def_id: &str) -> Option<String> {
        cred_def_id.split(":").collect::<Vec<&str>>().get(0).and_then(|s| Some(s.to_string()))
    }
}

impl From<CredentialDefinition> for CredentialDefinitionV1 {
    fn from(cred_def: CredentialDefinition) -> Self {
        match cred_def {
            CredentialDefinition::CredentialDefinitionV1(cred_def) => cred_def
        }
    }
}

pub fn cred_defs_map_to_cred_defs_v1_map(cred_defs: HashMap<String, CredentialDefinition>) -> HashMap<String, CredentialDefinitionV1> {
    let mut cred_defs_v1: HashMap<String, CredentialDefinitionV1> = HashMap::new();

    for (cred_def_id, cred_def) in cred_defs {
        cred_defs_v1.insert(cred_def_id, CredentialDefinitionV1::from(cred_def));
    }

    cred_defs_v1
}

#[derive(Debug, Serialize, Deserialize, NamedType)]
pub struct CredentialDefinitionPrivateKey {
    pub value: CredentialPrivateKey
}

#[derive(Debug, Serialize, Deserialize, NamedType)]
pub struct CredentialDefinitionCorrectnessProof {
    pub value: CredentialKeyCorrectnessProof
}
<commit_msg>replace single char str by single char char<commit_after>use super::DELIMITER;
use super::super::ledger::request::ProtocolVersion;

use ursa::cl::{
    CredentialPrimaryPublicKey,
    CredentialRevocationPublicKey,
    CredentialPrivateKey,
    CredentialKeyCorrectnessProof
};

use std::collections::HashMap;
use named_type::NamedType;

pub const CL_SIGNATURE_TYPE: &str = "CL";
pub const CRED_DEF_MARKER: &str = "3";

#[derive(Deserialize, Debug, Serialize, PartialEq, Clone)]
pub enum SignatureType {
    CL
}

impl SignatureType {
    pub fn to_str(&self) -> &'static str {
        match *self {
            SignatureType::CL => CL_SIGNATURE_TYPE
        }
    }
}

fn default_false() -> bool { false }

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CredentialDefinitionConfig {
    #[serde(default = "default_false")]
    pub support_revocation: bool
}

impl Default for CredentialDefinitionConfig {
    fn default() -> Self {
        CredentialDefinitionConfig {
            support_revocation: false
        }
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct CredentialDefinitionData {
    pub primary: CredentialPrimaryPublicKey,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub revocation: Option<CredentialRevocationPublicKey>
}

#[derive(Deserialize, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CredentialDefinitionV1 {
    pub id: String,
    pub schema_id: String,
    #[serde(rename = "type")]
    pub signature_type: SignatureType,
    pub tag: String,
    pub value: CredentialDefinitionData
}

#[derive(Debug, Serialize, Deserialize, NamedType)]
#[serde(tag = "ver")]
pub enum CredentialDefinition {
    #[serde(rename = "1.0")]
    CredentialDefinitionV1(CredentialDefinitionV1)
}

impl CredentialDefinition {
    pub fn cred_def_id(did: &str, schema_id: &str, signature_type: &str, tag: &str) -> String {
        if ProtocolVersion::is_node_1_3(){
            format!("{}{}{}{}{}{}{}", did, DELIMITER, CRED_DEF_MARKER, DELIMITER, signature_type, DELIMITER, schema_id)
        } else {
            format!("{}{}{}{}{}{}{}{}{}", did, DELIMITER, CRED_DEF_MARKER, DELIMITER, signature_type, DELIMITER, schema_id, DELIMITER, tag)
        }
    }

    pub fn issuer_did(cred_def_id: &str) -> Option<String> {
        cred_def_id.split(':').collect::<Vec<&str>>().get(0).and_then(|s| Some(s.to_string()))
    }
}

impl From<CredentialDefinition> for CredentialDefinitionV1 {
    fn from(cred_def: CredentialDefinition) -> Self {
        match cred_def {
            CredentialDefinition::CredentialDefinitionV1(cred_def) => cred_def
        }
    }
}

pub fn cred_defs_map_to_cred_defs_v1_map(cred_defs: HashMap<String, CredentialDefinition>) -> HashMap<String, CredentialDefinitionV1> {
    let mut cred_defs_v1: HashMap<String, CredentialDefinitionV1> = HashMap::new();

    for (cred_def_id, cred_def) in cred_defs {
        cred_defs_v1.insert(cred_def_id, CredentialDefinitionV1::from(cred_def));
    }

    cred_defs_v1
}

#[derive(Debug, Serialize, Deserialize, NamedType)]
pub struct CredentialDefinitionPrivateKey {
    pub value: CredentialPrivateKey
}

#[derive(Debug, Serialize, Deserialize, NamedType)]
pub struct CredentialDefinitionCorrectnessProof {
    pub value: CredentialKeyCorrectnessProof
}
<|endoftext|>


<commit_before>// Rust JSON-RPC Library
// Written in 2015 by
//   Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # Rust JSON-RPC Library
//!
//! Rust support for the JSON-RPC 2.0 protocol.
//!

#![crate_type = "lib"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![crate_name = "jsonrpc"]
// Coding conventions
#![deny(non_upper_case_globals)]
#![deny(non_camel_case_types)]
#![deny(non_snake_case)]
#![deny(unused_mut)]
#![warn(missing_docs)]

// extern crate base64;
// extern crate http;
extern crate serde;
#[macro_use]
extern crate serde_derive;
pub extern crate serde_json;

#[cfg(feature = "base64-compat")]
pub extern crate base64;

pub mod client;
pub mod error;
mod util;

#[cfg(feature = "simple_http")]
pub mod simple_http;

// Re-export error type
pub use error::Error;
pub use client::{Client, Transport};

use serde_json::value::RawValue;

/// Shorthand method to convert an argument into a [Box<serde_json::value::RawValue>].
/// Since serializers rarely fail, it's probably easier to use [arg] instead.
pub fn try_arg<T: serde::Serialize>(arg: T) -> Result<Box<RawValue>, serde_json::Error> {
    RawValue::from_string(serde_json::to_string(&arg)?)
}

/// Shorthand method to convert an argument into a [Box<serde_json::value::RawValue>].
///
/// This conversion should not fail, so to avoid returning a [Result],
/// in case of an error, the error is serialized as the return value.
pub fn arg<T: serde::Serialize>(arg: T) -> Box<RawValue> {
    match try_arg(arg) {
        Ok(v) => v,
        Err(e) => RawValue::from_string(format!("<<ERROR SERIALIZING ARGUMENT: {}>>", e))
            .unwrap_or(RawValue::from_string("<<ERROR SERIALIZING ARGUMENT>>".to_owned()).unwrap()),
    }
}

#[derive(Debug, Clone, Serialize)]
/// A JSONRPC request object
pub struct Request<'a> {
    /// The name of the RPC call
    pub method: &'a str,
    /// Parameters to the RPC call
    pub params: &'a [Box<RawValue>],
    /// Identifier for this Request, which should appear in the response
    pub id: serde_json::Value,
    /// jsonrpc field, MUST be "2.0"
    pub jsonrpc: Option<&'a str>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
/// A JSONRPC response object
pub struct Response {
    /// A result if there is one, or null
    pub result: Option<Box<RawValue>>,
    /// An error if there is one, or null
    pub error: Option<error::RpcError>,
    /// Identifier for this Request, which should match that of the request
    pub id: serde_json::Value,
    /// jsonrpc field, MUST be "2.0"
    pub jsonrpc: Option<String>,
}

impl Response {
    /// Extract the result from a response
    pub fn result<T: for<'a> serde::de::Deserialize<'a>>(&self) -> Result<T, Error> {
        if let Some(ref e) = self.error {
            return Err(Error::Rpc(e.clone()));
        }

        if let Some(ref res) = self.result {
            serde_json::from_str(res.get()).map_err(Error::Json)
        } else {
            serde_json::from_value(serde_json::Value::Null).map_err(Error::Json)
        }
    }

    /// Return the RPC error, if there was one, but do not check the result
    pub fn check_error(self) -> Result<(), Error> {
        if let Some(e) = self.error {
            Err(Error::Rpc(e))
        } else {
            Ok(())
        }
    }

    /// Returns whether or not the `result` field is empty
    pub fn is_none(&self) -> bool {
        self.result.is_none()
    }
}

#[cfg(test)]
mod tests {

    use super::Response;
    use serde_json;
    use serde_json::value::RawValue;

    #[test]
    fn response_is_none() {
        let joanna = Response {
            result: Some(RawValue::from_string(serde_json::to_string(&true).unwrap()).unwrap()),
            error: None,
            id: From::from(81),
            jsonrpc: Some(String::from("2.0")),
        };

        let bill = Response {
            result: None,
            error: None,
            id: From::from(66),
            jsonrpc: Some(String::from("2.0")),
        };

        assert!(!joanna.is_none());
        assert!(bill.is_none());
    }

    #[test]
    fn response_extract() {
        let obj = vec!["Mary", "had", "a", "little", "lamb"];
        let response = Response {
            result: Some(RawValue::from_string(serde_json::to_string(&obj).unwrap()).unwrap()),
            error: None,
            id: serde_json::Value::Null,
            jsonrpc: Some(String::from("2.0")),
        };
        let recovered1: Vec<String> = response.result().unwrap();
        assert!(response.clone().check_error().is_ok());
        let recovered2: Vec<String> = response.result().unwrap();
        assert_eq!(obj, recovered1);
        assert_eq!(obj, recovered2);
    }

    #[test]
    fn null_result() {
        let s = r#"{"result":null,"error":null,"id":"test"}"#;
        let response: Response = serde_json::from_str(&s).unwrap();
        let recovered1: Result<(), _> = response.result();
        let recovered2: Result<(), _> = response.clone().result();
        assert!(recovered1.is_ok());
        assert!(recovered2.is_ok());

        let recovered1: Result<String, _> = response.result();
        let recovered2: Result<String, _> = response.clone().result();
        assert!(recovered1.is_err());
        assert!(recovered2.is_err());
    }

    #[test]
    fn batch_response() {
        // from the jsonrpc.org spec example
        let s = r#"[
            {"jsonrpc": "2.0", "result": 7, "id": "1"},
            {"jsonrpc": "2.0", "result": 19, "id": "2"},
            {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
            {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"},
            {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"}
        ]"#;
        let batch_response: Vec<Response> = serde_json::from_str(&s).unwrap();
        assert_eq!(batch_response.len(), 5);
    }

    #[test]
    fn test_arg() {
        macro_rules! test_arg {
            ($val:expr, $t:ty) => {{
                let val1: $t = $val;
                let arg = super::arg(val1.clone());
                let val2: $t = serde_json::from_str(arg.get()).expect(stringify!($val));
                assert_eq!(val1, val2, "failed test for {}", stringify!($val));
            }}
        }

        test_arg!(true, bool);
        test_arg!(42, u8);
        test_arg!(42, usize);
        test_arg!(42, isize);
        test_arg!(vec![42, 35], Vec<u8>);
        test_arg!(String::from("test"), String);

        #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
        struct Test {
            v: String,
        }
        test_arg!(Test { v: String::from("test"), }, Test);
    }
}
<commit_msg>remove some commented out `extern crate` lines and old rustisms<commit_after>// Rust JSON-RPC Library
// Written in 2015 by
//   Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # Rust JSON-RPC Library
//!
//! Rust support for the JSON-RPC 2.0 protocol.
//!

// Coding conventions
#![deny(non_upper_case_globals)]
#![deny(non_camel_case_types)]
#![deny(non_snake_case)]
#![deny(unused_mut)]
#![warn(missing_docs)]

extern crate serde;
#[macro_use]
extern crate serde_derive;
pub extern crate serde_json;

#[cfg(feature = "base64-compat")]
pub extern crate base64;

pub mod client;
pub mod error;
mod util;

#[cfg(feature = "simple_http")]
pub mod simple_http;

// Re-export error type
pub use error::Error;
pub use client::{Client, Transport};

use serde_json::value::RawValue;

/// Shorthand method to convert an argument into a [Box<serde_json::value::RawValue>].
/// Since serializers rarely fail, it's probably easier to use [arg] instead.
pub fn try_arg<T: serde::Serialize>(arg: T) -> Result<Box<RawValue>, serde_json::Error> {
    RawValue::from_string(serde_json::to_string(&arg)?)
}

/// Shorthand method to convert an argument into a [Box<serde_json::value::RawValue>].
///
/// This conversion should not fail, so to avoid returning a [Result],
/// in case of an error, the error is serialized as the return value.
pub fn arg<T: serde::Serialize>(arg: T) -> Box<RawValue> {
    match try_arg(arg) {
        Ok(v) => v,
        Err(e) => RawValue::from_string(format!("<<ERROR SERIALIZING ARGUMENT: {}>>", e))
            .unwrap_or(RawValue::from_string("<<ERROR SERIALIZING ARGUMENT>>".to_owned()).unwrap()),
    }
}

#[derive(Debug, Clone, Serialize)]
/// A JSONRPC request object
pub struct Request<'a> {
    /// The name of the RPC call
    pub method: &'a str,
    /// Parameters to the RPC call
    pub params: &'a [Box<RawValue>],
    /// Identifier for this Request, which should appear in the response
    pub id: serde_json::Value,
    /// jsonrpc field, MUST be "2.0"
    pub jsonrpc: Option<&'a str>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
/// A JSONRPC response object
pub struct Response {
    /// A result if there is one, or null
    pub result: Option<Box<RawValue>>,
    /// An error if there is one, or null
    pub error: Option<error::RpcError>,
    /// Identifier for this Request, which should match that of the request
    pub id: serde_json::Value,
    /// jsonrpc field, MUST be "2.0"
    pub jsonrpc: Option<String>,
}

impl Response {
    /// Extract the result from a response
    pub fn result<T: for<'a> serde::de::Deserialize<'a>>(&self) -> Result<T, Error> {
        if let Some(ref e) = self.error {
            return Err(Error::Rpc(e.clone()));
        }

        if let Some(ref res) = self.result {
            serde_json::from_str(res.get()).map_err(Error::Json)
        } else {
            serde_json::from_value(serde_json::Value::Null).map_err(Error::Json)
        }
    }

    /// Return the RPC error, if there was one, but do not check the result
    pub fn check_error(self) -> Result<(), Error> {
        if let Some(e) = self.error {
            Err(Error::Rpc(e))
        } else {
            Ok(())
        }
    }

    /// Returns whether or not the `result` field is empty
    pub fn is_none(&self) -> bool {
        self.result.is_none()
    }
}

#[cfg(test)]
mod tests {

    use super::Response;
    use serde_json;
    use serde_json::value::RawValue;

    #[test]
    fn response_is_none() {
        let joanna = Response {
            result: Some(RawValue::from_string(serde_json::to_string(&true).unwrap()).unwrap()),
            error: None,
            id: From::from(81),
            jsonrpc: Some(String::from("2.0")),
        };

        let bill = Response {
            result: None,
            error: None,
            id: From::from(66),
            jsonrpc: Some(String::from("2.0")),
        };

        assert!(!joanna.is_none());
        assert!(bill.is_none());
    }

    #[test]
    fn response_extract() {
        let obj = vec!["Mary", "had", "a", "little", "lamb"];
        let response = Response {
            result: Some(RawValue::from_string(serde_json::to_string(&obj).unwrap()).unwrap()),
            error: None,
            id: serde_json::Value::Null,
            jsonrpc: Some(String::from("2.0")),
        };
        let recovered1: Vec<String> = response.result().unwrap();
        assert!(response.clone().check_error().is_ok());
        let recovered2: Vec<String> = response.result().unwrap();
        assert_eq!(obj, recovered1);
        assert_eq!(obj, recovered2);
    }

    #[test]
    fn null_result() {
        let s = r#"{"result":null,"error":null,"id":"test"}"#;
        let response: Response = serde_json::from_str(&s).unwrap();
        let recovered1: Result<(), _> = response.result();
        let recovered2: Result<(), _> = response.clone().result();
        assert!(recovered1.is_ok());
        assert!(recovered2.is_ok());

        let recovered1: Result<String, _> = response.result();
        let recovered2: Result<String, _> = response.clone().result();
        assert!(recovered1.is_err());
        assert!(recovered2.is_err());
    }

    #[test]
    fn batch_response() {
        // from the jsonrpc.org spec example
        let s = r#"[
            {"jsonrpc": "2.0", "result": 7, "id": "1"},
            {"jsonrpc": "2.0", "result": 19, "id": "2"},
            {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
            {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"},
            {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"}
        ]"#;
        let batch_response: Vec<Response> = serde_json::from_str(&s).unwrap();
        assert_eq!(batch_response.len(), 5);
    }

    #[test]
    fn test_arg() {
        macro_rules! test_arg {
            ($val:expr, $t:ty) => {{
                let val1: $t = $val;
                let arg = super::arg(val1.clone());
                let val2: $t = serde_json::from_str(arg.get()).expect(stringify!($val));
                assert_eq!(val1, val2, "failed test for {}", stringify!($val));
            }}
        }

        test_arg!(true, bool);
        test_arg!(42, u8);
        test_arg!(42, usize);
        test_arg!(42, isize);
        test_arg!(vec![42, 35], Vec<u8>);
        test_arg!(String::from("test"), String);

        #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
        struct Test {
            v: String,
        }
        test_arg!(Test { v: String::from("test"), }, Test);
    }
}
<|endoftext|>


<commit_before>#![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts)]
#![warn(rust_2018_idioms)]
#![warn(unused_lifetimes)]
#![warn(unreachable_pub)]

extern crate snap;
#[macro_use]
extern crate rustc_middle;
extern crate rustc_ast;
extern crate rustc_codegen_ssa;
extern crate rustc_data_structures;
extern crate rustc_errors;
extern crate rustc_fs_util;
extern crate rustc_hir;
extern crate rustc_incremental;
extern crate rustc_index;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;

// This prevents duplicating functions and statics that are already part of the host rustc process.
#[allow(unused_extern_crates)]
extern crate rustc_driver;

use std::any::Any;

use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::CodegenResults;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
use rustc_middle::ty::query::Providers;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;

use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::settings::{self, Configurable};

pub use crate::config::*;
use crate::prelude::*;

mod abi;
mod allocator;
mod analyze;
mod archive;
mod backend;
mod base;
mod cast;
mod codegen_i128;
mod common;
mod compiler_builtins;
mod config;
mod constant;
mod debuginfo;
mod discriminant;
mod driver;
mod inline_asm;
mod intrinsics;
mod linkage;
mod main_shim;
mod metadata;
mod num;
mod optimize;
mod pointer;
mod pretty_clif;
mod toolchain;
mod trap;
mod unsize;
mod value_and_place;
mod vtable;

mod prelude {
    pub(crate) use std::convert::{TryFrom, TryInto};

    pub(crate) use rustc_span::Span;

    pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
    pub(crate) use rustc_middle::bug;
    pub(crate) use rustc_middle::mir::{self, *};
    pub(crate) use rustc_middle::ty::layout::{self, TyAndLayout};
    pub(crate) use rustc_middle::ty::{
        self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut,
        TypeFoldable, UintTy,
    };
    pub(crate) use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx};

    pub(crate) use rustc_data_structures::fx::FxHashMap;

    pub(crate) use rustc_index::vec::Idx;

    pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
    pub(crate) use cranelift_codegen::ir::function::Function;
    pub(crate) use cranelift_codegen::ir::types;
    pub(crate) use cranelift_codegen::ir::{
        AbiParam, Block, ExternalName, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc,
        StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value,
    };
    pub(crate) use cranelift_codegen::isa::{self, CallConv};
    pub(crate) use cranelift_codegen::Context;
    pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
    pub(crate) use cranelift_module::{self, DataContext, DataId, FuncId, Linkage, Module};

    pub(crate) use crate::abi::*;
    pub(crate) use crate::base::{codegen_operand, codegen_place};
    pub(crate) use crate::cast::*;
    pub(crate) use crate::common::*;
    pub(crate) use crate::debuginfo::{DebugContext, UnwindContext};
    pub(crate) use crate::pointer::Pointer;
    pub(crate) use crate::trap::*;
    pub(crate) use crate::value_and_place::{CPlace, CPlaceInner, CValue};
}

struct PrintOnPanic<F: Fn() -> String>(F);
impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
    fn drop(&mut self) {
        if ::std::thread::panicking() {
            println!("{}", (self.0)());
        }
    }
}

/// The codegen context holds any information shared between the codegen of individual functions
/// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module).
struct CodegenCx<'tcx> {
    tcx: TyCtxt<'tcx>,
    global_asm: String,
    cached_context: Context,
    debug_context: Option<DebugContext<'tcx>>,
    unwind_context: UnwindContext,
}

impl<'tcx> CodegenCx<'tcx> {
    fn new(
        tcx: TyCtxt<'tcx>,
        backend_config: BackendConfig,
        isa: &dyn TargetIsa,
        debug_info: bool,
    ) -> Self {
        assert_eq!(pointer_ty(tcx), isa.pointer_type());

        let unwind_context =
            UnwindContext::new(tcx, isa, matches!(backend_config.codegen_mode, CodegenMode::Aot));
        let debug_context = if debug_info { Some(DebugContext::new(tcx, isa)) } else { None };
        CodegenCx {
            tcx,
            global_asm: String::new(),
            cached_context: Context::new(),
            debug_context,
            unwind_context,
        }
    }
}

pub struct CraneliftCodegenBackend {
    pub config: Option<BackendConfig>,
}

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, sess: &Session) {
        use rustc_session::config::Lto;
        match sess.lto() {
            Lto::No | Lto::ThinLocal => {}
            Lto::Thin | Lto::Fat => sess.warn("LTO is not supported. You may get a linker error."),
        }
    }

    fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
        Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
    }

    fn provide(&self, _providers: &mut Providers) {}
    fn provide_extern(&self, _providers: &mut Providers) {}

    fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> {
        vec![]
    }

    fn codegen_crate(
        &self,
        tcx: TyCtxt<'_>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
    ) -> Box<dyn Any> {
        tcx.sess.abort_if_errors();
        let config = if let Some(config) = self.config.clone() {
            config
        } else {
            BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
                .unwrap_or_else(|err| tcx.sess.fatal(&err))
        };
        match config.codegen_mode {
            CodegenMode::Aot => driver::aot::run_aot(tcx, config, metadata, need_metadata_module),
            CodegenMode::Jit | CodegenMode::JitLazy => {
                #[cfg(feature = "jit")]
                let _: ! = driver::jit::run_jit(tcx, config);

                #[cfg(not(feature = "jit"))]
                tcx.sess.fatal("jit support was disabled when compiling rustc_codegen_cranelift");
            }
        }
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        _sess: &Session,
    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
        Ok(*ongoing_codegen
            .downcast::<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)>()
            .unwrap())
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: CodegenResults,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_codegen_ssa::back::link::link_binary;

        link_binary::<crate::archive::ArArchiveBuilder<'_>>(
            sess,
            &codegen_results,
            outputs,
            &codegen_results.crate_name.as_str(),
        );

        Ok(())
    }
}

fn target_triple(sess: &Session) -> target_lexicon::Triple {
    sess.target.llvm_target.parse().unwrap()
}

fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::TargetIsa + 'static> {
    use target_lexicon::BinaryFormat;

    let target_triple = crate::target_triple(sess);

    let mut flags_builder = settings::builder();
    flags_builder.enable("is_pic").unwrap();
    flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
    let enable_verifier = if backend_config.enable_verifier { "true" } else { "false" };
    flags_builder.set("enable_verifier", enable_verifier).unwrap();

    let tls_model = match target_triple.binary_format {
        BinaryFormat::Elf => "elf_gd",
        BinaryFormat::Macho => "macho",
        BinaryFormat::Coff => "coff",
        _ => "none",
    };
    flags_builder.set("tls_model", tls_model).unwrap();

    flags_builder.set("enable_simd", "true").unwrap();

    flags_builder.set("enable_llvm_abi_extensions", "true").unwrap();

    flags_builder.set("regalloc", &backend_config.regalloc).unwrap();

    use rustc_session::config::OptLevel;
    match sess.opts.optimize {
        OptLevel::No => {
            flags_builder.set("opt_level", "none").unwrap();
        }
        OptLevel::Less | OptLevel::Default => {}
        OptLevel::Size | OptLevel::SizeMin | OptLevel::Aggressive => {
            flags_builder.set("opt_level", "speed_and_size").unwrap();
        }
    }

    let flags = settings::Flags::new(flags_builder);

    let variant = cranelift_codegen::isa::BackendVariant::MachInst;

    let isa_builder = match sess.opts.cg.target_cpu.as_deref() {
        Some("native") => {
            let builder = cranelift_native::builder_with_options(variant, true).unwrap();
            builder
        }
        Some(value) => {
            let mut builder =
                cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
            if let Err(_) = builder.enable(value) {
                sess.fatal("The specified target cpu isn't currently supported by Cranelift.");
            }
            builder
        }
        None => {
            let mut builder =
                cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
            // Don't use "haswell" as the default, as it implies `has_lzcnt`.
            // macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`.
            builder.enable("nehalem").unwrap();
            builder
        }
    };

    isa_builder.finish(flags)
}

/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(CraneliftCodegenBackend { config: None })
}
<commit_msg>Provide a default provide* implementation for CodegenBackend<commit_after>#![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts)]
#![warn(rust_2018_idioms)]
#![warn(unused_lifetimes)]
#![warn(unreachable_pub)]

extern crate snap;
#[macro_use]
extern crate rustc_middle;
extern crate rustc_ast;
extern crate rustc_codegen_ssa;
extern crate rustc_data_structures;
extern crate rustc_errors;
extern crate rustc_fs_util;
extern crate rustc_hir;
extern crate rustc_incremental;
extern crate rustc_index;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;

// This prevents duplicating functions and statics that are already part of the host rustc process.
#[allow(unused_extern_crates)]
extern crate rustc_driver;

use std::any::Any;

use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::CodegenResults;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
use rustc_session::config::OutputFilenames;
use rustc_session::Session;

use cranelift_codegen::isa::TargetIsa;
use cranelift_codegen::settings::{self, Configurable};

pub use crate::config::*;
use crate::prelude::*;

mod abi;
mod allocator;
mod analyze;
mod archive;
mod backend;
mod base;
mod cast;
mod codegen_i128;
mod common;
mod compiler_builtins;
mod config;
mod constant;
mod debuginfo;
mod discriminant;
mod driver;
mod inline_asm;
mod intrinsics;
mod linkage;
mod main_shim;
mod metadata;
mod num;
mod optimize;
mod pointer;
mod pretty_clif;
mod toolchain;
mod trap;
mod unsize;
mod value_and_place;
mod vtable;

mod prelude {
    pub(crate) use std::convert::{TryFrom, TryInto};

    pub(crate) use rustc_span::Span;

    pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
    pub(crate) use rustc_middle::bug;
    pub(crate) use rustc_middle::mir::{self, *};
    pub(crate) use rustc_middle::ty::layout::{self, TyAndLayout};
    pub(crate) use rustc_middle::ty::{
        self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut,
        TypeFoldable, UintTy,
    };
    pub(crate) use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx};

    pub(crate) use rustc_data_structures::fx::FxHashMap;

    pub(crate) use rustc_index::vec::Idx;

    pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
    pub(crate) use cranelift_codegen::ir::function::Function;
    pub(crate) use cranelift_codegen::ir::types;
    pub(crate) use cranelift_codegen::ir::{
        AbiParam, Block, ExternalName, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc,
        StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value,
    };
    pub(crate) use cranelift_codegen::isa::{self, CallConv};
    pub(crate) use cranelift_codegen::Context;
    pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
    pub(crate) use cranelift_module::{self, DataContext, DataId, FuncId, Linkage, Module};

    pub(crate) use crate::abi::*;
    pub(crate) use crate::base::{codegen_operand, codegen_place};
    pub(crate) use crate::cast::*;
    pub(crate) use crate::common::*;
    pub(crate) use crate::debuginfo::{DebugContext, UnwindContext};
    pub(crate) use crate::pointer::Pointer;
    pub(crate) use crate::trap::*;
    pub(crate) use crate::value_and_place::{CPlace, CPlaceInner, CValue};
}

struct PrintOnPanic<F: Fn() -> String>(F);
impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
    fn drop(&mut self) {
        if ::std::thread::panicking() {
            println!("{}", (self.0)());
        }
    }
}

/// The codegen context holds any information shared between the codegen of individual functions
/// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module).
struct CodegenCx<'tcx> {
    tcx: TyCtxt<'tcx>,
    global_asm: String,
    cached_context: Context,
    debug_context: Option<DebugContext<'tcx>>,
    unwind_context: UnwindContext,
}

impl<'tcx> CodegenCx<'tcx> {
    fn new(
        tcx: TyCtxt<'tcx>,
        backend_config: BackendConfig,
        isa: &dyn TargetIsa,
        debug_info: bool,
    ) -> Self {
        assert_eq!(pointer_ty(tcx), isa.pointer_type());

        let unwind_context =
            UnwindContext::new(tcx, isa, matches!(backend_config.codegen_mode, CodegenMode::Aot));
        let debug_context = if debug_info { Some(DebugContext::new(tcx, isa)) } else { None };
        CodegenCx {
            tcx,
            global_asm: String::new(),
            cached_context: Context::new(),
            debug_context,
            unwind_context,
        }
    }
}

pub struct CraneliftCodegenBackend {
    pub config: Option<BackendConfig>,
}

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, sess: &Session) {
        use rustc_session::config::Lto;
        match sess.lto() {
            Lto::No | Lto::ThinLocal => {}
            Lto::Thin | Lto::Fat => sess.warn("LTO is not supported. You may get a linker error."),
        }
    }

    fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
        Box::new(rustc_codegen_ssa::back::metadata::DefaultMetadataLoader)
    }

    fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> {
        vec![]
    }

    fn codegen_crate(
        &self,
        tcx: TyCtxt<'_>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
    ) -> Box<dyn Any> {
        tcx.sess.abort_if_errors();
        let config = if let Some(config) = self.config.clone() {
            config
        } else {
            BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
                .unwrap_or_else(|err| tcx.sess.fatal(&err))
        };
        match config.codegen_mode {
            CodegenMode::Aot => driver::aot::run_aot(tcx, config, metadata, need_metadata_module),
            CodegenMode::Jit | CodegenMode::JitLazy => {
                #[cfg(feature = "jit")]
                let _: ! = driver::jit::run_jit(tcx, config);

                #[cfg(not(feature = "jit"))]
                tcx.sess.fatal("jit support was disabled when compiling rustc_codegen_cranelift");
            }
        }
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        _sess: &Session,
    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
        Ok(*ongoing_codegen
            .downcast::<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)>()
            .unwrap())
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: CodegenResults,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_codegen_ssa::back::link::link_binary;

        link_binary::<crate::archive::ArArchiveBuilder<'_>>(
            sess,
            &codegen_results,
            outputs,
            &codegen_results.crate_name.as_str(),
        );

        Ok(())
    }
}

fn target_triple(sess: &Session) -> target_lexicon::Triple {
    sess.target.llvm_target.parse().unwrap()
}

fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::TargetIsa + 'static> {
    use target_lexicon::BinaryFormat;

    let target_triple = crate::target_triple(sess);

    let mut flags_builder = settings::builder();
    flags_builder.enable("is_pic").unwrap();
    flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
    let enable_verifier = if backend_config.enable_verifier { "true" } else { "false" };
    flags_builder.set("enable_verifier", enable_verifier).unwrap();

    let tls_model = match target_triple.binary_format {
        BinaryFormat::Elf => "elf_gd",
        BinaryFormat::Macho => "macho",
        BinaryFormat::Coff => "coff",
        _ => "none",
    };
    flags_builder.set("tls_model", tls_model).unwrap();

    flags_builder.set("enable_simd", "true").unwrap();

    flags_builder.set("enable_llvm_abi_extensions", "true").unwrap();

    flags_builder.set("regalloc", &backend_config.regalloc).unwrap();

    use rustc_session::config::OptLevel;
    match sess.opts.optimize {
        OptLevel::No => {
            flags_builder.set("opt_level", "none").unwrap();
        }
        OptLevel::Less | OptLevel::Default => {}
        OptLevel::Size | OptLevel::SizeMin | OptLevel::Aggressive => {
            flags_builder.set("opt_level", "speed_and_size").unwrap();
        }
    }

    let flags = settings::Flags::new(flags_builder);

    let variant = cranelift_codegen::isa::BackendVariant::MachInst;

    let isa_builder = match sess.opts.cg.target_cpu.as_deref() {
        Some("native") => {
            let builder = cranelift_native::builder_with_options(variant, true).unwrap();
            builder
        }
        Some(value) => {
            let mut builder =
                cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
            if let Err(_) = builder.enable(value) {
                sess.fatal("The specified target cpu isn't currently supported by Cranelift.");
            }
            builder
        }
        None => {
            let mut builder =
                cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
            // Don't use "haswell" as the default, as it implies `has_lzcnt`.
            // macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`.
            builder.enable("nehalem").unwrap();
            builder
        }
    };

    isa_builder.finish(flags)
}

/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(CraneliftCodegenBackend { config: None })
}
<|endoftext|>