<commit_before>//! Crate for accessing MS Windows registry
#![cfg_attr(test, feature(collections))]
extern crate winapi;
extern crate kernel32;
extern crate advapi32;
use std::ptr;
use std::fmt;
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use types::{FromReg, ToReg};

pub mod types;

pub struct RegError {
    err: winapi::DWORD,
}

impl fmt::Debug for RegError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "RegError {{ err: {:?}, message: {:?} }}",
                   self.err, error_string(self.err))
    }
}

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

#[derive(Debug)]
pub struct RegKey {
    hkey: winapi::HKEY,
}

impl RegKey {
    pub fn predef(hkey: winapi::HKEY) -> RegKey {
        RegKey{ hkey: hkey }
    }

    pub fn open_subkey<P: AsRef<OsStr>>(&self, path: P, perms: winapi::REGSAM) -> RegResult<RegKey> {
        let c_path = to_utf16(path);
        let mut new_hkey: winapi::HKEY = ptr::null_mut();
        match unsafe {
            advapi32::RegOpenKeyExW(
                self.hkey,
                c_path.as_ptr(),
                0,
                perms,
                &mut new_hkey,
            ) as winapi::DWORD
        } {
            0 => Ok(RegKey{ hkey: new_hkey }),
            err => Err(RegError{ err: err })
        }
    }

    /// Will also create all missing parent keys. Will open key if it already exists.
    pub fn create_subkey<P: AsRef<OsStr>>(&self, path: P, perms: winapi::REGSAM) -> RegResult<RegKey> {
        let c_path = to_utf16(path);
        let mut new_hkey: winapi::HKEY = ptr::null_mut();
        let mut disp: winapi::DWORD = 0;
        match unsafe {
            advapi32::RegCreateKeyExW(
                self.hkey,
                c_path.as_ptr(),
                0,
                ptr::null(),
                winapi::REG_OPTION_NON_VOLATILE,
                perms,
                ptr::null_mut(),
                &mut new_hkey,
                &mut disp // TODO: return this somehow
            ) as winapi::DWORD
        } {
            0 => Ok(RegKey{ hkey: new_hkey }),
            err => Err(RegError{ err: err })
        }
    }

    pub fn delete_subkey<P: AsRef<OsStr>>(&self, path: P) -> RegResult<()> {
        let c_path = to_utf16(path);
        match unsafe {
            advapi32::RegDeleteKeyW(
                self.hkey,
                c_path.as_ptr(),
            ) as winapi::DWORD
        } {
            0 => Ok(()),
            err => Err(RegError{ err: err })
        }
    }

    pub fn delete_subkey_all<P: AsRef<OsStr>>(&self, path: P) -> RegResult<()> {
        let c_path = to_utf16(path);
        match unsafe{
            advapi32::RegDeleteTreeW(
                self.hkey,
                c_path.as_ptr(),
            ) as winapi::DWORD
        } {
            0 => Ok(()),
            err => Err(RegError{ err: err })
        }
    }

    /// Gets the `Default` value if `name` is an empty string
    pub fn get_value<T: FromReg, P: AsRef<OsStr>>(&self, name: P) -> RegResult<T> {
        let c_name = to_utf16(name);
        let mut buf_len: winapi::DWORD = winapi::MAX_PATH as winapi::DWORD;
        let mut buf_type: winapi::DWORD = 0;
        let mut buf: Vec<u16> = Vec::with_capacity(buf_len as usize);
        match unsafe {
            advapi32::RegQueryValueExW(
                self.hkey,
                c_name.as_ptr() as *const u16,
                ptr::null_mut(),
                &mut buf_type,
                buf.as_mut_ptr() as winapi::LPBYTE,
                &mut buf_len
            ) as winapi::DWORD
        } {
            0 => {
                // set length to wchars count - 1 (trailing \0)
                unsafe{ buf.set_len(((buf_len >> 1) - 1) as usize); }
                FromReg::convert_from_bytes(buf, buf_type)
            },
            err => Err(RegError{ err: err })
        }
    }

    /// Sets the `Default` value if `name` is an empty string
    pub fn set_value<T: ToReg, P: AsRef<OsStr>>(&self, name: P, value: &T) -> RegResult<()> {
        let c_name = to_utf16(name);
        let c_value = value.convert_to_bytes();
        let v_type = value.get_val_type();
        match unsafe{
            advapi32::RegSetValueExW(
                self.hkey,
                c_name.as_ptr(),
                0,
                v_type,
                c_value.as_ptr() as *const winapi::BYTE,
                (c_value.len()*2) as u32
            ) as winapi::DWORD
        } {
            0 => Ok(()),
            err => Err(RegError{ err: err })
        }
    }

    /// Deletes the `Default` value if `name` is an empty string
    pub fn delete_value<P: AsRef<OsStr>>(&self, name: P) -> RegResult<()> {
        let c_name = to_utf16(name);
        match unsafe {
            advapi32::RegDeleteValueW(
                self.hkey,
                c_name.as_ptr(),
            ) as winapi::DWORD
        } {
            0 => Ok(()),
            err => Err(RegError{ err: err })
        }
    }

    fn close_(&mut self) -> RegResult<()> {
        match unsafe {
            advapi32::RegCloseKey(self.hkey) as winapi::DWORD
        } {
            0 => Ok(()),
            err => Err(RegError{ err: err })
        }
    }
}

impl Drop for RegKey {
    fn drop(&mut self) {
        self.close_().unwrap();
    }
}

fn to_utf16<P: AsRef<OsStr>>(s: P) -> Vec<u16> {
    s.as_ref().encode_wide().chain(Some(0).into_iter()).collect()
}

// copycat of rust/src/libstd/sys/windows/os.rs::error_string
// `use std::sys::os::error_string` leads to
// error: function `error_string` is private.
// Get a detailed string description for the given error number
fn error_string(errnum: winapi::DWORD) -> String {
    let mut buf = [0 as winapi::WCHAR; 2048];
    unsafe {
        let res = kernel32::FormatMessageW(winapi::FORMAT_MESSAGE_FROM_SYSTEM |
                                 winapi::FORMAT_MESSAGE_IGNORE_INSERTS,
                                 ptr::null_mut(),
                                 errnum as winapi::DWORD,
                                 0,
                                 buf.as_mut_ptr(),
                                 buf.len() as winapi::DWORD,
                                 ptr::null_mut());
        if res == 0 {
            // Sometimes FormatMessageW can fail e.g. system doesn't like langId,
            // let fm_err = errno();
            return format!("OS Error {} (FormatMessageW() returned error)",
                           errnum);
        }

        let b = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
        let msg = String::from_utf16(&buf[..b]);
        match msg {
            Ok(msg) => msg,
            Err(..) => format!("OS Error {} (FormatMessageW() returned \
                                invalid UTF-16)", errnum),
        }
    }
}

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

    #[test]
    fn test_open_subkey() {
        let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
        let win = hklm.open_subkey("Software\\Microsoft\\Windows", KEY_READ);
        assert!(win.is_ok());
        assert!(win.unwrap().open_subkey("CurrentVersion\\", KEY_READ).is_ok());
        assert!(hklm.open_subkey("i\\just\\hope\\nobody\\created\\that\\key", KEY_READ).is_err());
    }

    const KEY_PATH: &'static str = "Software\\WinregRsTestKey";

    fn create_test_key() -> RegKey {
        RegKey::predef(HKEY_CURRENT_USER)
        .create_subkey(KEY_PATH, KEY_ALL_ACCESS).unwrap()
    }

    fn delete_test_key() {
        RegKey::predef(HKEY_CURRENT_USER)
        .delete_subkey(KEY_PATH).unwrap();
    }

    #[test]
    fn test_create_delete_subkey() {
        create_test_key();
        delete_test_key();
    }

    #[test]
    fn test_delete_subkey_all() {
        let key = create_test_key();
        key.create_subkey("with\\sub\\keys", KEY_READ).unwrap();
        assert!(RegKey::predef(HKEY_CURRENT_USER).delete_subkey_all(KEY_PATH).is_ok());
    }

    #[test]
    fn test_string_value() {
        let key = create_test_key();
        let name = "WinregRsTestVal";
        let val1 = String::from_str("Test123 \n$%^&|+-*/\\()");

        assert!(key.set_value(name, &val1).is_ok());
        let val2: String = key.get_value(name).unwrap();
        assert_eq!(val1, val2);
        delete_test_key();
    }

    #[test]
    fn test_delete_value() {
        let key = create_test_key();
        let name = "WinregRsTestVal";
        key.set_value(name, &"Qwerty123").unwrap();
        assert!(key.delete_value(name).is_ok());
        delete_test_key();
    }
}
<commit_msg>Don't close predefined keys, fix tests<commit_after>//! Crate for accessing MS Windows registry
extern crate winapi;
extern crate kernel32;
extern crate advapi32;
use std::ptr;
use std::fmt;
use std::ffi::OsStr;
use std::os::windows::ffi::OsStrExt;
use types::{FromReg, ToReg};

pub mod types;

pub struct RegError {
    err: winapi::DWORD,
}

impl fmt::Debug for RegError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "RegError {{ err: {:?}, message: {:?} }}",
                   self.err, error_string(self.err))
    }
}

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

#[derive(Debug)]
pub struct RegKey {
    hkey: winapi::HKEY,
}

impl RegKey {
    pub fn predef(hkey: winapi::HKEY) -> RegKey {
        RegKey{ hkey: hkey }
    }

    pub fn open_subkey<P: AsRef<OsStr>>(&self, path: P, perms: winapi::REGSAM) -> RegResult<RegKey> {
        let c_path = to_utf16(path);
        let mut new_hkey: winapi::HKEY = ptr::null_mut();
        match unsafe {
            advapi32::RegOpenKeyExW(
                self.hkey,
                c_path.as_ptr(),
                0,
                perms,
                &mut new_hkey,
            ) as winapi::DWORD
        } {
            0 => Ok(RegKey{ hkey: new_hkey }),
            err => Err(RegError{ err: err })
        }
    }

    /// Will also create all missing parent keys. Will open key if it already exists.
    pub fn create_subkey<P: AsRef<OsStr>>(&self, path: P, perms: winapi::REGSAM) -> RegResult<RegKey> {
        let c_path = to_utf16(path);
        let mut new_hkey: winapi::HKEY = ptr::null_mut();
        let mut disp: winapi::DWORD = 0;
        match unsafe {
            advapi32::RegCreateKeyExW(
                self.hkey,
                c_path.as_ptr(),
                0,
                ptr::null(),
                winapi::REG_OPTION_NON_VOLATILE,
                perms,
                ptr::null_mut(),
                &mut new_hkey,
                &mut disp // TODO: return this somehow
            ) as winapi::DWORD
        } {
            0 => Ok(RegKey{ hkey: new_hkey }),
            err => Err(RegError{ err: err })
        }
    }

    pub fn delete_subkey<P: AsRef<OsStr>>(&self, path: P) -> RegResult<()> {
        let c_path = to_utf16(path);
        match unsafe {
            advapi32::RegDeleteKeyW(
                self.hkey,
                c_path.as_ptr(),
            ) as winapi::DWORD
        } {
            0 => Ok(()),
            err => Err(RegError{ err: err })
        }
    }

    pub fn delete_subkey_all<P: AsRef<OsStr>>(&self, path: P) -> RegResult<()> {
        let c_path = to_utf16(path);
        match unsafe{
            advapi32::RegDeleteTreeW(
                self.hkey,
                c_path.as_ptr(),
            ) as winapi::DWORD
        } {
            0 => Ok(()),
            err => Err(RegError{ err: err })
        }
    }

    /// Gets the `Default` value if `name` is an empty string
    pub fn get_value<T: FromReg, P: AsRef<OsStr>>(&self, name: P) -> RegResult<T> {
        let c_name = to_utf16(name);
        let mut buf_len: winapi::DWORD = winapi::MAX_PATH as winapi::DWORD;
        let mut buf_type: winapi::DWORD = 0;
        let mut buf: Vec<u16> = Vec::with_capacity(buf_len as usize);
        match unsafe {
            advapi32::RegQueryValueExW(
                self.hkey,
                c_name.as_ptr() as *const u16,
                ptr::null_mut(),
                &mut buf_type,
                buf.as_mut_ptr() as winapi::LPBYTE,
                &mut buf_len
            ) as winapi::DWORD
        } {
            0 => {
                // set length to wchars count - 1 (trailing \0)
                unsafe{ buf.set_len(((buf_len >> 1) - 1) as usize); }
                FromReg::convert_from_bytes(buf, buf_type)
            },
            err => Err(RegError{ err: err })
        }
    }

    /// Sets the `Default` value if `name` is an empty string
    pub fn set_value<T: ToReg, P: AsRef<OsStr>>(&self, name: P, value: &T) -> RegResult<()> {
        let c_name = to_utf16(name);
        let c_value = value.convert_to_bytes();
        let v_type = value.get_val_type();
        match unsafe{
            advapi32::RegSetValueExW(
                self.hkey,
                c_name.as_ptr(),
                0,
                v_type,
                c_value.as_ptr() as *const winapi::BYTE,
                (c_value.len()*2) as u32
            ) as winapi::DWORD
        } {
            0 => Ok(()),
            err => Err(RegError{ err: err })
        }
    }

    /// Deletes the `Default` value if `name` is an empty string
    pub fn delete_value<P: AsRef<OsStr>>(&self, name: P) -> RegResult<()> {
        let c_name = to_utf16(name);
        match unsafe {
            advapi32::RegDeleteValueW(
                self.hkey,
                c_name.as_ptr(),
            ) as winapi::DWORD
        } {
            0 => Ok(()),
            err => Err(RegError{ err: err })
        }
    }

    fn close_(&mut self) -> RegResult<()> {
        // don't try to close predefined keys
        if self.hkey >= winapi::HKEY_CLASSES_ROOT { return Ok(()) };
        match unsafe {
            advapi32::RegCloseKey(self.hkey) as winapi::DWORD
        } {
            0 => Ok(()),
            err => Err(RegError{ err: err })
        }
    }
}

impl Drop for RegKey {
    fn drop(&mut self) {
        self.close_().unwrap();
    }
}

fn to_utf16<P: AsRef<OsStr>>(s: P) -> Vec<u16> {
    s.as_ref().encode_wide().chain(Some(0).into_iter()).collect()
}

// copycat of rust/src/libstd/sys/windows/os.rs::error_string
// `use std::sys::os::error_string` leads to
// error: function `error_string` is private.
// Get a detailed string description for the given error number
fn error_string(errnum: winapi::DWORD) -> String {
    let mut buf = [0 as winapi::WCHAR; 2048];
    unsafe {
        let res = kernel32::FormatMessageW(winapi::FORMAT_MESSAGE_FROM_SYSTEM |
                                 winapi::FORMAT_MESSAGE_IGNORE_INSERTS,
                                 ptr::null_mut(),
                                 errnum as winapi::DWORD,
                                 0,
                                 buf.as_mut_ptr(),
                                 buf.len() as winapi::DWORD,
                                 ptr::null_mut());
        if res == 0 {
            // Sometimes FormatMessageW can fail e.g. system doesn't like langId,
            // let fm_err = errno();
            return format!("OS Error {} (FormatMessageW() returned error)",
                           errnum);
        }

        let b = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
        let msg = String::from_utf16(&buf[..b]);
        match msg {
            Ok(msg) => msg,
            Err(..) => format!("OS Error {} (FormatMessageW() returned \
                                invalid UTF-16)", errnum),
        }
    }
}

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

    #[test]
    fn test_open_subkey() {
        let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
        let win = hklm.open_subkey("Software\\Microsoft\\Windows", KEY_READ);
        assert!(win.is_ok());
        assert!(win.unwrap().open_subkey("CurrentVersion\\", KEY_READ).is_ok());
        assert!(hklm.open_subkey("i\\just\\hope\\nobody\\created\\that\\key", KEY_READ).is_err());
    }

    fn create_test_key(path: &str) -> RegKey {
        let mut full_path = "Software\\WinRegRsTest".to_string();
        full_path.push_str(path);
        RegKey::predef(HKEY_CURRENT_USER)
        .create_subkey(full_path, KEY_ALL_ACCESS).unwrap()
    }

    fn delete_test_key(path: &str) {
        let mut full_path = "Software\\WinRegRsTest".to_string();
        full_path.push_str(path);
        RegKey::predef(HKEY_CURRENT_USER)
        .delete_subkey(full_path).unwrap();
    }

    #[test]
    fn test_create_delete_subkey() {
        let path = "CreateDeleteSubkey";
        create_test_key(path);
        delete_test_key(path);
    }

    #[test]
    fn test_delete_subkey_all() {
        let path = "DeleteSubkeyAll";
        let key = create_test_key(path);
        key.create_subkey("with\\sub\\keys", KEY_READ).unwrap();
        assert!(RegKey::predef(HKEY_CURRENT_USER)
            .delete_subkey_all("Software\\WinRegRsTestDeleteSubkeyAll").is_ok());
    }

    #[test]
    fn test_string_value() {
        let path = "StringValue";
        let key = create_test_key(path);
        let name = "RustStringVal";
        let val1 = "Test123 \n$%^&|+-*/\\()".to_string();

        key.set_value(name, &val1).unwrap();
        let val2: String = key.get_value(name).unwrap();
        assert_eq!(val1, val2);
        delete_test_key(path);
    }

    #[test]
    fn test_delete_value() {
        let path = "StringValue";
        let key = create_test_key(path);
        let name = "WinregRsTestVal";
        key.set_value(name, &"Qwerty123").unwrap();
        assert!(key.delete_value(name).is_ok());
        delete_test_key(path);
    }
}
<|endoftext|>


<commit_before>#![crate_name = "firebase"]
#![crate_type = "rlib"]

extern crate curl;
extern crate "rustc-serialize" as rustc_serialize;

use std::str;
use curl::http;

pub struct Firebase<'a> {
    base_uri: &'a str
}

impl <'a> Firebase<'a> {
    pub fn new(base_uri: &str) -> Firebase {
        Firebase { base_uri: base_uri }
    }

    pub fn push(self, path: &str, data: &str) -> Response {
        let mut url = self.base_uri.to_string();
        url.push_str(path);

        let res = http::handle()
            .post(url, data)
            .exec().unwrap();

        let body = match str::from_utf8(res.get_body()) {
            Ok(b) => b,
            Err(..) => "Unable to parse"
        };

        return Response { body: body.to_string() };
    }
}

pub struct Response {
    pub body: String
}
<commit_msg>Refactored lifetime specifier within Firebase#base_uri<commit_after>#![crate_name = "firebase"]
#![crate_type = "rlib"]

extern crate curl;
extern crate "rustc-serialize" as rustc_serialize;

use std::str;
use curl::http;

pub struct Firebase {
    base_uri: String
}

impl Firebase {
    pub fn new(base_uri: &str) -> Firebase {
        Firebase { base_uri: base_uri.to_string() }
    }

    pub fn push(self, path: &str, data: &str) -> Response {
        let mut url = self.base_uri;
        url.push_str(path);

        let res = http::handle()
            .post(url, data)
            .exec().unwrap();

        let body = match str::from_utf8(res.get_body()) {
            Ok(b) => b,
            Err(..) => "Unable to parse"
        };

        return Response { body: body.to_string() };
    }
}

pub struct Response {
    pub body: String
}
<|endoftext|>


<commit_before>mod token;

pub fn compile(sass: String, style: &str) -> String {
    let mut sp = SassParser::new(sass); // SassTokenizer::new(sass);
    let parsed = sp.parse();
    match style {
        "nested"     => nested(parsed),
        "compressed" => compressed(parsed),
        "expanded"   => expanded(parsed),
        "compact"    => compact(parsed),
        _            => panic!("Unknown style: {}. Please specify one of nested, compressed, expanded, or compact.", style),
    }
}

fn nested(sass: String) -> String {
    sass
}

fn compressed(sass: String) -> String {
    sass.replace(" ", "").replace("\n", "")
}

fn expanded(sass: String) -> String {
    sass
}

fn compact(sass: String) -> String {
    sass
}

#[derive(Debug)]
struct SassRuleSet {
    pub rules: Vec<SassRule>,
}

#[derive(Debug)]
struct SassRule {
    pub selectors: Vec<token::Range>,
    pub props_and_values: Vec<PropertyValueSet>,
}

#[derive(Debug)]
struct PropertyValueSet {
    pub property: token::Range,
    pub value: token::Range,
}

#[derive(Debug)]
struct SassParser {
    pub curr: Option<token::Range>,
    pub peek_range: token::Range,
    pub tok: SassTokenizer,
}

impl SassParser {
    pub fn new(str: String) -> SassParser {
        let mut sp = SassParser {
            tok: SassTokenizer::new(str),
            curr: None,
            peek_range: token::Range { start_pos: 0, end_pos: 0, token: token::Eof },
        };
        sp.advance_token();
        sp.bump();
        sp
    }

    pub fn bump(&mut self) {
        if self.peek_range.token == token::Eof {
            self.curr = None;
        } else {
            self.curr = Some(self.peek_range.clone());
            self.advance_token();
        }
    }

    pub fn advance_token(&mut self) {
        match self.tok.scan_whitespace() {
            Some(whitespace) => {
                self.peek_range = whitespace;
            },
            None => {
                if self.tok.is_eof() {
                    self.peek_range = token::Range { start_pos: self.tok.pos + 1, end_pos: self.tok.pos + 1, token: token::Eof };
                } else {
                    self.peek_range = self.tok.next_token_inner();
                }
            },
        }
    }

    pub fn parse(&mut self) -> String {
        println!("{:?}", self.parse_rules());
        self.tok.sass.clone()
    }

    fn parse_rules(&mut self) -> Result<SassRuleSet, &'static str> {
        let mut rules = vec![];
        while let Some(rule) = try!(self.parse_rule()) {
            rules.push(rule);
        }
        Ok(SassRuleSet { rules: rules })
    }

    fn parse_rule(&mut self) -> Result<Option<SassRule>, &'static str> {
        let c = match self.curr.clone() {
            Some(c) => c,
            None => return Ok(None),
        };

        let mut selectors = vec![];
        while let Some(selector) = try!(self.parse_selector()) {
            selectors.push(selector);
        }
        if selectors.len() == 0 {
            panic!("Empty selector!")
        }

        let mut props_and_values = vec![];
        while let Some(property_value_set) = try!(self.parse_property_value_set()) {
            props_and_values.push(property_value_set);
        }

        // A rule without properties and values isn't *wrong*, per se...
        Ok(Some(SassRule { selectors: selectors, props_and_values: props_and_values }))
    }

    fn parse_selector(&mut self) -> Result<Option<token::Range>, &'static str> {
        let c = match self.curr.clone() {
            Some(c) => c,
            None => return Ok(None),
        };

        if c.token == token::Text {
            self.bump();
            return Ok(Some(c))
        }

        match &c.token {
            &token::Eof => Ok(None),
            &token::OpenDelim(token::Brace) => {
                self.bump(); // for the delim
                self.bump(); // whitespace
                Ok(None)
            },
            &token::Comma => {
                self.bump();
                self.parse_selector()
            },
            &token::Whitespace => { // wrong but temporarily so
                self.bump();
                self.parse_selector()
            },
            _ => Err("Unexpected token where we expected selectors"),
        }
    }

    fn parse_property_value_set(&mut self) -> Result<Option<PropertyValueSet>, &'static str> {
        let p = match self.curr.clone() {
            Some(p) => p,
            None => return Ok(None),
        };

        match p.token {
            token::Text => {
                self.bump(); // should be colon
                self.bump(); // optional whitespace required for now
                self.bump(); // now val

                let v = match self.curr.clone() {
                    Some(v) => v,
                    None => panic!("Expected a value here, instead got EOF!"),
                };

                if v.token == token::Text {
                    self.bump(); // semicolon
                    self.bump(); // whitespace
                    return Ok(Some(PropertyValueSet { property: p, value: v }))
                } else {
                    panic!("Expected a value here, instead got who knows what!");
                }
            },
            token::CloseDelim(token::Brace) => {
                self.bump();
                Ok(None)
            },
            token::Whitespace => {
                self.bump();
                self.parse_property_value_set()
            },
            _ => Err("Unexpected token where we expected properties and values"),
        }
    }
}

#[derive(Debug)]
struct SassTokenizer {
    pub pos: u32,
    pub last_pos: u32,
    pub curr: Option<char>,
    sass: String,
}

impl SassTokenizer {
    pub fn new(str: String) -> SassTokenizer {
        let mut sr = SassTokenizer {
            pos: 0,
            last_pos: 0,
            curr: Some('\n'),
            sass: str,
        };
        sr.bump();
        sr
    }

    pub fn bump(&mut self) {
        self.last_pos = self.pos;
        let current_pos = self.pos as usize;
        if current_pos < self.sass.len() {
            let ch = char_at(&self.sass, current_pos);

            self.pos = self.pos + (ch.len_utf8() as u32);
            self.curr = Some(ch);
        } else {
            self.curr = None;
        }
    }

    fn next_token_inner(&mut self) -> token::Range {
        let c = match self.curr {
            Some(c) => c,
            None => return token::Range { start_pos: self.pos + 1, end_pos: self.pos + 1, token: token::Eof },
        };

        if c >= 'a' && c <= 'z' {
            let start = self.last_pos;
            while !self.curr.is_none() && self.curr.unwrap() >= 'a' && self.curr.unwrap() <= 'z' {
                self.bump();
            }
            return token::Range { start_pos: start, end_pos: self.last_pos, token: token::Text }
        }

        match c {
            ';' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Semi }; },
            ':' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Colon }; },
            ',' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Comma }; },
            '{' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::OpenDelim(token::Brace) }; },
            '}' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::CloseDelim(token::Brace) }; },
            _   => { return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Unknown} },
        }
    }

    fn scan_whitespace(&mut self) -> Option<token::Range> {
        match self.curr.unwrap_or('\0') {
            c if is_whitespace(Some(c)) => {
                let start = self.last_pos;
                while is_whitespace(self.curr) { self.bump(); }
                Some(token::Range { start_pos: start, end_pos: self.last_pos, token: token::Whitespace })
            },
            _ => None
        }
    }

    fn is_eof(&self) -> bool {
        self.curr.is_none()
    }
}

pub fn char_at(s: &str, byte: usize) -> char {
    s[byte..].chars().next().unwrap()
}

pub fn is_whitespace(c: Option<char>) -> bool {
    match c.unwrap_or('\x00') { // None can be null for now... it's not whitespace
        ' ' | '\n' | '\t' | '\r' => true,
        _ => false
    }
}
<commit_msg>Try to be more like libsyntax<commit_after>mod token;

pub fn compile(sass: String, style: &str) -> String {
    let mut sp = SassParser::new(sass); // SassTokenizer::new(sass);
    let parsed = sp.parse();
    match style {
        "nested"     => nested(parsed),
        "compressed" => compressed(parsed),
        "expanded"   => expanded(parsed),
        "compact"    => compact(parsed),
        _            => panic!("Unknown style: {}. Please specify one of nested, compressed, expanded, or compact.", style),
    }
}

fn nested(sass: String) -> String {
    sass
}

fn compressed(sass: String) -> String {
    sass.replace(" ", "").replace("\n", "")
}

fn expanded(sass: String) -> String {
    sass
}

fn compact(sass: String) -> String {
    sass
}

#[derive(Debug)]
struct SassRuleSet {
    pub rules: Vec<SassRule>,
}

#[derive(Debug)]
struct SassRule {
    pub selectors: Vec<token::Range>,
    pub props_and_values: Vec<PropertyValueSet>,
}

#[derive(Debug)]
struct PropertyValueSet {
    pub property: token::Range,
    pub value: token::Range,
}

#[derive(Debug)]
struct SassParser {
    pub curr: Option<token::Range>,
    pub peek_range: token::Range,
    pub tok: SassTokenizer,
}

impl SassParser {
    pub fn new(str: String) -> SassParser {
        let mut sp = SassParser {
            tok: SassTokenizer::new(str),
            curr: None,
            peek_range: token::Range { start_pos: 0, end_pos: 0, token: token::Eof },
        };
        sp.advance_token();
        sp.bump();
        sp
    }

    pub fn bump(&mut self) {
        if self.peek_range.token == token::Eof {
            self.curr = None;
        } else {
            self.curr = Some(self.peek_range.clone());
            self.advance_token();
        }
    }

    pub fn advance_token(&mut self) {
        match self.tok.scan_whitespace() {
            Some(whitespace) => {
                self.peek_range = whitespace;
            },
            None => {
                if self.tok.is_eof() {
                    self.peek_range = token::Range { start_pos: self.tok.pos + 1, end_pos: self.tok.pos + 1, token: token::Eof };
                } else {
                    self.peek_range = self.tok.next_token_inner();
                }
            },
        }
    }

    pub fn parse(&mut self) -> String {
        println!("{:?}", self.parse_rules());
        self.tok.sass.clone()
    }

    fn parse_rules(&mut self) -> Result<SassRuleSet, &'static str> {
        let mut rules = vec![];
        while let Some(rule) = try!(self.parse_rule()) {
            rules.push(rule);
        }
        Ok(SassRuleSet { rules: rules })
    }

    fn parse_rule(&mut self) -> Result<Option<SassRule>, &'static str> {
        let c = match self.curr.clone() {
            Some(c) => c,
            None => return Ok(None),
        };

        let mut selectors = vec![];
        while let Some(selector) = try!(self.parse_selector()) {
            selectors.push(selector);
        }
        if selectors.len() == 0 {
            panic!("Empty selector!")
        }

        let mut props_and_values = vec![];
        while let Some(property_value_set) = try!(self.parse_property_value_set()) {
            props_and_values.push(property_value_set);
        }

        // A rule without properties and values isn't *wrong*, per se...
        Ok(Some(SassRule { selectors: selectors, props_and_values: props_and_values }))
    }

    fn parse_selector(&mut self) -> Result<Option<token::Range>, &'static str> {
        let c = match self.curr.clone() {
            Some(c) => c,
            None => return Ok(None),
        };

        if c.token == token::Text {
            self.bump();
            return Ok(Some(c))
        }

        match &c.token {
            &token::Eof => Ok(None),
            &token::OpenDelim(token::Brace) => {
                self.bump(); // for the delim
                self.bump(); // whitespace
                Ok(None)
            },
            &token::Comma => {
                self.bump();
                self.parse_selector()
            },
            &token::Whitespace => { // wrong but temporarily so
                self.bump();
                self.parse_selector()
            },
            _ => Err("Unexpected token where we expected selectors"),
        }
    }

    fn parse_property_value_set(&mut self) -> Result<Option<PropertyValueSet>, &'static str> {
        let p = match self.curr.clone() {
            Some(p) => p,
            None => return Ok(None),
        };

        match p.token {
            token::Text => {
                self.bump(); // should be colon
                self.bump(); // optional whitespace required for now
                self.bump(); // now val

                let v = match self.curr.clone() {
                    Some(v) => v,
                    None => panic!("Expected a value here, instead got EOF!"),
                };

                if v.token == token::Text {
                    self.bump(); // semicolon
                    self.bump(); // whitespace
                    return Ok(Some(PropertyValueSet { property: p, value: v }))
                } else {
                    panic!("Expected a value here, instead got who knows what!");
                }
            },
            token::CloseDelim(token::Brace) => {
                self.bump();
                Ok(None)
            },
            token::Whitespace => {
                self.bump();
                self.parse_property_value_set()
            },
            _ => Err("Unexpected token where we expected properties and values"),
        }
    }
}

#[derive(Debug)]
struct SassTokenizer {
    pub pos: u32,
    pub last_pos: u32,
    pub curr: Option<char>,
    sass: String,
}

impl SassTokenizer {
    pub fn new(str: String) -> SassTokenizer {
        let mut sr = SassTokenizer {
            pos: 0,
            last_pos: 0,
            curr: Some('\n'),
            sass: str,
        };
        sr.bump();
        sr
    }

    pub fn bump(&mut self) {
        self.last_pos = self.pos;
        let current_pos = self.pos as usize;
        if current_pos < self.sass.len() {
            let ch = char_at(&self.sass, current_pos);

            self.pos = self.pos + (ch.len_utf8() as u32);
            self.curr = Some(ch);
        } else {
            self.curr = None;
        }
    }

    fn next_token_inner(&mut self) -> token::Range {
        let c = match self.curr {
            Some(c) => c,
            None => return token::Range { start_pos: self.pos + 1, end_pos: self.pos + 1, token: token::Eof },
        };

        if c >= 'a' && c <= 'z' {
            let start = self.last_pos;
            while !self.curr.is_none() && self.curr.unwrap() >= 'a' && self.curr.unwrap() <= 'z' {
                self.bump();
            }
            return token::Range { start_pos: start, end_pos: self.last_pos, token: token::Text }
        }

        match c {
            ';' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Semi }; },
            ':' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Colon }; },
            ',' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Comma }; },
            '{' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::OpenDelim(token::Brace) }; },
            '}' => { self.bump(); return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::CloseDelim(token::Brace) }; },
            _   => { return token::Range { start_pos: self.last_pos, end_pos: self.last_pos, token: token::Unknown} },
        }
    }

    fn real_token(&mut self) -> token::Range {
        let mut t = self.next_token_inner();
        loop {
            match t.token {
                token::Whitespace => {
                    t = self.next_token_inner();
                },
                _ => break,
            }
        }
        t
    }

    fn scan_whitespace(&mut self) -> Option<token::Range> {
        match self.curr.unwrap_or('\0') {
            c if is_whitespace(Some(c)) => {
                let start = self.last_pos;
                while is_whitespace(self.curr) { self.bump(); }
                Some(token::Range { start_pos: start, end_pos: self.last_pos, token: token::Whitespace })
            },
            _ => None
        }
    }

    fn is_eof(&self) -> bool {
        self.curr.is_none()
    }
}

pub fn char_at(s: &str, byte: usize) -> char {
    s[byte..].chars().next().unwrap()
}

pub fn is_whitespace(c: Option<char>) -> bool {
    match c.unwrap_or('\x00') { // None can be null for now... it's not whitespace
        ' ' | '\n' | '\t' | '\r' => true,
        _ => false
    }
}
<|endoftext|>


<commit_before>use std::process::{Command, Stdio};
use std::collections::HashSet;

struct ProcessSets {
    prev_set: HashSet<u32>,
    curr_set: HashSet<u32>,
}

pub trait ProcessWatcherCallback {
    fn on_open(&self, pid: u32) -> ();
    fn on_close(&self, pid: u32) -> ();
}

fn get_processes(callback: &ProcessWatcherCallback) -> () {
    let mut sets = ProcessSets { prev_set: HashSet::new(), curr_set: HashSet::new() };

    let child = Command::new("/bin/ps").arg("-e")
        .stdout(Stdio::piped()).spawn().expect("process spawn failed");

    let output = child.wait_with_output().expect("failed to wait on process");
    let vector = output.stdout.as_slice();
    let newline : u8 = 10;
    let iter = vector.split(|num| num == &newline);

    for line in iter {
        let str_line = String::from_utf8_lossy(line);
        let mut fields = str_line.split_whitespace();

        let field = fields.next();
        if field.is_some() {
            let pid: u32 = match field.unwrap().trim().parse() {
                Ok(num) => num,
                Err(_) => continue,
            };

            sets.curr_set.insert(pid);
        }
    }

    //first run, the previous set will be empty
    if sets.prev_set.is_empty() {
        for x in sets.curr_set.iter() {
            callback.on_open(x.clone());
        }
    }
    else {
        let open_set: HashSet<u32> = sets.curr_set.difference(&sets.prev_set).cloned().collect();
        let closed_set: HashSet<u32> = sets.prev_set.difference(&sets.curr_set).cloned().collect();

        for opened in open_set.iter() {
            callback.on_open(opened.clone());
        }

        for closed in closed_set.iter() {
            callback.on_close(closed.clone());
        }
    }

    sets.prev_set = sets.curr_set.clone();
    sets.curr_set.clear();
}

pub fn watch(callback: &ProcessWatcherCallback) -> () {
	get_processes(callback);
}<commit_msg>Adding closure variant<commit_after>use std::process::{Command, Stdio};
use std::collections::HashSet;

struct ProcessSets {
    prev_set: HashSet<u32>,
    curr_set: HashSet<u32>,
}

pub trait ProcessWatcherCallback {
    fn on_open(&self, pid: u32) -> ();
    fn on_close(&self, pid: u32) -> ();
}

fn get_processes(callback: &ProcessWatcherCallback) -> () {
    let mut sets = ProcessSets { prev_set: HashSet::new(), curr_set: HashSet::new() };

    let child = Command::new("/bin/ps").arg("-e")
        .stdout(Stdio::piped()).spawn().expect("process spawn failed");

    let output = child.wait_with_output().expect("failed to wait on process");
    let vector = output.stdout.as_slice();
    let newline : u8 = 10;
    let iter = vector.split(|num| num == &newline);

    for line in iter {
        let str_line = String::from_utf8_lossy(line);
        let mut fields = str_line.split_whitespace();

        let field = fields.next();
        if field.is_some() {
            let pid: u32 = match field.unwrap().trim().parse() {
                Ok(num) => num,
                Err(_) => continue,
            };

            sets.curr_set.insert(pid);
        }
    }

    //first run, the previous set will be empty
    if sets.prev_set.is_empty() {
        for x in sets.curr_set.iter() {
            callback.on_open(x.clone());
        }
    }
    else {
        let open_set: HashSet<u32> = sets.curr_set.difference(&sets.prev_set).cloned().collect();
        let closed_set: HashSet<u32> = sets.prev_set.difference(&sets.curr_set).cloned().collect();

        for opened in open_set.iter() {
            callback.on_open(opened.clone());
        }

        for closed in closed_set.iter() {
            callback.on_close(closed.clone());
        }
    }

    sets.prev_set = sets.curr_set.clone();
    sets.curr_set.clear();
}

pub fn watch_with_callback(callback: &ProcessWatcherCallback) -> () {
	get_processes(callback);
}

pub fn watch_with_closure(on_open: &Fn(i32) -> (), on_close: &Fn(i32) -> ()) {
    //Implement me
}<|endoftext|>


<commit_before>#![feature(libc)]

#![allow(dead_code)]
#![allow(non_camel_case_types)]

extern crate libc;
use libc::{c_int, size_t, c_void};
use std::mem;

/**
 * Abstraction of libnl core functionality
 */
#[link(name="nl-3")]
extern "C" {
	// Exposed socket functions
	fn nl_socket_alloc() -> *const nl_sock;
	fn nl_socket_free(socket: *const nl_sock);
	fn nl_socket_get_fd(socket: *const nl_sock) -> i32;
	fn nl_socket_set_buffer_size(socket: *const nl_sock, rxbuf: c_int, txbuf: c_int) -> i32;

	fn nl_socket_set_local_port(socket: *const nl_sock, port: u32);
	fn nl_socket_get_local_port(socket: *const nl_sock) -> u32;

	fn nl_connect(socket: *const nl_sock, protocol: u32) -> i32;
	fn nl_close(socket: *const nl_sock);

	fn nl_socket_set_cb(socket: *const nl_sock, cb: *const nl_cb);
	fn nl_socket_get_cb(socket: *const nl_sock) -> nl_cb;

	// Exposed socket transceivers
	fn nl_send_simple(socket: *const nl_sock, msg_type: c_int, flags: c_int, buf: *const c_void, size: c_int) -> i32;

	// Exposed msg functions
	fn nlmsg_alloc() -> *const nl_msg;
	fn nlmsg_free(msg: *const nl_msg);
	fn nlmsg_append(msg: *const nl_msg, data: *const c_void, len: size_t, pad: c_int) -> i32;
    fn nlmsg_put(msg: *const nl_msg, pid: u32, seq: u32, mtype: c_int, payload: c_int, flags: c_int) -> *const nlmsghdr;
    fn nlmsg_datalen(nlh: *const nlmsghdr) -> i32;
    fn nlmsg_next(nlh: *const nlmsghdr, remaining: *const i32) -> *const nlmsghdr;

}

// exposed structures - these are wrapped
#[repr(C)]
struct nl_sock;
#[repr(C)]
struct nl_msg;
#[repr(C)]
struct nl_cb;
#[repr(C)]
struct nlmsghdr;

// RSNL datatypes wrapping the libnl data structures
pub enum NetlinkProtocol {
	route,
	unused,
	usersock,
	firewall,
	sock_diag,
	nflog,
	xfrm,
	selinux,
	iscsi,
	audit,
	fib_lookup,
	connector,
	netfilter,
	ip6_fw,
	dnrtmsg,
	kobject_uevent,
	DMEVENTS,
	scsitransport,
	ecryptfs,
	rdma,
	crypto,
}

pub struct NetlinkSocket {
    ptr: *const nl_sock,
}

pub struct NetlinkMessage {
	ptr: *const nl_msg,
    hdr: Option<*const nlmsghdr>,
}

pub fn sock_alloc() -> NetlinkSocket {
    NetlinkSocket {
        ptr: unsafe { nl_socket_alloc() },
    }
}

pub fn sock_free(sock: NetlinkSocket) {
    unsafe { nl_socket_free(sock.ptr); }
}

pub fn sock_set_buffer_size(sock: &mut NetlinkSocket, rxbuf: i32, txbuf: i32) -> i32 {
    unsafe { nl_socket_set_buffer_size(sock.ptr, rxbuf, txbuf) }
}

pub fn connect(sock: &mut NetlinkSocket, protocol: u32) -> i32 {
    unsafe { nl_connect(sock.ptr, protocol) }
}

pub fn close(sock: &mut NetlinkSocket) {
    unsafe{ nl_close(sock.ptr) }
}

pub fn sock_get_local_port(sock: &NetlinkSocket) -> u32 {
    unsafe { nl_socket_get_local_port(sock.ptr) }
}

pub fn sock_set_local_port(sock: &mut NetlinkSocket, port: u32) {
    unsafe { nl_socket_set_local_port(sock.ptr, port) }
}

pub fn sock_get_fd(sock: &NetlinkSocket) -> i32 {
    unsafe { nl_socket_get_fd(sock.ptr) }
}

pub fn send_simple<T>(sock: &NetlinkSocket, msg_type: i32, flags: i32, buf: &T, size: i32) -> i32 {
    unsafe {
        let vptr: *const c_void = mem::transmute(buf);
        nl_send_simple(sock.ptr, msg_type, flags, vptr, size) as i32
    }
}

pub fn msg_alloc() -> NetlinkMessage {
    NetlinkMessage {
        ptr: unsafe { nlmsg_alloc() },
        hdr: None
    }
}

pub fn msg_free(msg: NetlinkMessage) {
    unsafe { nlmsg_free(msg.ptr) }
}

pub fn msg_append<T>(msg: &mut NetlinkMessage, data: &T, len: u32, pad: i32) -> i32 {
    unsafe {
        let vptr: *const c_void = mem::transmute(data);
        nlmsg_append(msg.ptr, vptr, len as size_t, pad as c_int) as i32
    }
}

pub fn msg_put(msg: &mut NetlinkMessage, pid: u32, seq: u32, mtype: i32, payload: i32, flags: i32) -> bool {
    unsafe {
        let hdr = nlmsg_put(msg.ptr, pid, seq, mtype as c_int, payload as c_int, flags as c_int);

        match hdr as i32 {
            0x0 => false,
            _ => {
                msg.hdr = Some(hdr);
                true
            }
        }
    }
}

pub fn msg_data_len(msg: &NetlinkMessage) -> i32 {

    match msg.hdr {
        None => 0,
        Some(hdr) => {
            unsafe { nlmsg_datalen(hdr) }
        }
    }
}

<commit_msg>Implement extraction of nlmsghdr and msg inherit<commit_after>#![feature(libc)]

#![allow(dead_code)]
#![allow(non_camel_case_types)]

extern crate libc;
use libc::{c_int, size_t, c_void};
use std::mem;

/**
 * Abstraction of libnl core functionality
 */
#[link(name="nl-3")]
extern "C" {
	// Exposed socket functions
	fn nl_socket_alloc() -> *const nl_sock;
	fn nl_socket_free(socket: *const nl_sock);
	fn nl_socket_get_fd(socket: *const nl_sock) -> i32;
	fn nl_socket_set_buffer_size(socket: *const nl_sock, rxbuf: c_int, txbuf: c_int) -> i32;

	fn nl_socket_set_local_port(socket: *const nl_sock, port: u32);
	fn nl_socket_get_local_port(socket: *const nl_sock) -> u32;

	fn nl_connect(socket: *const nl_sock, protocol: u32) -> i32;
	fn nl_close(socket: *const nl_sock);

	fn nl_socket_set_cb(socket: *const nl_sock, cb: *const nl_cb);
	fn nl_socket_get_cb(socket: *const nl_sock) -> nl_cb;

	// Exposed socket transceivers
	fn nl_send_simple(socket: *const nl_sock, msg_type: c_int, flags: c_int, buf: *const c_void, size: c_int) -> i32;

	// Exposed msg functions
	fn nlmsg_alloc() -> *const nl_msg;
	fn nlmsg_free(msg: *const nl_msg);
	fn nlmsg_append(msg: *const nl_msg, data: *const c_void, len: size_t, pad: c_int) -> i32;
    fn nlmsg_put(msg: *const nl_msg, pid: u32, seq: u32, mtype: c_int, payload: c_int, flags: c_int) -> *const nlmsghdr;
    fn nlmsg_datalen(nlh: *const nlmsghdr) -> i32;
    fn nlmsg_next(nlh: *const nlmsghdr, remaining: *const i32) -> *const nlmsghdr;
    fn nlmsg_inherit(nlh: *const nlmsghdr) -> *const nl_msg;
    fn nlmsg_hdr(msg: *const nl_msg) -> *const nlmsghdr;

}

// exposed structures - these are wrapped
#[repr(C)]
struct nl_sock;
#[repr(C)]
struct nl_msg;
#[repr(C)]
struct nl_cb;
#[repr(C)]
struct nlmsghdr;

// RSNL datatypes wrapping the libnl data structures
pub enum NetlinkProtocol {
	route,
	unused,
	usersock,
	firewall,
	sock_diag,
	nflog,
	xfrm,
	selinux,
	iscsi,
	audit,
	fib_lookup,
	connector,
	netfilter,
	ip6_fw,
	dnrtmsg,
	kobject_uevent,
	DMEVENTS,
	scsitransport,
	ecryptfs,
	rdma,
	crypto,
}

pub struct NetlinkSocket {
    ptr: *const nl_sock,
}

pub struct NetlinkMessage {
	ptr: *const nl_msg,
    hdr: Option<*const nlmsghdr>,
}

pub fn sock_alloc() -> NetlinkSocket {
    NetlinkSocket {
        ptr: unsafe { nl_socket_alloc() },
    }
}

pub fn sock_free(sock: NetlinkSocket) {
    unsafe { nl_socket_free(sock.ptr); }
}

pub fn sock_set_buffer_size(sock: &mut NetlinkSocket, rxbuf: i32, txbuf: i32) -> i32 {
    unsafe { nl_socket_set_buffer_size(sock.ptr, rxbuf, txbuf) }
}

pub fn connect(sock: &mut NetlinkSocket, protocol: u32) -> i32 {
    unsafe { nl_connect(sock.ptr, protocol) }
}

pub fn close(sock: &mut NetlinkSocket) {
    unsafe{ nl_close(sock.ptr) }
}

pub fn sock_get_local_port(sock: &NetlinkSocket) -> u32 {
    unsafe { nl_socket_get_local_port(sock.ptr) }
}

pub fn sock_set_local_port(sock: &mut NetlinkSocket, port: u32) {
    unsafe { nl_socket_set_local_port(sock.ptr, port) }
}

pub fn sock_get_fd(sock: &NetlinkSocket) -> i32 {
    unsafe { nl_socket_get_fd(sock.ptr) }
}

pub fn send_simple<T>(sock: &NetlinkSocket, msg_type: i32, flags: i32, buf: &T, size: i32) -> i32 {
    unsafe {
        let vptr: *const c_void = mem::transmute(buf);
        nl_send_simple(sock.ptr, msg_type, flags, vptr, size) as i32
    }
}

pub fn msg_alloc() -> NetlinkMessage {
    NetlinkMessage {
        ptr: unsafe { nlmsg_alloc() },
        hdr: None
    }
}

pub fn msg_free(msg: NetlinkMessage) {
    unsafe { nlmsg_free(msg.ptr) }
}

pub fn msg_append<T>(msg: &mut NetlinkMessage, data: &T, len: u32, pad: i32) -> i32 {
    unsafe {
        let vptr: *const c_void = mem::transmute(data);
        nlmsg_append(msg.ptr, vptr, len as size_t, pad as c_int) as i32
    }
}

pub fn msg_put(msg: &mut NetlinkMessage, pid: u32, seq: u32, mtype: i32, payload: i32, flags: i32) -> bool {
    unsafe {
        let hdr = nlmsg_put(msg.ptr, pid, seq, mtype as c_int, payload as c_int, flags as c_int);

        match hdr as i32 {
            0x0 => false,
            _ => {
                msg.hdr = Some(hdr);
                true
            }
        }
    }
}

pub fn msg_data_len(msg: &NetlinkMessage) -> i32 {

    match msg.hdr {
        None => 0,
        Some(hdr) => {
            unsafe { nlmsg_datalen(hdr) }
        }
    }
}

pub fn msg_inherit(msg: &NetlinkMessage) -> NetlinkMessage {
    if msg.hdr == None {
        return msg_alloc();
    }

    let mut m = NetlinkMessage {
        ptr: unsafe { nlmsg_inherit(msg.hdr.unwrap()) },
        hdr: None
    };

    m.hdr = Some( unsafe {nlmsg_hdr(msg.ptr)} );
    m
}

<|endoftext|>


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

// TODO we're going to allocate a whole bunch of temp Strings, is it worth
// keeping some scratch mem for this and running our own StrPool?
// TODO for lint violations of names, emit a refactor script

#[macro_use]
extern crate log;

extern crate syntex_syntax as syntax;
extern crate rustc_serialize;

extern crate strings;

extern crate unicode_segmentation;
extern crate regex;
extern crate diff;
extern crate term;

use syntax::ast;
use syntax::codemap::{mk_sp, Span};
use syntax::diagnostic::{EmitterWriter, Handler};
use syntax::parse::{self, ParseSess};

use std::io::stdout;
use std::ops::{Add, Sub};
use std::path::Path;
use std::collections::HashMap;
use std::fmt;

use issues::{BadIssueSeeker, Issue};
use filemap::FileMap;
use visitor::FmtVisitor;
use config::{Config, WriteMode};

#[macro_use]
mod utils;
pub mod config;
pub mod filemap;
mod visitor;
mod checkstyle;
mod items;
mod missed_spans;
mod lists;
mod types;
mod expr;
mod imports;
mod issues;
mod rewrite;
mod string;
mod comment;
mod modules;
pub mod rustfmt_diff;
mod chains;
mod macros;
mod patterns;

const MIN_STRING: usize = 10;
// When we get scoped annotations, we should have rustfmt::skip.
const SKIP_ANNOTATION: &'static str = "rustfmt_skip";

pub trait Spanned {
    fn span(&self) -> Span;
}

impl Spanned for ast::Expr {
    fn span(&self) -> Span {
        self.span
    }
}

impl Spanned for ast::Pat {
    fn span(&self) -> Span {
        self.span
    }
}

impl Spanned for ast::Ty {
    fn span(&self) -> Span {
        self.span
    }
}

impl Spanned for ast::Arg {
    fn span(&self) -> Span {
        if items::is_named_arg(self) {
            mk_sp(self.pat.span.lo, self.ty.span.hi)
        } else {
            self.ty.span
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub struct Indent {
    // Width of the block indent, in characters. Must be a multiple of
    // Config::tab_spaces.
    pub block_indent: usize,
    // Alignment in characters.
    pub alignment: usize,
}

impl Indent {
    pub fn new(block_indent: usize, alignment: usize) -> Indent {
        Indent {
            block_indent: block_indent,
            alignment: alignment,
        }
    }

    pub fn empty() -> Indent {
        Indent::new(0, 0)
    }

    pub fn block_indent(mut self, config: &Config) -> Indent {
        self.block_indent += config.tab_spaces;
        self
    }

    pub fn block_unindent(mut self, config: &Config) -> Indent {
        self.block_indent -= config.tab_spaces;
        self
    }

    pub fn width(&self) -> usize {
        self.block_indent + self.alignment
    }

    pub fn to_string(&self, config: &Config) -> String {
        let (num_tabs, num_spaces) = if config.hard_tabs {
            (self.block_indent / config.tab_spaces, self.alignment)
        } else {
            (0, self.block_indent + self.alignment)
        };
        let num_chars = num_tabs + num_spaces;
        let mut indent = String::with_capacity(num_chars);
        for _ in 0..num_tabs {
            indent.push('\t')
        }
        for _ in 0..num_spaces {
            indent.push(' ')
        }
        indent
    }
}

impl Add for Indent {
    type Output = Indent;

    fn add(self, rhs: Indent) -> Indent {
        Indent {
            block_indent: self.block_indent + rhs.block_indent,
            alignment: self.alignment + rhs.alignment,
        }
    }
}

impl Sub for Indent {
    type Output = Indent;

    fn sub(self, rhs: Indent) -> Indent {
        Indent::new(self.block_indent - rhs.block_indent,
                    self.alignment - rhs.alignment)
    }
}

impl Add<usize> for Indent {
    type Output = Indent;

    fn add(self, rhs: usize) -> Indent {
        Indent::new(self.block_indent, self.alignment + rhs)
    }
}

impl Sub<usize> for Indent {
    type Output = Indent;

    fn sub(self, rhs: usize) -> Indent {
        Indent::new(self.block_indent, self.alignment - rhs)
    }
}

pub enum ErrorKind {
    // Line has exceeded character limit
    LineOverflow,
    // Line ends in whitespace
    TrailingWhitespace,
    // TO-DO or FIX-ME item without an issue number
    BadIssue(Issue),
}

impl fmt::Display for ErrorKind {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            ErrorKind::LineOverflow => write!(fmt, "line exceeded maximum length"),
            ErrorKind::TrailingWhitespace => write!(fmt, "left behind trailing whitespace"),
            ErrorKind::BadIssue(issue) => write!(fmt, "found {}", issue),
        }
    }
}

// Formatting errors that are identified *after* rustfmt has run.
pub struct FormattingError {
    line: u32,
    kind: ErrorKind,
}

impl FormattingError {
    fn msg_prefix(&self) -> &str {
        match self.kind {
            ErrorKind::LineOverflow |
            ErrorKind::TrailingWhitespace => "Rustfmt failed at",
            ErrorKind::BadIssue(_) => "WARNING:",
        }
    }

    fn msg_suffix(&self) -> &str {
        match self.kind {
            ErrorKind::LineOverflow |
            ErrorKind::TrailingWhitespace => "(sorry)",
            ErrorKind::BadIssue(_) => "",
        }
    }
}

pub struct FormatReport {
    // Maps stringified file paths to their associated formatting errors.
    file_error_map: HashMap<String, Vec<FormattingError>>,
}

impl FormatReport {
    pub fn warning_count(&self) -> usize {
        self.file_error_map.iter().map(|(_, ref errors)| errors.len()).fold(0, |acc, x| acc + x)
    }
}

impl fmt::Display for FormatReport {
    // Prints all the formatting errors.
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        for (file, errors) in &self.file_error_map {
            for error in errors {
                try!(write!(fmt,
                            "{} {}:{}: {} {}\n",
                            error.msg_prefix(),
                            file,
                            error.line,
                            error.kind,
                            error.msg_suffix()));
            }
        }
        Ok(())
    }
}

// Formatting which depends on the AST.
fn fmt_ast(krate: &ast::Crate,
           parse_session: &ParseSess,
           main_file: &Path,
           config: &Config,
           mode: WriteMode)
           -> FileMap {
    let mut file_map = FileMap::new();
    for (path, module) in modules::list_files(krate, parse_session.codemap()) {
        if config.skip_children && path.as_path() != main_file {
            continue;
        }
        let path = path.to_str().unwrap();
        if config.verbose {
            println!("Formatting {}", path);
        }
        let mut visitor = FmtVisitor::from_codemap(parse_session, config, Some(mode));
        visitor.format_separate_mod(module);
        file_map.insert(path.to_owned(), visitor.buffer);
    }
    file_map
}

// Formatting done on a char by char or line by line basis.
// TODO(#209) warn on bad license
// TODO(#20) other stuff for parity with make tidy
pub fn fmt_lines(file_map: &mut FileMap, config: &Config) -> FormatReport {
    let mut truncate_todo = Vec::new();
    let mut report = FormatReport { file_error_map: HashMap::new() };

    // Iterate over the chars in the file map.
    for (f, text) in file_map.iter() {
        let mut trims = vec![];
        let mut last_wspace: Option<usize> = None;
        let mut line_len = 0;
        let mut cur_line = 1;
        let mut newline_count = 0;
        let mut errors = vec![];
        let mut issue_seeker = BadIssueSeeker::new(config.report_todo, config.report_fixme);

        for (c, b) in text.chars() {
            if c == '\r' {
                line_len += c.len_utf8();
                continue;
            }

            // Add warnings for bad todos/ fixmes
            if let Some(issue) = issue_seeker.inspect(c) {
                errors.push(FormattingError {
                    line: cur_line,
                    kind: ErrorKind::BadIssue(issue),
                });
            }

            if c == '\n' {
                // Check for (and record) trailing whitespace.
                if let Some(lw) = last_wspace {
                    trims.push((cur_line, lw, b));
                    line_len -= b - lw;
                }
                // Check for any line width errors we couldn't correct.
                if line_len > config.max_width {
                    errors.push(FormattingError {
                        line: cur_line,
                        kind: ErrorKind::LineOverflow,
                    });
                }
                line_len = 0;
                cur_line += 1;
                newline_count += 1;
                last_wspace = None;
            } else {
                newline_count = 0;
                line_len += c.len_utf8();
                if c.is_whitespace() {
                    if last_wspace.is_none() {
                        last_wspace = Some(b);
                    }
                } else {
                    last_wspace = None;
                }
            }
        }

        if newline_count > 1 {
            debug!("track truncate: {} {} {}", f, text.len, newline_count);
            truncate_todo.push((f.to_owned(), text.len - newline_count + 1))
        }

        for &(l, _, _) in &trims {
            errors.push(FormattingError {
                line: l,
                kind: ErrorKind::TrailingWhitespace,
            });
        }

        report.file_error_map.insert(f.to_owned(), errors);
    }

    for (f, l) in truncate_todo {
        file_map.get_mut(&f).unwrap().truncate(l);
    }

    report
}

pub fn format_string(input: String, config: &Config, mode: WriteMode) -> FileMap {
    let path = "stdin";
    let mut parse_session = ParseSess::new();
    let krate = parse::parse_crate_from_source_str(path.to_owned(),
                                                   input,
                                                   Vec::new(),
                                                   &parse_session);

    // Suppress error output after parsing.
    let emitter = Box::new(EmitterWriter::new(Box::new(Vec::new()), None));
    parse_session.span_diagnostic.handler = Handler::with_emitter(false, emitter);

    // FIXME: we still use a FileMap even though we only have
    // one file, because fmt_lines requires a FileMap
    let mut file_map = FileMap::new();

    // do the actual formatting
    let mut visitor = FmtVisitor::from_codemap(&parse_session, config, Some(mode));
    visitor.format_separate_mod(&krate.module);

    // append final newline
    visitor.buffer.push_str("\n");
    file_map.insert(path.to_owned(), visitor.buffer);

    file_map
}

pub fn format(file: &Path, config: &Config, mode: WriteMode) -> FileMap {
    let mut parse_session = ParseSess::new();
    let krate = parse::parse_crate_from_file(file, Vec::new(), &parse_session);

    // Suppress error output after parsing.
    let emitter = Box::new(EmitterWriter::new(Box::new(Vec::new()), None));
    parse_session.span_diagnostic.handler = Handler::with_emitter(false, emitter);

    let mut file_map = fmt_ast(&krate, &parse_session, file, config, mode);

    // For some reason, the codemap does not include terminating
    // newlines so we must add one on for each file. This is sad.
    filemap::append_newlines(&mut file_map);

    file_map
}

// Make sure that we are using the correct WriteMode,
// preferring what is passed as an argument
fn check_write_mode(arg: WriteMode, config: WriteMode) -> WriteMode {
    match (arg, config) {
        (WriteMode::Default, WriteMode::Default) => WriteMode::Replace,
        (WriteMode::Default, mode) => mode,
        (mode, _) => mode,
    }
}

// args are the arguments passed on the command line, generally passed through
// to the compiler.
// write_mode determines what happens to the result of running rustfmt, see
// WriteMode.
pub fn run(file: &Path, write_mode: WriteMode, config: &Config) {
    let mode = check_write_mode(write_mode, config.write_mode);
    let mut result = format(file, config, mode);

    print!("{}", fmt_lines(&mut result, config));
    let out = stdout();
    let write_result = filemap::write_all_files(&result, out, mode, config);

    if let Err(msg) = write_result {
        println!("Error writing files: {}", msg);
    }
}

// Similar to run, but takes an input String instead of a file to format
pub fn run_from_stdin(input: String, write_mode: WriteMode, config: &Config) {
    let mode = check_write_mode(write_mode, config.write_mode);
    let mut result = format_string(input, config, mode);
    fmt_lines(&mut result, config);

    let mut out = stdout();
    let write_result = filemap::write_file(&result["stdin"], "stdin", &mut out, mode, config);

    if let Err(msg) = write_result {
        panic!("Error writing to stdout: {}", msg);
    }
}
<commit_msg>cleanup: Remove documentation of deleted parameter<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// TODO we're going to allocate a whole bunch of temp Strings, is it worth
// keeping some scratch mem for this and running our own StrPool?
// TODO for lint violations of names, emit a refactor script

#[macro_use]
extern crate log;

extern crate syntex_syntax as syntax;
extern crate rustc_serialize;

extern crate strings;

extern crate unicode_segmentation;
extern crate regex;
extern crate diff;
extern crate term;

use syntax::ast;
use syntax::codemap::{mk_sp, Span};
use syntax::diagnostic::{EmitterWriter, Handler};
use syntax::parse::{self, ParseSess};

use std::io::stdout;
use std::ops::{Add, Sub};
use std::path::Path;
use std::collections::HashMap;
use std::fmt;

use issues::{BadIssueSeeker, Issue};
use filemap::FileMap;
use visitor::FmtVisitor;
use config::{Config, WriteMode};

#[macro_use]
mod utils;
pub mod config;
pub mod filemap;
mod visitor;
mod checkstyle;
mod items;
mod missed_spans;
mod lists;
mod types;
mod expr;
mod imports;
mod issues;
mod rewrite;
mod string;
mod comment;
mod modules;
pub mod rustfmt_diff;
mod chains;
mod macros;
mod patterns;

const MIN_STRING: usize = 10;
// When we get scoped annotations, we should have rustfmt::skip.
const SKIP_ANNOTATION: &'static str = "rustfmt_skip";

pub trait Spanned {
    fn span(&self) -> Span;
}

impl Spanned for ast::Expr {
    fn span(&self) -> Span {
        self.span
    }
}

impl Spanned for ast::Pat {
    fn span(&self) -> Span {
        self.span
    }
}

impl Spanned for ast::Ty {
    fn span(&self) -> Span {
        self.span
    }
}

impl Spanned for ast::Arg {
    fn span(&self) -> Span {
        if items::is_named_arg(self) {
            mk_sp(self.pat.span.lo, self.ty.span.hi)
        } else {
            self.ty.span
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub struct Indent {
    // Width of the block indent, in characters. Must be a multiple of
    // Config::tab_spaces.
    pub block_indent: usize,
    // Alignment in characters.
    pub alignment: usize,
}

impl Indent {
    pub fn new(block_indent: usize, alignment: usize) -> Indent {
        Indent {
            block_indent: block_indent,
            alignment: alignment,
        }
    }

    pub fn empty() -> Indent {
        Indent::new(0, 0)
    }

    pub fn block_indent(mut self, config: &Config) -> Indent {
        self.block_indent += config.tab_spaces;
        self
    }

    pub fn block_unindent(mut self, config: &Config) -> Indent {
        self.block_indent -= config.tab_spaces;
        self
    }

    pub fn width(&self) -> usize {
        self.block_indent + self.alignment
    }

    pub fn to_string(&self, config: &Config) -> String {
        let (num_tabs, num_spaces) = if config.hard_tabs {
            (self.block_indent / config.tab_spaces, self.alignment)
        } else {
            (0, self.block_indent + self.alignment)
        };
        let num_chars = num_tabs + num_spaces;
        let mut indent = String::with_capacity(num_chars);
        for _ in 0..num_tabs {
            indent.push('\t')
        }
        for _ in 0..num_spaces {
            indent.push(' ')
        }
        indent
    }
}

impl Add for Indent {
    type Output = Indent;

    fn add(self, rhs: Indent) -> Indent {
        Indent {
            block_indent: self.block_indent + rhs.block_indent,
            alignment: self.alignment + rhs.alignment,
        }
    }
}

impl Sub for Indent {
    type Output = Indent;

    fn sub(self, rhs: Indent) -> Indent {
        Indent::new(self.block_indent - rhs.block_indent,
                    self.alignment - rhs.alignment)
    }
}

impl Add<usize> for Indent {
    type Output = Indent;

    fn add(self, rhs: usize) -> Indent {
        Indent::new(self.block_indent, self.alignment + rhs)
    }
}

impl Sub<usize> for Indent {
    type Output = Indent;

    fn sub(self, rhs: usize) -> Indent {
        Indent::new(self.block_indent, self.alignment - rhs)
    }
}

pub enum ErrorKind {
    // Line has exceeded character limit
    LineOverflow,
    // Line ends in whitespace
    TrailingWhitespace,
    // TO-DO or FIX-ME item without an issue number
    BadIssue(Issue),
}

impl fmt::Display for ErrorKind {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            ErrorKind::LineOverflow => write!(fmt, "line exceeded maximum length"),
            ErrorKind::TrailingWhitespace => write!(fmt, "left behind trailing whitespace"),
            ErrorKind::BadIssue(issue) => write!(fmt, "found {}", issue),
        }
    }
}

// Formatting errors that are identified *after* rustfmt has run.
pub struct FormattingError {
    line: u32,
    kind: ErrorKind,
}

impl FormattingError {
    fn msg_prefix(&self) -> &str {
        match self.kind {
            ErrorKind::LineOverflow |
            ErrorKind::TrailingWhitespace => "Rustfmt failed at",
            ErrorKind::BadIssue(_) => "WARNING:",
        }
    }

    fn msg_suffix(&self) -> &str {
        match self.kind {
            ErrorKind::LineOverflow |
            ErrorKind::TrailingWhitespace => "(sorry)",
            ErrorKind::BadIssue(_) => "",
        }
    }
}

pub struct FormatReport {
    // Maps stringified file paths to their associated formatting errors.
    file_error_map: HashMap<String, Vec<FormattingError>>,
}

impl FormatReport {
    pub fn warning_count(&self) -> usize {
        self.file_error_map.iter().map(|(_, ref errors)| errors.len()).fold(0, |acc, x| acc + x)
    }
}

impl fmt::Display for FormatReport {
    // Prints all the formatting errors.
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        for (file, errors) in &self.file_error_map {
            for error in errors {
                try!(write!(fmt,
                            "{} {}:{}: {} {}\n",
                            error.msg_prefix(),
                            file,
                            error.line,
                            error.kind,
                            error.msg_suffix()));
            }
        }
        Ok(())
    }
}

// Formatting which depends on the AST.
fn fmt_ast(krate: &ast::Crate,
           parse_session: &ParseSess,
           main_file: &Path,
           config: &Config,
           mode: WriteMode)
           -> FileMap {
    let mut file_map = FileMap::new();
    for (path, module) in modules::list_files(krate, parse_session.codemap()) {
        if config.skip_children && path.as_path() != main_file {
            continue;
        }
        let path = path.to_str().unwrap();
        if config.verbose {
            println!("Formatting {}", path);
        }
        let mut visitor = FmtVisitor::from_codemap(parse_session, config, Some(mode));
        visitor.format_separate_mod(module);
        file_map.insert(path.to_owned(), visitor.buffer);
    }
    file_map
}

// Formatting done on a char by char or line by line basis.
// TODO(#209) warn on bad license
// TODO(#20) other stuff for parity with make tidy
pub fn fmt_lines(file_map: &mut FileMap, config: &Config) -> FormatReport {
    let mut truncate_todo = Vec::new();
    let mut report = FormatReport { file_error_map: HashMap::new() };

    // Iterate over the chars in the file map.
    for (f, text) in file_map.iter() {
        let mut trims = vec![];
        let mut last_wspace: Option<usize> = None;
        let mut line_len = 0;
        let mut cur_line = 1;
        let mut newline_count = 0;
        let mut errors = vec![];
        let mut issue_seeker = BadIssueSeeker::new(config.report_todo, config.report_fixme);

        for (c, b) in text.chars() {
            if c == '\r' {
                line_len += c.len_utf8();
                continue;
            }

            // Add warnings for bad todos/ fixmes
            if let Some(issue) = issue_seeker.inspect(c) {
                errors.push(FormattingError {
                    line: cur_line,
                    kind: ErrorKind::BadIssue(issue),
                });
            }

            if c == '\n' {
                // Check for (and record) trailing whitespace.
                if let Some(lw) = last_wspace {
                    trims.push((cur_line, lw, b));
                    line_len -= b - lw;
                }
                // Check for any line width errors we couldn't correct.
                if line_len > config.max_width {
                    errors.push(FormattingError {
                        line: cur_line,
                        kind: ErrorKind::LineOverflow,
                    });
                }
                line_len = 0;
                cur_line += 1;
                newline_count += 1;
                last_wspace = None;
            } else {
                newline_count = 0;
                line_len += c.len_utf8();
                if c.is_whitespace() {
                    if last_wspace.is_none() {
                        last_wspace = Some(b);
                    }
                } else {
                    last_wspace = None;
                }
            }
        }

        if newline_count > 1 {
            debug!("track truncate: {} {} {}", f, text.len, newline_count);
            truncate_todo.push((f.to_owned(), text.len - newline_count + 1))
        }

        for &(l, _, _) in &trims {
            errors.push(FormattingError {
                line: l,
                kind: ErrorKind::TrailingWhitespace,
            });
        }

        report.file_error_map.insert(f.to_owned(), errors);
    }

    for (f, l) in truncate_todo {
        file_map.get_mut(&f).unwrap().truncate(l);
    }

    report
}

pub fn format_string(input: String, config: &Config, mode: WriteMode) -> FileMap {
    let path = "stdin";
    let mut parse_session = ParseSess::new();
    let krate = parse::parse_crate_from_source_str(path.to_owned(),
                                                   input,
                                                   Vec::new(),
                                                   &parse_session);

    // Suppress error output after parsing.
    let emitter = Box::new(EmitterWriter::new(Box::new(Vec::new()), None));
    parse_session.span_diagnostic.handler = Handler::with_emitter(false, emitter);

    // FIXME: we still use a FileMap even though we only have
    // one file, because fmt_lines requires a FileMap
    let mut file_map = FileMap::new();

    // do the actual formatting
    let mut visitor = FmtVisitor::from_codemap(&parse_session, config, Some(mode));
    visitor.format_separate_mod(&krate.module);

    // append final newline
    visitor.buffer.push_str("\n");
    file_map.insert(path.to_owned(), visitor.buffer);

    file_map
}

pub fn format(file: &Path, config: &Config, mode: WriteMode) -> FileMap {
    let mut parse_session = ParseSess::new();
    let krate = parse::parse_crate_from_file(file, Vec::new(), &parse_session);

    // Suppress error output after parsing.
    let emitter = Box::new(EmitterWriter::new(Box::new(Vec::new()), None));
    parse_session.span_diagnostic.handler = Handler::with_emitter(false, emitter);

    let mut file_map = fmt_ast(&krate, &parse_session, file, config, mode);

    // For some reason, the codemap does not include terminating
    // newlines so we must add one on for each file. This is sad.
    filemap::append_newlines(&mut file_map);

    file_map
}

// Make sure that we are using the correct WriteMode,
// preferring what is passed as an argument
fn check_write_mode(arg: WriteMode, config: WriteMode) -> WriteMode {
    match (arg, config) {
        (WriteMode::Default, WriteMode::Default) => WriteMode::Replace,
        (WriteMode::Default, mode) => mode,
        (mode, _) => mode,
    }
}

// write_mode determines what happens to the result of running rustfmt, see
// WriteMode.
pub fn run(file: &Path, write_mode: WriteMode, config: &Config) {
    let mode = check_write_mode(write_mode, config.write_mode);
    let mut result = format(file, config, mode);

    print!("{}", fmt_lines(&mut result, config));
    let out = stdout();
    let write_result = filemap::write_all_files(&result, out, mode, config);

    if let Err(msg) = write_result {
        println!("Error writing files: {}", msg);
    }
}

// Similar to run, but takes an input String instead of a file to format
pub fn run_from_stdin(input: String, write_mode: WriteMode, config: &Config) {
    let mode = check_write_mode(write_mode, config.write_mode);
    let mut result = format_string(input, config, mode);
    fmt_lines(&mut result, config);

    let mut out = stdout();
    let write_result = filemap::write_file(&result["stdin"], "stdin", &mut out, mode, config);

    if let Err(msg) = write_result {
        panic!("Error writing to stdout: {}", msg);
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! This module is the main module for the Ligature project.
//! It represents to common types and traits used by Ligature.

#![deny(missing_docs)]
//#![deny(missing_doc_example)] <-- for later, when I'm swole

#[macro_use]
extern crate lazy_static;

use regex::Regex;
use serde::{Deserialize, Serialize};

/// A string that represents a Dataset by name.
/// Currently can only be ASCII text separated by /
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize)]
pub struct Dataset(String);

impl Dataset {
    /// Creates a new Dataset and returns a Result based on if it is valid or not.
    pub fn new(name: &str) -> Result<Dataset, LigatureError> {
        lazy_static! {
            static ref RE: Regex =
                Regex::new(r"^([a-zA-Z_]{1}[a-zA-Z0-9_]*)(/[a-zA-Z_]{1}[a-zA-Z0-9_]*)*$").unwrap();
        }

        if RE.is_match(name) {
            Ok(Dataset(name.to_string()))
        } else {
            Err(LigatureError(format!("Invalid Dataset name {}", name)))
        }
    }

    /// Returns the name of the given Dataset.
    pub fn name(&self) -> &str {
        &self.0
    }
}

/// An Entity that is identified by a unique u64 id.
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
pub struct Entity(pub u64);

/// A named connection between an Entity and a Value.
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
pub struct Attribute(String);

impl Attribute {
    /// Creates a new Arrow and returns a Result based on if it is valid or not.
    pub fn new(name: &str) -> Result<Self, LigatureError> {
        lazy_static! {
            static ref RE: Regex = Regex::new(r"^[a-zA-Z_]{1}[a-zA-Z0-9_]*$").unwrap();
        }

        if RE.is_match(name) {
            Ok(Self(name.to_string()))
        } else {
            Err(LigatureError(format!("Invalid Attribute name {}", name)))
        }
    }

    /// Returns the name of the given Arrow.
    pub fn name(&self) -> &str {
        &self.0
    }
}

/// An enum that represents all the currently supported Value types.
#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub enum Value {
    /// An Entity.
    Entity(Entity),
    /// A String used for a Ligature literal
    StringLiteral(String),
    /// An i64 used for a Ligature literal
    IntegerLiteral(i64),
    /// An f64 used for a Ligature literal
    FloatLiteral(f64),
}

/// A set of enums used to express range queries when it makes sense for that type (ie no support for BooleanLiteralRange or UnknownLiteralRange since they don't make sense).
#[derive(Debug)]
pub enum Range {
    /// Represents a String range using basic String comparisons.
    StringLiteralRange {
        /// The starting String (inclusive)
        start: String,
        /// The end String (exclusive)
        end: String,
    },
    /// Represents a String range using basic i64 comparisons.
    IntegerLiteralRange {
        /// The starting i64 (inclusive)
        start: i64,
        /// The end i64 (exclusive)
        end: i64,
    },
    /// Represents a String range using basic f64 comparisons.
    FloatLiteralRange {
        /// The starting f64 (inclusive)
        start: f64,
        /// The end f64 (exclusive)
        end: f64,
    },
}

/// A Statement is a grouping of an Entity, an Attribute, and a Value.
#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub struct Statement {
    /// The Entity of a Statement
    pub entity: Entity,
    /// The Attribute of a Statement
    pub attribute: Attribute,
    /// The Value of a Statement
    pub value: Value,
}

/// A Statement that has been persisted so it has an assoicated Context Entity.
#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub struct PersistedStatement {
    /// The target Statment
    pub statement: Statement,
    /// The Context of this Statement
    pub context: Entity,
}

/// A general struct for representing errors involving Ligature.
/// TODO should probably be an enum with a bunch of specific cases
#[derive(Debug, PartialEq, Eq)]
pub struct LigatureError(pub String);

/// A trait that all Ligature implementations implement.
pub trait Ligature {
    /// Returns all Datasets in a Ligature instance.
    fn all_datasets(&self) -> Box<dyn Iterator<Item = Result<Dataset, LigatureError>>>;

    /// Check if a given Dataset exists.
    fn dataset_exists(&self, dataset: &Dataset) -> Result<bool, LigatureError>;

    /// Returns all Datasets in a Ligature instance that start with the given prefix.
    fn match_datasets_prefix(
        &self,
        prefix: &str,
    ) -> Box<dyn Iterator<Item = Result<Dataset, LigatureError>>>;

    /// Returns all Datasets in a Ligature instance that are in a given range (inclusive, exclusive].
    fn match_datasets_range(
        &self,
        start: &str,
        end: &str,
    ) -> Box<dyn Iterator<Item = Result<Dataset, LigatureError>>>;

    /// Creates a dataset with the given name.
    /// TODO should probably return its own error type { InvalidDataset, DatasetExists, CouldNotCreateDataset }
    fn create_dataset(&self, dataset: &Dataset) -> Result<(), LigatureError>;

    /// Deletes a dataset with the given name.
    /// TODO should probably return its own error type { InvalidDataset, CouldNotDeleteDataset }
    fn delete_dataset(&self, dataset: &Dataset) -> Result<(), LigatureError>;

    /// Initiazes a QueryTx
    /// TODO should probably return its own error type CouldNotInitializeQueryTx
    fn query<T>(
        &self,
        dataset: &Dataset,
        f: QueryFn<T>,
    ) -> Result<T, LigatureError>;

    /// Initiazes a WriteTx
    /// TODO should probably return its own error type CouldNotInitializeWriteTx
    fn write<T>(
        &self,
        dataset: &Dataset,
        f: WriteFn<T>,
    ) -> Result<T, LigatureError>;
}

/// An Fn that is used when making a Query tranaction.
pub type QueryFn<T> = Box<dyn Fn(Box<dyn QueryTx>) -> Result<T, LigatureError>>;

/// An Fn that is used when making a Write transaction.
pub type WriteFn<T> = Box<dyn Fn(Box<dyn WriteTx>) -> Result<T, LigatureError>>;

/// Represents a QueryTx within the context of a Ligature instance and a single Dataset
pub trait QueryTx {
    /// Returns all PersistedStatements in this Dataset.
    fn all_statements(&self)
        -> Box<dyn Iterator<Item = Result<PersistedStatement, LigatureError>>>;

    /// Returns all PersistedStatements that match the given criteria.
    /// If a parameter is None then it matches all, so passing all Nones is the same as calling all_statements.
    fn match_statements(
        &self,
        source: Option<Entity>,
        arrow: Option<Attribute>,
        target: Option<Value>,
    ) -> Box<dyn Iterator<Item = Result<PersistedStatement, LigatureError>>>;

    /// Retuns all PersistedStatements that match the given criteria.
    /// If a parameter is None then it matches all.
    fn match_statements_range(
        &self,
        source: Option<Entity>,
        arrow: Option<Attribute>,
        target: Range,
    ) -> Box<dyn Iterator<Item = Result<PersistedStatement, LigatureError>>>;

    /// Returns the PersistedStatement for the given context.
    fn statement_for_context(
        &self,
        context: &Entity,
    ) -> Result<Option<PersistedStatement>, LigatureError>;
}

/// Represents a WriteTx within the context of a Ligature instance and a single Dataset
pub trait WriteTx {
    /// Creates a new, unique Entity within this Dataset.
    /// Note: Entitys are shared across named graphs in a given Dataset.
    fn new_entity(&self) -> Result<Entity, LigatureError>;

    /// Adds a given Statement to this Dataset.
    /// If the Statement already exists nothing happens (TODO maybe add it with a new context?).
    /// Note: Potentally could trigger a ValidationError
    fn add_statement(&self, statement: &Statement) -> Result<PersistedStatement, LigatureError>;

    /// Removes a given PersistedStatement from this Dataset.
    /// If the PersistedStatement doesn't exist nothing happens.
    /// Note: Potentally could trigger a ValidationError.
    fn remove_statement(
        &self,
        persisted_statement: &PersistedStatement,
    ) -> Result<(), LigatureError>;

    /// Cancels this transaction so that none of the changes made so far will be stored.
    /// This also closes this transaction so no other methods can be called without returning a LigatureError.
    fn cancel(&self) -> Result<(), LigatureError>;
}
<commit_msg>cargo fmt<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! This module is the main module for the Ligature project.
//! It represents to common types and traits used by Ligature.

#![deny(missing_docs)]
//#![deny(missing_doc_example)] <-- for later, when I'm swole

#[macro_use]
extern crate lazy_static;

use regex::Regex;
use serde::{Deserialize, Serialize};

/// A string that represents a Dataset by name.
/// Currently can only be ASCII text separated by /
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize)]
pub struct Dataset(String);

impl Dataset {
    /// Creates a new Dataset and returns a Result based on if it is valid or not.
    pub fn new(name: &str) -> Result<Dataset, LigatureError> {
        lazy_static! {
            static ref RE: Regex =
                Regex::new(r"^([a-zA-Z_]{1}[a-zA-Z0-9_]*)(/[a-zA-Z_]{1}[a-zA-Z0-9_]*)*$").unwrap();
        }

        if RE.is_match(name) {
            Ok(Dataset(name.to_string()))
        } else {
            Err(LigatureError(format!("Invalid Dataset name {}", name)))
        }
    }

    /// Returns the name of the given Dataset.
    pub fn name(&self) -> &str {
        &self.0
    }
}

/// An Entity that is identified by a unique u64 id.
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
pub struct Entity(pub u64);

/// A named connection between an Entity and a Value.
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
pub struct Attribute(String);

impl Attribute {
    /// Creates a new Arrow and returns a Result based on if it is valid or not.
    pub fn new(name: &str) -> Result<Self, LigatureError> {
        lazy_static! {
            static ref RE: Regex = Regex::new(r"^[a-zA-Z_]{1}[a-zA-Z0-9_]*$").unwrap();
        }

        if RE.is_match(name) {
            Ok(Self(name.to_string()))
        } else {
            Err(LigatureError(format!("Invalid Attribute name {}", name)))
        }
    }

    /// Returns the name of the given Arrow.
    pub fn name(&self) -> &str {
        &self.0
    }
}

/// An enum that represents all the currently supported Value types.
#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub enum Value {
    /// An Entity.
    Entity(Entity),
    /// A String used for a Ligature literal
    StringLiteral(String),
    /// An i64 used for a Ligature literal
    IntegerLiteral(i64),
    /// An f64 used for a Ligature literal
    FloatLiteral(f64),
}

/// A set of enums used to express range queries when it makes sense for that type (ie no support for BooleanLiteralRange or UnknownLiteralRange since they don't make sense).
#[derive(Debug)]
pub enum Range {
    /// Represents a String range using basic String comparisons.
    StringLiteralRange {
        /// The starting String (inclusive)
        start: String,
        /// The end String (exclusive)
        end: String,
    },
    /// Represents a String range using basic i64 comparisons.
    IntegerLiteralRange {
        /// The starting i64 (inclusive)
        start: i64,
        /// The end i64 (exclusive)
        end: i64,
    },
    /// Represents a String range using basic f64 comparisons.
    FloatLiteralRange {
        /// The starting f64 (inclusive)
        start: f64,
        /// The end f64 (exclusive)
        end: f64,
    },
}

/// A Statement is a grouping of an Entity, an Attribute, and a Value.
#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub struct Statement {
    /// The Entity of a Statement
    pub entity: Entity,
    /// The Attribute of a Statement
    pub attribute: Attribute,
    /// The Value of a Statement
    pub value: Value,
}

/// A Statement that has been persisted so it has an assoicated Context Entity.
#[derive(Debug, Clone, PartialOrd, PartialEq)]
pub struct PersistedStatement {
    /// The target Statment
    pub statement: Statement,
    /// The Context of this Statement
    pub context: Entity,
}

/// A general struct for representing errors involving Ligature.
/// TODO should probably be an enum with a bunch of specific cases
#[derive(Debug, PartialEq, Eq)]
pub struct LigatureError(pub String);

/// A trait that all Ligature implementations implement.
pub trait Ligature {
    /// Returns all Datasets in a Ligature instance.
    fn all_datasets(&self) -> Box<dyn Iterator<Item = Result<Dataset, LigatureError>>>;

    /// Check if a given Dataset exists.
    fn dataset_exists(&self, dataset: &Dataset) -> Result<bool, LigatureError>;

    /// Returns all Datasets in a Ligature instance that start with the given prefix.
    fn match_datasets_prefix(
        &self,
        prefix: &str,
    ) -> Box<dyn Iterator<Item = Result<Dataset, LigatureError>>>;

    /// Returns all Datasets in a Ligature instance that are in a given range (inclusive, exclusive].
    fn match_datasets_range(
        &self,
        start: &str,
        end: &str,
    ) -> Box<dyn Iterator<Item = Result<Dataset, LigatureError>>>;

    /// Creates a dataset with the given name.
    /// TODO should probably return its own error type { InvalidDataset, DatasetExists, CouldNotCreateDataset }
    fn create_dataset(&self, dataset: &Dataset) -> Result<(), LigatureError>;

    /// Deletes a dataset with the given name.
    /// TODO should probably return its own error type { InvalidDataset, CouldNotDeleteDataset }
    fn delete_dataset(&self, dataset: &Dataset) -> Result<(), LigatureError>;

    /// Initiazes a QueryTx
    /// TODO should probably return its own error type CouldNotInitializeQueryTx
    fn query<T>(&self, dataset: &Dataset, f: QueryFn<T>) -> Result<T, LigatureError>;

    /// Initiazes a WriteTx
    /// TODO should probably return its own error type CouldNotInitializeWriteTx
    fn write<T>(&self, dataset: &Dataset, f: WriteFn<T>) -> Result<T, LigatureError>;
}

/// An Fn that is used when making a Query tranaction.
pub type QueryFn<T> = Box<dyn Fn(Box<dyn QueryTx>) -> Result<T, LigatureError>>;

/// An Fn that is used when making a Write transaction.
pub type WriteFn<T> = Box<dyn Fn(Box<dyn WriteTx>) -> Result<T, LigatureError>>;

/// Represents a QueryTx within the context of a Ligature instance and a single Dataset
pub trait QueryTx {
    /// Returns all PersistedStatements in this Dataset.
    fn all_statements(&self)
        -> Box<dyn Iterator<Item = Result<PersistedStatement, LigatureError>>>;

    /// Returns all PersistedStatements that match the given criteria.
    /// If a parameter is None then it matches all, so passing all Nones is the same as calling all_statements.
    fn match_statements(
        &self,
        source: Option<Entity>,
        arrow: Option<Attribute>,
        target: Option<Value>,
    ) -> Box<dyn Iterator<Item = Result<PersistedStatement, LigatureError>>>;

    /// Retuns all PersistedStatements that match the given criteria.
    /// If a parameter is None then it matches all.
    fn match_statements_range(
        &self,
        source: Option<Entity>,
        arrow: Option<Attribute>,
        target: Range,
    ) -> Box<dyn Iterator<Item = Result<PersistedStatement, LigatureError>>>;

    /// Returns the PersistedStatement for the given context.
    fn statement_for_context(
        &self,
        context: &Entity,
    ) -> Result<Option<PersistedStatement>, LigatureError>;
}

/// Represents a WriteTx within the context of a Ligature instance and a single Dataset
pub trait WriteTx {
    /// Creates a new, unique Entity within this Dataset.
    /// Note: Entitys are shared across named graphs in a given Dataset.
    fn new_entity(&self) -> Result<Entity, LigatureError>;

    /// Adds a given Statement to this Dataset.
    /// If the Statement already exists nothing happens (TODO maybe add it with a new context?).
    /// Note: Potentally could trigger a ValidationError
    fn add_statement(&self, statement: &Statement) -> Result<PersistedStatement, LigatureError>;

    /// Removes a given PersistedStatement from this Dataset.
    /// If the PersistedStatement doesn't exist nothing happens.
    /// Note: Potentally could trigger a ValidationError.
    fn remove_statement(
        &self,
        persisted_statement: &PersistedStatement,
    ) -> Result<(), LigatureError>;

    /// Cancels this transaction so that none of the changes made so far will be stored.
    /// This also closes this transaction so no other methods can be called without returning a LigatureError.
    fn cancel(&self) -> Result<(), LigatureError>;
}
<|endoftext|>


<commit_before>#![feature(if_let, phase, plugin_registrar)]

extern crate rustc;
extern crate syntax;

#[phase(plugin, link)] extern crate log;

use rustc::plugin::Registry;
use syntax::ast::{Attribute, Attribute_, Item, MetaItem};
use syntax::ext::base::{ExtCtxt, ItemModifier, SyntaxExtension};
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::ptr::P;

use std::error::FromError;
use std::io::{mod, IoResult};

enum AttrError {
    IoError(io::IoError),
    Path,
    Syntax
}

impl FromError<io::IoError> for AttrError {
    fn from_error(e: io::IoError) -> AttrError {
        AttrError::IoError(e)
    }
}

fn extract_doc_path(meta: &MetaItem) -> Result<Path, AttrError> {
    use syntax::ast::MetaItem_::MetaNameValue as NameValue;
    use syntax::ast::Lit_::LitStr;

    match meta.node {
        NameValue(_, ref lit) => {
            match lit.node {
                LitStr(ref path, _) => {
                    Path::new_opt(path).ok_or(AttrError::Path)
                },
                _ => Err(AttrError::Syntax)
            }
        },
        _ => Err(AttrError::Syntax)
    }
}

fn slurp_doc_file(cx: &mut ExtCtxt, path: Path, sp: Span) -> IoResult<String> {
    use std::io::File;

    let source_path = Path::new(cx.codemap().span_to_filename(sp));
    let path = source_path.dir_path().join(path);
    let mut file = try!(File::open(&path));
    file.read_to_string()
}

fn mk_doc_attr(doc_string: String) -> Attribute {
    use syntax::attr;
    let meta_item = attr::mk_name_value_item_str(
        token::intern_and_get_ident("doc"),
        token::intern_and_get_ident(doc_string.as_slice())
    );
    attr::mk_attr_inner(attr::mk_attr_id(), meta_item)
}

fn expand_attr_(cx: &mut ExtCtxt, sp: Span, meta: &MetaItem,
                attrs: &mut Vec<Attribute>) -> Result<(), AttrError> {

    let path = try!(extract_doc_path(meta));
    let doc_string = try!(slurp_doc_file(cx, path, sp));

    let attr = mk_doc_attr(doc_string);
    attrs.push(attr);

    Ok(())
}

fn expand_attr(cx: &mut ExtCtxt, sp: Span, meta: &MetaItem,
               item: P<Item>) -> P<Item> {
    use syntax::ptr::P;

    let mut item = item.and_then(|x| x); // unwrap the item
    if let Err(e) = expand_attr_(cx, sp, meta, &mut item.attrs) {
        match e {
            AttrError::Path => {
                cx.span_err(sp, "Invalid path in doc_file attribute");
            }
            AttrError::Syntax => {
                cx.span_err(sp, "Invalid use of doc_file attribute, use like: \
                            `#[doc_file = \"foo.markdown\"]`");
            }
            AttrError::IoError(e) => {
                let msg = format!("IO error reading doc_file attribute: {}", e);
                cx.span_err(sp, msg.as_slice());
            }
        };
    };
    P(item)
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    let modifier = box expand_attr as Box<ItemModifier>;
    reg.register_syntax_extension(token::intern("doc_file"),
                                  SyntaxExtension::Modifier(modifier));
}
<commit_msg>Fix warnings<commit_after>#![feature(phase, plugin_registrar)]

extern crate rustc;
extern crate syntax;

#[phase(plugin, link)] extern crate log;

use rustc::plugin::Registry;
use syntax::ast::{Attribute, Item, MetaItem};
use syntax::ext::base::{ExtCtxt, ItemModifier, SyntaxExtension};
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::ptr::P;

use std::error::FromError;
use std::io::{mod, IoResult};

enum AttrError {
    IoError(io::IoError),
    Path,
    Syntax
}

impl FromError<io::IoError> for AttrError {
    fn from_error(e: io::IoError) -> AttrError {
        AttrError::IoError(e)
    }
}

fn extract_doc_path(meta: &MetaItem) -> Result<Path, AttrError> {
    use syntax::ast::MetaItem_::MetaNameValue as NameValue;
    use syntax::ast::Lit_::LitStr;

    match meta.node {
        NameValue(_, ref lit) => {
            match lit.node {
                LitStr(ref path, _) => {
                    Path::new_opt(path).ok_or(AttrError::Path)
                },
                _ => Err(AttrError::Syntax)
            }
        },
        _ => Err(AttrError::Syntax)
    }
}

fn slurp_doc_file(cx: &mut ExtCtxt, path: Path, sp: Span) -> IoResult<String> {
    use std::io::File;

    let source_path = Path::new(cx.codemap().span_to_filename(sp));
    let path = source_path.dir_path().join(path);
    let mut file = try!(File::open(&path));
    file.read_to_string()
}

fn mk_doc_attr(doc_string: String) -> Attribute {
    use syntax::attr;
    let meta_item = attr::mk_name_value_item_str(
        token::intern_and_get_ident("doc"),
        token::intern_and_get_ident(doc_string.as_slice())
    );
    attr::mk_attr_inner(attr::mk_attr_id(), meta_item)
}

fn expand_attr_(cx: &mut ExtCtxt, sp: Span, meta: &MetaItem,
                attrs: &mut Vec<Attribute>) -> Result<(), AttrError> {

    let path = try!(extract_doc_path(meta));
    let doc_string = try!(slurp_doc_file(cx, path, sp));

    let attr = mk_doc_attr(doc_string);
    attrs.push(attr);

    Ok(())
}

fn expand_attr(cx: &mut ExtCtxt, sp: Span, meta: &MetaItem,
               item: P<Item>) -> P<Item> {
    use syntax::ptr::P;

    let mut item = item.and_then(|x| x); // unwrap the item
    if let Err(e) = expand_attr_(cx, sp, meta, &mut item.attrs) {
        match e {
            AttrError::Path => {
                cx.span_err(sp, "Invalid path in doc_file attribute");
            }
            AttrError::Syntax => {
                cx.span_err(sp, "Invalid use of doc_file attribute, use like: \
                            `#[doc_file = \"foo.markdown\"]`");
            }
            AttrError::IoError(e) => {
                let msg = format!("IO error reading doc_file attribute: {}", e);
                cx.span_err(sp, msg.as_slice());
            }
        };
    };
    P(item)
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    let modifier = box expand_attr as Box<ItemModifier>;
    reg.register_syntax_extension(token::intern("doc_file"),
                                  SyntaxExtension::Modifier(modifier));
}
<|endoftext|>