<commit_before>use serde::{Serialize, Serializer};
use std::collections::HashMap;

#[derive(Serialize, PartialEq, Debug)]
pub struct Replay {
    pub header_size: u32,
    pub header_crc: u32,
    pub major_version: u32,
    pub minor_version: u32,
    pub game_type: String,

    #[serde(serialize_with = "pair_vec")]
    pub properties: Vec<(String, HeaderProp)>,
    pub content_size: u32,
    pub content_crc: u32,
    pub levels: Vec<String>,
    pub keyframes: Vec<KeyFrame>,
    pub debug_info: Vec<DebugInfo>,
    pub tick_marks: Vec<TickMark>,
    pub packages: Vec<String>,
    pub objects: Vec<String>,
    pub names: Vec<String>,
    pub class_indices: Vec<ClassIndex>,
    pub net_cache: Vec<ClassNetCache>,
}

#[derive(Serialize, PartialEq, Debug)]
pub struct TickMark {
    pub description: String,
    pub frame: u32,
}

#[derive(Serialize, PartialEq, Debug)]
pub struct KeyFrame {
    pub time: f32,
    pub frame: u32,
    pub position: u32,
}

#[derive(PartialEq, Debug)]
pub enum HeaderProp {
    Array(Vec<Vec<(String, HeaderProp)>>),
    Bool(bool),
    Byte,
    Float(f32),
    Int(u32),
    Name(String),
    QWord(u64),
    Str(String),
}

#[derive(Serialize, PartialEq, Debug)]
pub struct DebugInfo {
    pub frame: u32,
    pub user: String,
    pub text: String,
}

#[derive(Serialize, PartialEq, Debug)]
pub struct ClassIndex {
    pub class: String,
    pub index: u32,
}

#[derive(Serialize, PartialEq, Debug)]
pub struct CacheProp {
    pub index: u32,
    pub id: u32,
}

#[derive(Serialize, PartialEq, Debug)]
pub struct ClassNetCache {
    pub index: u32,
    pub parent_id: u32,
    pub id: u32,
    pub properties: Vec<CacheProp>,
}

/// Serialize a vector of key value tuples into a map. This is useful when the data we're ingesting
/// (rocket league replay data) doesn't have a defined spec, so it may be assuming too much to
/// store it into an associative array, so it's stored as a normal sequence. Here we serialize as a
/// map structure because most replay parser do this, so we should be compliant and the data format
/// doesn't dictate that the keys in a sequence of key value pairs must be distinct. It's true,
/// JSON doesn't need the keys to be unique: http://stackoverflow.com/q/21832701/433785
fn pair_vec<K, V, S>(inp: &[(K, V)], serializer: &mut S) -> Result<(), S::Error>
    where K: Serialize,
          V: Serialize,
          S: Serializer
{
    let mut state = try!(serializer.serialize_map(Some(inp.len())));
    for &(ref key, ref val) in inp.iter() {
        try!(serializer.serialize_map_key(&mut state, key));
        try!(serializer.serialize_map_value(&mut state, val));
    }
    return serializer.serialize_map_end(state);
}

/// By default serde will generate a serialization method that writes out the enum as well as the
/// enum value. Since header values are self describing in JSON, we do not need to serialize the
/// enum type. This is slightly lossy as in the serialized format it will be ambiguous if a value
/// is a `Name` or `Str`, as well as `Byte`, `Float`, `Int`, or `QWord`.
impl Serialize for HeaderProp {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer
    {
        match *self {
            HeaderProp::Array(ref x) => {
                let mut state = try!(serializer.serialize_seq(Some(x.len())));
                for inner in x {
                    // Look for a better way to do this instead of allocating the intermediate map
                    let mut els = HashMap::new();
                    for &(ref key, ref val) in inner.iter() {
                        els.insert(key.clone(), val.clone());
                    }
                    try!(serializer.serialize_seq_elt(&mut state, els));
                }
                return serializer.serialize_seq_end(state);
            }
            HeaderProp::Bool(ref x) => serializer.serialize_bool(*x),
            HeaderProp::Byte => serializer.serialize_u8(0),
            HeaderProp::Float(ref x) => serializer.serialize_f32(*x),
            HeaderProp::Int(ref x) => serializer.serialize_u32(*x),
            HeaderProp::QWord(ref x) => serializer.serialize_u64(*x),
            HeaderProp::Name(ref x) | HeaderProp::Str(ref x) => serializer.serialize_str(&x)
        }
    }
}

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

    fn to_json<T: serde::Serialize>(input: &T) -> std::string::String {
        return serde_json::to_string(input).unwrap();
    }

    #[test]
    fn serialize_header_array() {
        let data = vec![
            vec![
                ("frame".to_string(), HeaderProp::Int(441)),
                ("PlayerName".to_string(), HeaderProp::Str("rust is awesome".to_string()))
            ], vec![
                ("frame".to_string(), HeaderProp::Int(1738)),
                ("PlayerName".to_string(), HeaderProp::Str("rusty".to_string()))
            ]
          ];
        let actual = HeaderProp::Array(data);
        assert_eq!(to_json(&actual), "[{\"PlayerName\":\"rust is awesome\",\"frame\":441},{\"PlayerName\":\"rusty\",\"frame\":1738}]");
    }

    #[test]
    fn serialize_header_bool() {
        assert_eq!(to_json(&HeaderProp::Bool(false)), "false");
        assert_eq!(to_json(&HeaderProp::Bool(true)), "true");
    }

    #[test]
    fn serialize_header_numbers() {
        assert_eq!(to_json(&HeaderProp::Byte), "0");
        assert_eq!(to_json(&HeaderProp::QWord(10)), "10");
        assert_eq!(to_json(&HeaderProp::Float(10.2)), "10.2");
        assert_eq!(to_json(&HeaderProp::Int(11)), "11");
    }

    #[test]
    fn serialize_header_str() {
        let val = "hello world";
        assert_eq!(to_json(&HeaderProp::Str(val.to_string())), "\"hello world\"");
        assert_eq!(to_json(&HeaderProp::Name(val.to_string())), "\"hello world\"");
    }
}
<commit_msg>Avoid needless borrowing<commit_after>use serde::{Serialize, Serializer};
use std::collections::HashMap;

#[derive(Serialize, PartialEq, Debug)]
pub struct Replay {
    pub header_size: u32,
    pub header_crc: u32,
    pub major_version: u32,
    pub minor_version: u32,
    pub game_type: String,

    #[serde(serialize_with = "pair_vec")]
    pub properties: Vec<(String, HeaderProp)>,
    pub content_size: u32,
    pub content_crc: u32,
    pub levels: Vec<String>,
    pub keyframes: Vec<KeyFrame>,
    pub debug_info: Vec<DebugInfo>,
    pub tick_marks: Vec<TickMark>,
    pub packages: Vec<String>,
    pub objects: Vec<String>,
    pub names: Vec<String>,
    pub class_indices: Vec<ClassIndex>,
    pub net_cache: Vec<ClassNetCache>,
}

#[derive(Serialize, PartialEq, Debug)]
pub struct TickMark {
    pub description: String,
    pub frame: u32,
}

#[derive(Serialize, PartialEq, Debug)]
pub struct KeyFrame {
    pub time: f32,
    pub frame: u32,
    pub position: u32,
}

#[derive(PartialEq, Debug)]
pub enum HeaderProp {
    Array(Vec<Vec<(String, HeaderProp)>>),
    Bool(bool),
    Byte,
    Float(f32),
    Int(u32),
    Name(String),
    QWord(u64),
    Str(String),
}

#[derive(Serialize, PartialEq, Debug)]
pub struct DebugInfo {
    pub frame: u32,
    pub user: String,
    pub text: String,
}

#[derive(Serialize, PartialEq, Debug)]
pub struct ClassIndex {
    pub class: String,
    pub index: u32,
}

#[derive(Serialize, PartialEq, Debug)]
pub struct CacheProp {
    pub index: u32,
    pub id: u32,
}

#[derive(Serialize, PartialEq, Debug)]
pub struct ClassNetCache {
    pub index: u32,
    pub parent_id: u32,
    pub id: u32,
    pub properties: Vec<CacheProp>,
}

/// Serialize a vector of key value tuples into a map. This is useful when the data we're ingesting
/// (rocket league replay data) doesn't have a defined spec, so it may be assuming too much to
/// store it into an associative array, so it's stored as a normal sequence. Here we serialize as a
/// map structure because most replay parser do this, so we should be compliant and the data format
/// doesn't dictate that the keys in a sequence of key value pairs must be distinct. It's true,
/// JSON doesn't need the keys to be unique: http://stackoverflow.com/q/21832701/433785
fn pair_vec<K, V, S>(inp: &[(K, V)], serializer: &mut S) -> Result<(), S::Error>
    where K: Serialize,
          V: Serialize,
          S: Serializer
{
    let mut state = try!(serializer.serialize_map(Some(inp.len())));
    for &(ref key, ref val) in inp.iter() {
        try!(serializer.serialize_map_key(&mut state, key));
        try!(serializer.serialize_map_value(&mut state, val));
    }
    return serializer.serialize_map_end(state);
}

/// By default serde will generate a serialization method that writes out the enum as well as the
/// enum value. Since header values are self describing in JSON, we do not need to serialize the
/// enum type. This is slightly lossy as in the serialized format it will be ambiguous if a value
/// is a `Name` or `Str`, as well as `Byte`, `Float`, `Int`, or `QWord`.
impl Serialize for HeaderProp {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer
    {
        match *self {
            HeaderProp::Array(ref x) => {
                let mut state = try!(serializer.serialize_seq(Some(x.len())));
                for inner in x {
                    // Look for a better way to do this instead of allocating the intermediate map
                    let mut els = HashMap::new();
                    for &(ref key, ref val) in inner.iter() {
                        els.insert(key, val);
                    }
                    try!(serializer.serialize_seq_elt(&mut state, els));
                }
                return serializer.serialize_seq_end(state);
            }
            HeaderProp::Bool(ref x) => serializer.serialize_bool(*x),
            HeaderProp::Byte => serializer.serialize_u8(0),
            HeaderProp::Float(ref x) => serializer.serialize_f32(*x),
            HeaderProp::Int(ref x) => serializer.serialize_u32(*x),
            HeaderProp::QWord(ref x) => serializer.serialize_u64(*x),
            HeaderProp::Name(ref x) | HeaderProp::Str(ref x) => serializer.serialize_str(x)
        }
    }
}

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

    fn to_json<T: serde::Serialize>(input: &T) -> std::string::String {
        return serde_json::to_string(input).unwrap();
    }

    #[test]
    fn serialize_header_array() {
        let data = vec![
            vec![
                ("frame".to_string(), HeaderProp::Int(441)),
                ("PlayerName".to_string(), HeaderProp::Str("rust is awesome".to_string()))
            ], vec![
                ("frame".to_string(), HeaderProp::Int(1738)),
                ("PlayerName".to_string(), HeaderProp::Str("rusty".to_string()))
            ]
          ];
        let actual = HeaderProp::Array(data);
        assert_eq!(to_json(&actual), "[{\"PlayerName\":\"rust is awesome\",\"frame\":441},{\"PlayerName\":\"rusty\",\"frame\":1738}]");
    }

    #[test]
    fn serialize_header_bool() {
        assert_eq!(to_json(&HeaderProp::Bool(false)), "false");
        assert_eq!(to_json(&HeaderProp::Bool(true)), "true");
    }

    #[test]
    fn serialize_header_numbers() {
        assert_eq!(to_json(&HeaderProp::Byte), "0");
        assert_eq!(to_json(&HeaderProp::QWord(10)), "10");
        assert_eq!(to_json(&HeaderProp::Float(10.2)), "10.2");
        assert_eq!(to_json(&HeaderProp::Int(11)), "11");
    }

    #[test]
    fn serialize_header_str() {
        let val = "hello world";
        assert_eq!(to_json(&HeaderProp::Str(val.to_string())), "\"hello world\"");
        assert_eq!(to_json(&HeaderProp::Name(val.to_string())), "\"hello world\"");
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::CString;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::io::{Error, ErrorKind};
use std::io::Result as IoResult;
use std::iter::{Iterator, IntoIterator};
use std::path::Path;
use std::process::Command;

use cbox::{CBox, CSemiBox};
use ffi::analysis::LLVMVerifierFailureAction;
use ffi::{analysis, core, linker, LLVMModule};
use ffi::bit_writer as writer;
use ffi::bit_reader as reader;
use ffi::ir_reader as ir_reader;
use ffi::prelude::{LLVMValueRef, LLVMModuleRef};
use ffi::transforms::pass_manager_builder as builder;
use libc::{c_char, c_uint};

use buffer::MemoryBuffer;
use context::{Context, GetContext};
use util;
use ty::Type;
use value::{Function, GlobalValue, Value, ValueIter};

/// Represents a single compilation unit of code.
///
/// This is attached to the lifetime of the context that constructs it, but is owned by the `CSemiBox`.
pub struct Module;
native_ref!(&Module = LLVMModuleRef);
impl Module
{
  /// Create a new module in the context given with the name given.
  ///
  /// The lifetime of the module will match the lifetime of the context
  /// you instance it in because the context contains it.
  ///
  /// ```rust
  /// use llvm::*;
  /// let context = Context::new();
  /// let context = context.as_semi();
  /// let module = Module::new("name", &context);
  /// println!("{:?}", module)
  /// ```
  pub fn new<'a>(name: &str, context: &'a Context) -> CSemiBox<'a, Module>
  {
    let c_name = CString::new(name).unwrap();
    unsafe {
    	CSemiBox::new(core::LLVMModuleCreateWithNameInContext(c_name.as_ptr(), context.into()))
    }
  }

  /// Add an external global to the module with the given type and name.
  pub fn add_global<'a>(&'a self, name: &str, ty: &'a Type) -> &'a GlobalValue {
    util::with_cstr(name, |ptr| unsafe {
        core::LLVMAddGlobal(self.into(), ty.into(), ptr).into()
    })
  }

  /// Add a global in the given address space to the module with the given type and name.
  pub fn add_global_in_addr_space<'a>(&'a self,
  	                                  name: &str,
  	                                  ty: &'a Type,
  	                                  sp: AddressSpace) -> &'a GlobalValue
  {
    util::with_cstr(name, |ptr| unsafe {
      core::LLVMAddGlobalInAddressSpace(self.into(), ty.into(), ptr, sp as c_uint).into()
    })
  }

  /// Add a constant global to the module with the given type, name and value.
  pub fn add_global_constant<'a>(&'a self, name: &str, val: &'a Value) -> &'a GlobalValue
  {
    util::with_cstr(name, |ptr| unsafe {
      let global = core::LLVMAddGlobal(self.into(), val.get_type().into(), ptr);
      core::LLVMSetInitializer (global.into(), val.into());
      global.into()
    })
  }
  /// Get the global with the name given, or `None` if no global with that name exists.
  pub fn get_global<'a>(&'a self, name: &str) -> Option<&'a GlobalValue>
  {
    util::with_cstr(name, |ptr| unsafe {
        let ptr = core::LLVMGetNamedGlobal(self.into(), ptr);
        util::ptr_to_null(ptr)
    })
  }

  pub fn global_values<'a>(&'a self) -> ValueIter<&'a GlobalValue>
  {
  	ValueIter::new(
 			unsafe { core::LLVMGetFirstGlobal(self.into()) },
 			core::LLVMGetNextGlobal
 		)
  }

  pub fn parse_ir<'a>(context: &'a Context, path: &str) -> Result<CSemiBox<'a, Module>, CBox<str>>
  {
  	unsafe {
      let mut out = mem::uninitialized();
      let mut err = mem::uninitialized();
      let buf = try!(MemoryBuffer::new_from_file(path));

      let ret = ir_reader::LLVMParseIRInContext(context.into(), buf.as_ptr(), &mut out, &mut err);
      if ret == 1 {
      	Err(CBox::new(err))
      } else {
        Ok(CSemiBox::new(out))
      }
    }
  }

  /// Parse this bitcode file into a module, or return an error string.
  pub fn parse_bitcode<'a>(context: &'a Context, path: &str) -> Result<CSemiBox<'a, Module>, CBox<str>> {
    unsafe {
      let mut out = mem::uninitialized();
      let mut err = mem::uninitialized();
      let buf = try!(MemoryBuffer::new_from_file(path));

      let ret = reader::LLVMParseBitcodeInContext(context.into(),
      																					  buf.as_ptr(),
      	                                          &mut out,
      	                                          &mut err);
      if ret == 1 {
          Err(CBox::new(err))
      } else {
          Ok(CSemiBox::new(out))
      }
    }
  }
  /// Write this module's bitcode to the path given.
  pub fn write_bitcode(&self, path: &str) -> IoResult<()>
  {
     util::with_cstr(path, |cpath| unsafe {
       if writer::LLVMWriteBitcodeToFile(self.into(), cpath) != 0 {
           Err(Error::new(ErrorKind::Other, &format!("could not write to {}", path) as &str))
       } else {
           Ok(())
       }
     })
  }
  /// Add a function to the module with the name given.
  pub fn add_function<'a>(&'a self, name: &str, sig: &'a Type) -> &'a Function
  {
    let c_name = CString::new(name).unwrap();
    unsafe { core::LLVMAddFunction(self.into(), c_name.as_ptr(), sig.into()) }.into()
  }

  /// Returns the function with the name given, or `None` if no function with that name exists.
  pub fn get_function<'a>(&'a self, name: &str) -> Option<&'a Function>
  {
    let c_name = CString::new(name).unwrap();
    unsafe {
      let ty = core::LLVMGetNamedFunction(self.into(), c_name.as_ptr());
      util::ptr_to_null(ty)
    }
  }

  /// Returns the type with the name given, or `None`` if no type with that name exists.
  pub fn get_type<'a>(&'a self, name: &str) -> Option<&'a Type>
  {
    let c_name = CString::new(name).unwrap();
    unsafe {
      let ty = core::LLVMGetTypeByName(self.into(), c_name.as_ptr());
      util::ptr_to_null(ty)
    }
  }

  /// Clone this module.
  pub fn clone<'a>(&'a self) -> CSemiBox<'a, Module>
  {
    CSemiBox::new(unsafe { core::LLVMCloneModule(self.into()) })
  }

  /// Optimize this module with the given optimization level and size level.
  ///
  /// This runs passes depending on the levels given.
  pub fn optimize(&self, opt_level: usize, size_level: usize) {
    unsafe {
      let builder = builder::LLVMPassManagerBuilderCreate();
      builder::LLVMPassManagerBuilderSetOptLevel(builder, opt_level as c_uint);
      builder::LLVMPassManagerBuilderSetSizeLevel(builder, size_level as c_uint);
      let pass_manager = core::LLVMCreatePassManager();
      builder::LLVMPassManagerBuilderPopulateModulePassManager(builder, pass_manager);
      builder::LLVMPassManagerBuilderDispose(builder);
      core::LLVMRunPassManager(pass_manager, self.into());
    }
  }

  /// Returns the target data of this module represented as a string
  pub fn get_target(&self) -> &str
  {
    unsafe {
      let target = core::LLVMGetTarget(self.into());
      util::to_str(target as *mut c_char)
    }
  }

  pub fn get_data_layout(&self) -> &str
  {
  	unsafe {
  		let layout = core::LLVMGetDataLayout(self.into());
  		util::to_str(layout as *mut c_char)
  	}
  }

  /// Set the target data of this module to the target data string given.
  pub fn set_target(&self, target: &str)
  {
      let c_target = CString::new(target).unwrap();
      unsafe { core::LLVMSetTarget(self.into(), c_target.as_ptr()) }
  }

  /// Verify that the module is safe to run, returning a string detailing the error
  /// when an error occurs.
  pub fn verify(&self) -> Result<(), CBox<str>>
  {
    unsafe {
      let mut error = mem::uninitialized();
      let action = LLVMVerifierFailureAction::LLVMReturnStatusAction;
      if analysis::LLVMVerifyModule(self.into(), action, &mut error) == 1 {
          Err(CBox::new(error))
      } else {
          Ok(())
      }
    }
  }

  /// Compile the module into an object file at the given location.
  ///
  /// Note that this uses the LLVM tool `llc` to do this, which may or may not be
  /// installed on the user's machine.
  pub fn compile(&self, path: &Path, opt_level: usize) -> IoResult<()>
  {
    let dir = env::temp_dir();
    let path = path.to_str().unwrap();
    let mod_path = dir.join("module.bc");
    let mod_path = mod_path.to_str().unwrap();
    try!(self.write_bitcode(mod_path));
    Command::new("llc")
      .arg(&format!("-O={}", opt_level))
      .arg("-filetype=obj")
      .arg("-o").arg(path)
      .arg(mod_path)
      .spawn()
      .map(|_| ())
  }

  /// Link a module into this module, returning an error string if an error occurs.
  ///
  /// This *does not* destroy the source module.
  pub fn link(&self, src: &Module) -> Result<(), CBox<str>>
  {
    unsafe {
      let dest = self.into();
      let src = src.into();
      let mut message = mem::uninitialized();

      let ret = linker::LLVMLinkModules(dest, src,
      	                                linker::LLVMLinkerMode::LLVMLinkerPreserveSource,
      	                                &mut message);
      if ret == 1 {
        Err(CBox::new(message))
      } else {
        Ok(())
      }
    }
  }

  /// Link a module into this module, returning an error string if an error occurs.
  ///
  /// This *does* destroy the source module.
  pub fn link_destroy(&self, src: CSemiBox<Module>) -> Result<(), CBox<str>>
  {
    unsafe {
      let dest = self.into();
      let src = src.as_ptr();
      let mut message = mem::uninitialized();

      let ret = linker::LLVMLinkModules(dest, src,
      	                                linker::LLVMLinkerMode::LLVMLinkerDestroySource,
      	                                &mut message);
      if ret == 1 {
        Err(CBox::new(message))
      } else {
        Ok(())
      }
    }
  }

  /// Dump the module to stderr (for debugging).
  pub fn dump(&self)
  {
  	unsafe { core::LLVMDumpModule(self.into()); }
  }
}

get_context!(Module, LLVMGetModuleContext);
impl_display!(Module, LLVMPrintModuleToString);
dispose!(Module, LLVMModule, core::LLVMDisposeModule);

impl<'a> IntoIterator for &'a Module
{
  type Item = &'a Function;
  type IntoIter = ValueIter<'a, &'a Function>;
  /// Iterate through the functions in the module
  fn into_iter(self) -> ValueIter<'a, &'a Function>
  {
 		ValueIter::new(
 			unsafe { core::LLVMGetFirstFunction(self.into()) },
 			core::LLVMGetNextFunction
 		)
  }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub enum AddressSpace
{
  Generic = 0,
  Global = 1,
  Shared = 3,
  Const = 4,
  Local = 5,
}<commit_msg>Add some comments.<commit_after>use std::env;
use std::ffi::CString;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::io::{Error, ErrorKind};
use std::io::Result as IoResult;
use std::iter::{Iterator, IntoIterator};
use std::path::Path;
use std::process::Command;

use cbox::{CBox, CSemiBox};
use ffi::analysis::LLVMVerifierFailureAction;
use ffi::{analysis, core, linker, LLVMModule};
use ffi::bit_writer as writer;
use ffi::bit_reader as reader;
use ffi::ir_reader as ir_reader;
use ffi::prelude::{LLVMValueRef, LLVMModuleRef};
use ffi::transforms::pass_manager_builder as builder;
use libc::{c_char, c_uint};

use buffer::MemoryBuffer;
use context::{Context, GetContext};
use util;
use ty::Type;
use value::{Function, GlobalValue, Value, ValueIter};

/// Represents a single compilation unit of code.
///
/// This is attached to the lifetime of the context that constructs it, but is owned by the `CSemiBox`.
pub struct Module;
native_ref!(&Module = LLVMModuleRef);
impl Module
{
  /// Create a new module in the context given with the name given.
  ///
  /// The lifetime of the module will match the lifetime of the context
  /// you instance it in because the context contains it.
  ///
  /// ```rust
  /// use llvm::*;
  /// let context = Context::new();
  /// let context = context.as_semi();
  /// let module = Module::new("name", &context);
  /// println!("{:?}", module)
  /// ```
  pub fn new<'a>(name: &str, context: &'a Context) -> CSemiBox<'a, Module>
  {
    let c_name = CString::new(name).unwrap();
    unsafe {
    	CSemiBox::new(core::LLVMModuleCreateWithNameInContext(c_name.as_ptr(), context.into()))
    }
  }

  /// Add an external global to the module with the given type and name.
  pub fn add_global<'a>(&'a self, name: &str, ty: &'a Type) -> &'a GlobalValue {
    util::with_cstr(name, |ptr| unsafe {
        core::LLVMAddGlobal(self.into(), ty.into(), ptr).into()
    })
  }

  /// Add a global in the given address space to the module with the given type and name.
  pub fn add_global_in_addr_space<'a>(&'a self,
  	                                  name: &str,
  	                                  ty: &'a Type,
  	                                  sp: AddressSpace) -> &'a GlobalValue
  {
    util::with_cstr(name, |ptr| unsafe {
      core::LLVMAddGlobalInAddressSpace(self.into(), ty.into(), ptr, sp as c_uint).into()
    })
  }

  /// Add a constant global to the module with the given type, name and value.
  pub fn add_global_constant<'a>(&'a self, name: &str, val: &'a Value) -> &'a GlobalValue
  {
    util::with_cstr(name, |ptr| unsafe {
      let global = core::LLVMAddGlobal(self.into(), val.get_type().into(), ptr);
      core::LLVMSetInitializer (global.into(), val.into());
      global.into()
    })
  }

  /// Get the global with the name given, or `None` if no global with that name exists.
  pub fn get_global<'a>(&'a self, name: &str) -> Option<&'a GlobalValue>
  {
    util::with_cstr(name, |ptr| unsafe {
        let ptr = core::LLVMGetNamedGlobal(self.into(), ptr);
        util::ptr_to_null(ptr)
    })
  }

  /// Get an iterator of global values
  pub fn global_values<'a>(&'a self) -> ValueIter<&'a GlobalValue>
  {
  	ValueIter::new(
 			unsafe { core::LLVMGetFirstGlobal(self.into()) },
 			core::LLVMGetNextGlobal
 		)
  }

  /// Parse this LLVM IR into a module, or return an error string
  pub fn parse_ir<'a>(context: &'a Context, path: &str) -> Result<CSemiBox<'a, Module>, CBox<str>>
  {
  	unsafe {
      let mut out = mem::uninitialized();
      let mut err = mem::uninitialized();
      let buf = try!(MemoryBuffer::new_from_file(path));

      let ret = ir_reader::LLVMParseIRInContext(context.into(), buf.as_ptr(), &mut out, &mut err);
      if ret == 1 {
      	Err(CBox::new(err))
      } else {
        Ok(CSemiBox::new(out))
      }
    }
  }

  /// Parse this bitcode file into a module, or return an error string.
  pub fn parse_bitcode<'a>(context: &'a Context, path: &str) -> Result<CSemiBox<'a, Module>, CBox<str>> {
    unsafe {
      let mut out = mem::uninitialized();
      let mut err = mem::uninitialized();
      let buf = try!(MemoryBuffer::new_from_file(path));

      let ret = reader::LLVMParseBitcodeInContext(context.into(),
      																					  buf.as_ptr(),
      	                                          &mut out,
      	                                          &mut err);
      if ret == 1 {
          Err(CBox::new(err))
      } else {
          Ok(CSemiBox::new(out))
      }
    }
  }
  /// Write this module's bitcode to the path given.
  pub fn write_bitcode(&self, path: &str) -> IoResult<()>
  {
     util::with_cstr(path, |cpath| unsafe {
       if writer::LLVMWriteBitcodeToFile(self.into(), cpath) != 0 {
           Err(Error::new(ErrorKind::Other, &format!("could not write to {}", path) as &str))
       } else {
           Ok(())
       }
     })
  }
  /// Add a function to the module with the name given.
  pub fn add_function<'a>(&'a self, name: &str, sig: &'a Type) -> &'a Function
  {
    let c_name = CString::new(name).unwrap();
    unsafe { core::LLVMAddFunction(self.into(), c_name.as_ptr(), sig.into()) }.into()
  }

  /// Returns the function with the name given, or `None` if no function with that name exists.
  pub fn get_function<'a>(&'a self, name: &str) -> Option<&'a Function>
  {
    let c_name = CString::new(name).unwrap();
    unsafe {
      let ty = core::LLVMGetNamedFunction(self.into(), c_name.as_ptr());
      util::ptr_to_null(ty)
    }
  }

  /// Returns the type with the name given, or `None`` if no type with that name exists.
  pub fn get_type<'a>(&'a self, name: &str) -> Option<&'a Type>
  {
    let c_name = CString::new(name).unwrap();
    unsafe {
      let ty = core::LLVMGetTypeByName(self.into(), c_name.as_ptr());
      util::ptr_to_null(ty)
    }
  }

  /// Clone this module.
  pub fn clone<'a>(&'a self) -> CSemiBox<'a, Module>
  {
    CSemiBox::new(unsafe { core::LLVMCloneModule(self.into()) })
  }

  /// Optimize this module with the given optimization level and size level.
  ///
  /// This runs passes depending on the levels given.
  pub fn optimize(&self, opt_level: usize, size_level: usize) {
    unsafe {
      let builder = builder::LLVMPassManagerBuilderCreate();
      builder::LLVMPassManagerBuilderSetOptLevel(builder, opt_level as c_uint);
      builder::LLVMPassManagerBuilderSetSizeLevel(builder, size_level as c_uint);
      let pass_manager = core::LLVMCreatePassManager();
      builder::LLVMPassManagerBuilderPopulateModulePassManager(builder, pass_manager);
      builder::LLVMPassManagerBuilderDispose(builder);
      core::LLVMRunPassManager(pass_manager, self.into());
    }
  }

  /// Returns the target data of this module represented as a string
  pub fn get_target(&self) -> &str
  {
    unsafe {
      let target = core::LLVMGetTarget(self.into());
      util::to_str(target as *mut c_char)
    }
  }

  pub fn get_data_layout(&self) -> &str
  {
  	unsafe {
  		let layout = core::LLVMGetDataLayout(self.into());
  		util::to_str(layout as *mut c_char)
  	}
  }

  /// Set the target data of this module to the target data string given.
  pub fn set_target(&self, target: &str)
  {
      let c_target = CString::new(target).unwrap();
      unsafe { core::LLVMSetTarget(self.into(), c_target.as_ptr()) }
  }

  /// Verify that the module is safe to run, returning a string detailing the error
  /// when an error occurs.
  pub fn verify(&self) -> Result<(), CBox<str>>
  {
    unsafe {
      let mut error = mem::uninitialized();
      let action = LLVMVerifierFailureAction::LLVMReturnStatusAction;
      if analysis::LLVMVerifyModule(self.into(), action, &mut error) == 1 {
          Err(CBox::new(error))
      } else {
          Ok(())
      }
    }
  }

  /// Compile the module into an object file at the given location.
  ///
  /// Note that this uses the LLVM tool `llc` to do this, which may or may not be
  /// installed on the user's machine.
  pub fn compile(&self, path: &Path, opt_level: usize) -> IoResult<()>
  {
    let dir = env::temp_dir();
    let path = path.to_str().unwrap();
    let mod_path = dir.join("module.bc");
    let mod_path = mod_path.to_str().unwrap();
    try!(self.write_bitcode(mod_path));
    Command::new("llc")
      .arg(&format!("-O={}", opt_level))
      .arg("-filetype=obj")
      .arg("-o").arg(path)
      .arg(mod_path)
      .spawn()
      .map(|_| ())
  }

  /// Link a module into this module, returning an error string if an error occurs.
  ///
  /// This *does not* destroy the source module.
  pub fn link(&self, src: &Module) -> Result<(), CBox<str>>
  {
    unsafe {
      let dest = self.into();
      let src = src.into();
      let mut message = mem::uninitialized();

      let ret = linker::LLVMLinkModules(dest, src,
      	                                linker::LLVMLinkerMode::LLVMLinkerPreserveSource,
      	                                &mut message);
      if ret == 1 {
        Err(CBox::new(message))
      } else {
        Ok(())
      }
    }
  }

  /// Link a module into this module, returning an error string if an error occurs.
  ///
  /// This *does* destroy the source module.
  pub fn link_destroy(&self, src: CSemiBox<Module>) -> Result<(), CBox<str>>
  {
    unsafe {
      let dest = self.into();
      let src = src.as_ptr();
      let mut message = mem::uninitialized();

      let ret = linker::LLVMLinkModules(dest, src,
      	                                linker::LLVMLinkerMode::LLVMLinkerDestroySource,
      	                                &mut message);
      if ret == 1 {
        Err(CBox::new(message))
      } else {
        Ok(())
      }
    }
  }

  /// Dump the module to stderr (for debugging).
  pub fn dump(&self)
  {
  	unsafe { core::LLVMDumpModule(self.into()); }
  }
}

get_context!(Module, LLVMGetModuleContext);
impl_display!(Module, LLVMPrintModuleToString);
dispose!(Module, LLVMModule, core::LLVMDisposeModule);

impl<'a> IntoIterator for &'a Module
{
  type Item = &'a Function;
  type IntoIter = ValueIter<'a, &'a Function>;
  /// Iterate through the functions in the module
  fn into_iter(self) -> ValueIter<'a, &'a Function>
  {
 		ValueIter::new(
 			unsafe { core::LLVMGetFirstFunction(self.into()) },
 			core::LLVMGetNextFunction
 		)
  }
}

#[repr(C)]
#[derive(Copy, Clone)]
pub enum AddressSpace
{
  Generic = 0,
  Global = 1,
  Shared = 3,
  Const = 4,
  Local = 5,
}<|endoftext|>


<commit_before>use super::connection::Connection;
use super::error::Error;
use super::interface::{ChildrenList, Interfaces};
use super::message::Message;

pub struct Object {
    path: String,

    interfaces: Interfaces,
}

impl Object {
    pub fn new(path: &str, interfaces: Interfaces, children: ChildrenList) -> Result<Self, Error> {
        Ok(Object {
            path: path.to_owned(),
            interfaces: try!(interfaces.finalize(children)),
        })
    }

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

    pub fn handle_message(&mut self, conn: &Connection, msg: &mut Message) -> Option<Result<(), ()>> {
        self.interfaces.handle(conn, msg)
    }
}
<commit_msg>object: only a plain ref needed to handle messages<commit_after>use super::connection::Connection;
use super::error::Error;
use super::interface::{ChildrenList, Interfaces};
use super::message::Message;

pub struct Object {
    path: String,

    interfaces: Interfaces,
}

impl Object {
    pub fn new(path: &str, interfaces: Interfaces, children: ChildrenList) -> Result<Self, Error> {
        Ok(Object {
            path: path.to_owned(),
            interfaces: try!(interfaces.finalize(children)),
        })
    }

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

    pub fn handle_message(&self, conn: &Connection, msg: &mut Message) -> Option<Result<(), ()>> {
        self.interfaces.handle(conn, msg)
    }
}
<|endoftext|>


<commit_before>#![cfg(target_os = "windows")]

pub mod ffi {
   #![allow(non_snake_case)]

   use std::mem;

   pub use libc::{
      c_char, c_int, c_uint, c_void
   };
   pub use libc::types::os::arch::extra::{
      WORD, DWORD, BYTE, BOOL, HANDLE
   };
   pub use libc::consts::os::extra::{
      TRUE
   };
   pub use os::win::ffi::{
      HDC
   };

   pub type HGLRC = HANDLE;

   pub const PFD_TYPE_RGBA:          BYTE = 0;

   pub const PFD_MAIN_PLANE:         BYTE = 0;

   pub const PFD_DOUBLEBUFFER:      DWORD = 0x00000001;
   pub const PFD_DRAW_TO_WINDOW:    DWORD = 0x00000004;
   pub const PFD_SUPPORT_OPENGL:    DWORD = 0x00000020;

   #[repr(C)]
   #[derive(Copy)]
   pub struct PIXELFORMATDESCRIPTOR {
      pub nSize: WORD,
      pub nVersion: WORD,
      pub dwFlags: DWORD,
      pub iPixelType: BYTE,
      pub cColorBits: BYTE,
      pub cRedBits: BYTE,
      pub cRedShift: BYTE,
      pub cGreenBits: BYTE,
      pub cGreenShift: BYTE,
      pub cBlueBits: BYTE,
      pub cBlueShift: BYTE,
      pub cAlphaBits: BYTE,
      pub cAlphaShift: BYTE,
      pub cAccumBits: BYTE,
      pub cAccumRedBits: BYTE,
      pub cAccumGreenBits: BYTE,
      pub cAccumBlueBits: BYTE,
      pub cAccumAlphaBits: BYTE,
      pub cDepthBits: BYTE,
      pub cStencilBits: BYTE,
      pub cAuxBuffers: BYTE,
      pub iLayerType: BYTE,
      pub bReserved: BYTE,
      pub dwLayerMask: DWORD,
      pub dwVisibleMask: DWORD,
      pub dwDamageMask: DWORD,
   }
   impl Clone for PIXELFORMATDESCRIPTOR {
      fn clone(&self) -> Self { *self }
   }
   impl Default for PIXELFORMATDESCRIPTOR {
      fn default() -> Self { unsafe { mem::zeroed() } }
   }

   #[link(name="gdi32")]
   extern "C" {
      pub fn ChoosePixelFormat(hdc: HDC, ppfd: *const PIXELFORMATDESCRIPTOR) -> c_int;

      pub fn SetPixelFormat(hdc: HDC, iPixelFormat: c_int, ppfd: *const PIXELFORMATDESCRIPTOR) -> BOOL;

      pub fn SwapBuffers(rc: HDC) -> BOOL;
   }

   #[link(name="opengl32")]
   extern "C" {
      pub fn wglChoosePixelFormat(hdc: HDC, ppfd: *const PIXELFORMATDESCRIPTOR) -> c_int;

      pub fn wglSetPixelFormat(hdc: HDC, iPixelFormat: c_int, ppfd: *const PIXELFORMATDESCRIPTOR) -> BOOL;

      pub fn wglCreateContext(hdc: HDC) -> HGLRC;

      pub fn wglMakeCurrent(hdc: HDC, rc: HGLRC) -> BOOL;

      pub fn wglDeleteContext(rc: HGLRC) -> BOOL;

      pub fn wglGetCurrentContext() -> HGLRC;

      pub fn wglSwapBuffers(rc: HDC) -> BOOL;

      pub fn wglGetProcAddress(name: *const c_char) -> *const c_void;
   }
}

use std::io;
use std::mem;
use std::ptr;
use std::ffi::CString;

use error::{RuntimeError, ErrorKind};
use super::utils::fn_ptr::{FnPtrLoader, FnPtr};

pub fn init_pixel_format(
   hdc: ffi::HDC,
) -> Result<(), RuntimeError> {
   let pfd = ffi::PIXELFORMATDESCRIPTOR {
      nSize: mem::size_of::<ffi::PIXELFORMATDESCRIPTOR>() as ffi::WORD,
      nVersion: 1,
      dwFlags: ffi::PFD_DRAW_TO_WINDOW | ffi::PFD_SUPPORT_OPENGL | ffi::PFD_DOUBLEBUFFER,
      iPixelType: ffi::PFD_TYPE_RGBA,
      cColorBits: 24,
      cRedBits: 0, cRedShift: 0, cGreenBits: 0, cGreenShift: 0, cBlueBits: 0, cBlueShift: 0,
      cAlphaBits: 0, cAlphaShift: 0, cAccumBits: 0,
      cAccumRedBits: 0, cAccumGreenBits: 0, cAccumBlueBits: 0, cAccumAlphaBits: 0,
      cDepthBits: 0,
      cStencilBits: 0,
      cAuxBuffers: 0,
      iLayerType: ffi::PFD_MAIN_PLANE,
      bReserved: 0,
      dwLayerMask: 0, dwVisibleMask: 0, dwDamageMask: 0
   };

   let pixel_format = unsafe { ffi::ChoosePixelFormat(hdc, &pfd) };

   if pixel_format == 0 {
      return Err(RuntimeError::new(
         ErrorKind::WGL,
         "Choosing pixel format failed".to_string()
      ));
   }

   println!("PIXEL FORMAT: {:?}", pixel_format);

   let result = unsafe { ffi::SetPixelFormat(hdc, pixel_format, &pfd) };

   if result != ffi::TRUE {
      return Err(RuntimeError::new(
         ErrorKind::WGL,
         "Setting pixel format failed".to_string()
      ));
   }

   Ok(())
}

pub struct Context {
   pub rc: ffi::HGLRC
}

impl Context {
   pub fn create(hdc: ffi::HDC) -> Result<Self, RuntimeError> {
      let rc = unsafe { ffi::wglCreateContext(hdc) };

      if rc == ptr::null_mut() {
         return Err(RuntimeError::new(
            ErrorKind::WGL,
            format!("Create WGL context failed: {}", io::Error::last_os_error())
         ));
      }

      let result = unsafe { ffi::wglMakeCurrent(hdc, rc) };

      if result != ffi::TRUE {
         return Err(RuntimeError::new(
            ErrorKind::WGL,
            "wglMakeCurrent failed".to_string()
         ));
      }

      Ok(Context {
         rc: rc,
      })
   }

   pub fn current() -> Result<Self, RuntimeError> {
      let rc = unsafe { ffi::wglGetCurrentContext() };

      if rc == ptr::null_mut() {
         return Err(RuntimeError::new(
            ErrorKind::WGL,
            "Getting current WGL context failed".to_string()
         ));
      }

      Ok(Context {
         rc: rc,
      })
   }
}

impl Drop for Context {
   fn drop (&mut self) {
      unsafe {
         ffi::wglDeleteContext(self.rc);
      }
   }
}

pub fn swap_buffers(hdc: ffi::HDC) {
   unsafe { ffi::SwapBuffers(hdc) };
}

pub struct Loader;

impl Loader {
   pub fn new() -> Self {
      Loader
   }
}

impl FnPtrLoader for Loader {
   fn get_proc_addr(&self, name: &str) -> FnPtr {
      let cname = CString::new(name).unwrap().as_ptr();

      let addr = unsafe {
         ffi::wglGetProcAddress(cname)
      };
      println!("{}: {:?}", name, addr);

      addr
   }
}
<commit_msg>Adding a call to DescribePixelFormat and cleaning up WGL defs<commit_after>#![cfg(target_os = "windows")]

pub mod ffi {
   #![allow(non_snake_case)]

   use std::mem;

   pub use libc::{
      c_char, c_int, c_uint, c_void
   };
   pub use libc::types::os::arch::extra::{
      WORD, DWORD, BYTE, BOOL, HANDLE
   };
   pub use libc::consts::os::extra::{
      TRUE
   };
   pub use os::win::ffi::{
      HDC
   };

   pub type HGLRC = HANDLE;

   pub const PFD_TYPE_RGBA:          BYTE = 0;

   pub const PFD_MAIN_PLANE:         BYTE = 0;

   pub const PFD_DOUBLEBUFFER:      DWORD = 0x00000001;
   pub const PFD_DRAW_TO_WINDOW:    DWORD = 0x00000004;
   pub const PFD_SUPPORT_OPENGL:    DWORD = 0x00000020;

   #[repr(C)]
   #[derive(Copy)]
   pub struct PIXELFORMATDESCRIPTOR {
      pub nSize: WORD,
      pub nVersion: WORD,
      pub dwFlags: DWORD,
      pub iPixelType: BYTE,
      pub cColorBits: BYTE,
      pub cRedBits: BYTE,
      pub cRedShift: BYTE,
      pub cGreenBits: BYTE,
      pub cGreenShift: BYTE,
      pub cBlueBits: BYTE,
      pub cBlueShift: BYTE,
      pub cAlphaBits: BYTE,
      pub cAlphaShift: BYTE,
      pub cAccumBits: BYTE,
      pub cAccumRedBits: BYTE,
      pub cAccumGreenBits: BYTE,
      pub cAccumBlueBits: BYTE,
      pub cAccumAlphaBits: BYTE,
      pub cDepthBits: BYTE,
      pub cStencilBits: BYTE,
      pub cAuxBuffers: BYTE,
      pub iLayerType: BYTE,
      pub bReserved: BYTE,
      pub dwLayerMask: DWORD,
      pub dwVisibleMask: DWORD,
      pub dwDamageMask: DWORD,
   }
   impl Clone for PIXELFORMATDESCRIPTOR {
      fn clone(&self) -> Self { *self }
   }
   impl Default for PIXELFORMATDESCRIPTOR {
      fn default() -> Self { unsafe { mem::zeroed() } }
   }

   #[link(name="gdi32")]
   extern "C" {
      pub fn ChoosePixelFormat(hdc: HDC, ppfd: *const PIXELFORMATDESCRIPTOR) -> c_int;

      pub fn DescribePixelFormat(hdc: HDC, iPixelFormat: c_int, nBytes: c_uint, ppfd: *mut PIXELFORMATDESCRIPTOR) -> c_int;

      pub fn SetPixelFormat(hdc: HDC, iPixelFormat: c_int, ppfd: *const PIXELFORMATDESCRIPTOR) -> BOOL;

      pub fn SwapBuffers(rc: HDC) -> BOOL;
   }

   #[link(name="opengl32")]
   extern "C" {
      pub fn wglCreateContext(hdc: HDC) -> HGLRC;

      pub fn wglMakeCurrent(hdc: HDC, rc: HGLRC) -> BOOL;

      pub fn wglDeleteContext(rc: HGLRC) -> BOOL;

      pub fn wglGetCurrentContext() -> HGLRC;

      pub fn wglGetProcAddress(name: *const c_char) -> *const c_void;
   }
}

use std::io;
use std::mem;
use std::ptr;
use std::ffi::CString;

use error::{RuntimeError, ErrorKind};
use super::utils::fn_ptr::{FnPtrLoader, FnPtr};

pub fn init_pixel_format(
   hdc: ffi::HDC,
) -> Result<(), RuntimeError> {
   let mut pfd = ffi::PIXELFORMATDESCRIPTOR {
      nSize: mem::size_of::<ffi::PIXELFORMATDESCRIPTOR>() as ffi::WORD,
      nVersion: 1,
      dwFlags: ffi::PFD_DRAW_TO_WINDOW | ffi::PFD_SUPPORT_OPENGL | ffi::PFD_DOUBLEBUFFER,
      iPixelType: ffi::PFD_TYPE_RGBA,
      cColorBits: 24,
      cRedBits: 0, cRedShift: 0, cGreenBits: 0, cGreenShift: 0, cBlueBits: 0, cBlueShift: 0,
      cAlphaBits: 0, cAlphaShift: 0, cAccumBits: 0,
      cAccumRedBits: 0, cAccumGreenBits: 0, cAccumBlueBits: 0, cAccumAlphaBits: 0,
      cDepthBits: 0,
      cStencilBits: 0,
      cAuxBuffers: 0,
      iLayerType: ffi::PFD_MAIN_PLANE,
      bReserved: 0,
      dwLayerMask: 0, dwVisibleMask: 0, dwDamageMask: 0
   };

   let pixel_format = unsafe { ffi::ChoosePixelFormat(hdc, &pfd) };

   if pixel_format == 0 {
      return Err(RuntimeError::new(
         ErrorKind::WGL,
         "Choosing pixel format failed".to_string()
      ));
   }

   println!("PIXEL FORMAT: {:?}", pixel_format);

   unsafe { ffi::DescribePixelFormat(hdc, pixel_format, mem::size_of::<ffi::PIXELFORMATDESCRIPTOR>() as ffi::c_uint, &mut pfd) };

   let result = unsafe { ffi::SetPixelFormat(hdc, pixel_format, &pfd) };

   if result != ffi::TRUE {
      return Err(RuntimeError::new(
         ErrorKind::WGL,
         "Setting pixel format failed".to_string()
      ));
   }

   Ok(())
}

pub struct Context {
   pub rc: ffi::HGLRC
}

impl Context {
   pub fn create(hdc: ffi::HDC) -> Result<Self, RuntimeError> {
      let rc = unsafe { ffi::wglCreateContext(hdc) };

      if rc == ptr::null_mut() {
         return Err(RuntimeError::new(
            ErrorKind::WGL,
            format!("Create WGL context failed: {}", io::Error::last_os_error())
         ));
      }

      let result = unsafe { ffi::wglMakeCurrent(hdc, rc) };

      if result != ffi::TRUE {
         return Err(RuntimeError::new(
            ErrorKind::WGL,
            "wglMakeCurrent failed".to_string()
         ));
      }

      Ok(Context {
         rc: rc,
      })
   }

   pub fn current() -> Result<Self, RuntimeError> {
      let rc = unsafe { ffi::wglGetCurrentContext() };

      if rc == ptr::null_mut() {
         return Err(RuntimeError::new(
            ErrorKind::WGL,
            "Getting current WGL context failed".to_string()
         ));
      }

      Ok(Context {
         rc: rc,
      })
   }
}

impl Drop for Context {
   fn drop (&mut self) {
      unsafe {
         ffi::wglDeleteContext(self.rc);
      }
   }
}

pub fn swap_buffers(hdc: ffi::HDC) {
   unsafe { ffi::SwapBuffers(hdc) };
}

pub struct Loader;

impl Loader {
   pub fn new() -> Self {
      Loader
   }
}

impl FnPtrLoader for Loader {
   fn get_proc_addr(&self, name: &str) -> FnPtr {
      let cname = CString::new(name).unwrap().as_ptr();

      let addr = unsafe {
         ffi::wglGetProcAddress(cname)
      };
      println!("{}: {:?}", name, addr);

      addr
   }
}
<|endoftext|>


<commit_before>use syntax::parse::parser::Parser;
use syntax::parse::token;

use block::{Block, Describe, It};

pub fn parse(parser: &mut Parser) -> Describe {
    parse_describe("sup", parser)
}

pub fn parse_describe(name: &str, parser: &mut Parser) -> Describe {
    let brace = token::CloseDelim(token::Brace);

    let mut before = None;
    let mut after = None;
    let mut blocks = vec![];

    loop {
        if parser.token == brace || parser.token == token::Eof {
            break
        }

        let span = parser.span;
        let ident = parser.parse_ident();

        match ident.as_str() {
            "describe" => {
                let (name, _) = parser.parse_str();
                parser.expect(&token::OpenDelim(token::Brace));
                blocks.push(Block::Describe(parse_describe(name.get(), parser)))
            },

            "it" => {
                let (name, _) = parser.parse_str();
                let block = parser.parse_block();

                blocks.push(Block::It(It {
                    name: name.get().to_string(),
                    block: block
                }))
            },

            "before" => {
                before = Some(parser.parse_block());
            },

            "after" => {
                after = Some(parser.parse_block());
            },

            otherwise => {
                let message = format!("Expected `it`, found `{}`", otherwise);
                parser.span_fatal(span, message.as_slice())
            }
        }
    }

    Describe {
        name: name.to_string(),
        before: before,
        after: after,
        blocks: blocks
    }
}
<commit_msg>Fix a parsing error message.<commit_after>use syntax::parse::parser::Parser;
use syntax::parse::token;

use block::{Block, Describe, It};

pub fn parse(parser: &mut Parser) -> Describe {
    parse_describe("sup", parser)
}

pub fn parse_describe(name: &str, parser: &mut Parser) -> Describe {
    let brace = token::CloseDelim(token::Brace);

    let mut before = None;
    let mut after = None;
    let mut blocks = vec![];

    loop {
        if parser.token == brace || parser.token == token::Eof {
            break
        }

        let span = parser.span;
        let ident = parser.parse_ident();

        match ident.as_str() {
            "describe" => {
                let (name, _) = parser.parse_str();
                parser.expect(&token::OpenDelim(token::Brace));
                blocks.push(Block::Describe(parse_describe(name.get(), parser)))
            },

            "it" => {
                let (name, _) = parser.parse_str();
                let block = parser.parse_block();

                blocks.push(Block::It(It {
                    name: name.get().to_string(),
                    block: block
                }))
            },

            "before" => {
                before = Some(parser.parse_block());
            },

            "after" => {
                after = Some(parser.parse_block());
            },

            otherwise => {
                let message = format!("Expected \
`describe`, `before`, `after`, or `it`, found `{}`", otherwise);
                parser.span_fatal(span, message.as_slice())
            }
        }
    }

    Describe {
        name: name.to_string(),
        before: before,
        after: after,
        blocks: blocks
    }
}
<|endoftext|>


<commit_before>use syntax::ast;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::ptr::P;

use block::{Block, Describe, It, Bench};

pub fn parse(parser: &mut Parser) -> Describe {
    parse_describe("sup", parser)
}

pub fn parse_describe(name: &str, parser: &mut Parser) -> Describe {
    let brace = token::CloseDelim(token::Brace);

    let mut before = vec![];
    let mut after = vec![];
    let mut blocks = vec![];

    loop {
        if parser.token == brace || parser.token == token::Eof {
            break
        }

        let span = parser.span;
        let ident = parser.parse_ident().unwrap();

        match ident.as_str() {
            "describe" | "context" => {
                let (name, _) = parser.parse_str().unwrap();
                parser.expect(&token::OpenDelim(token::Brace)).unwrap();
                let block = Block::Describe(parse_describe(&name, parser));
                parser.expect(&token::CloseDelim(token::Brace)).unwrap();
                blocks.push(block);
            },

            "it" | "test" => {
                let (name, _) = parser.parse_str().unwrap();
                let block = parse_block(parser);

                blocks.push(Block::It(It {
                    name: name.to_string(),
                    block: block
                }))
            },

            "bench" => {
                let (name, _) = parser.parse_str().unwrap();
                parser.expect(&token::BinOp(token::Or)).unwrap();
                let ident = parser.parse_ident().unwrap();
                parser.expect(&token::BinOp(token::Or)).unwrap();
                let block = parse_block(parser);

                blocks.push(Block::Bench(Bench {
                    name: name.to_string(),
                    ident: ident,
                    block: block
                }))
            },

            "before" => {
                before.push(parse_block(parser));
            },

            "after" => {
                after.push(parse_block(parser));
            },

            otherwise => {
                let message = format!("Expected \
`describe`, `context`, `before`, `after`, or `it`, found `{}`", otherwise);
                panic!("{}", parser.span_fatal(span, &message))
            }
        }
    }

    Describe {
        name: name.to_string(),
        before: before,
        after: after,
        blocks: blocks
    }
}

fn parse_block(parser: &mut Parser) -> P<ast::Block> {
    let span = parser.span;
    let block = parser.parse_block().unwrap();
    if block.expr.is_some() {
        panic!("{}", parser.span_fatal(
            span,
            "last expression in this block must be terminated by `;`"))
    }
    block
}
<commit_msg>Fix a parser error message.<commit_after>use syntax::ast;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::ptr::P;

use block::{Block, Describe, It, Bench};

pub fn parse(parser: &mut Parser) -> Describe {
    parse_describe("sup", parser)
}

pub fn parse_describe(name: &str, parser: &mut Parser) -> Describe {
    let brace = token::CloseDelim(token::Brace);

    let mut before = vec![];
    let mut after = vec![];
    let mut blocks = vec![];

    loop {
        if parser.token == brace || parser.token == token::Eof {
            break
        }

        let span = parser.span;
        let ident = parser.parse_ident().unwrap();

        match ident.as_str() {
            "describe" | "context" => {
                let (name, _) = parser.parse_str().unwrap();
                parser.expect(&token::OpenDelim(token::Brace)).unwrap();
                let block = Block::Describe(parse_describe(&name, parser));
                parser.expect(&token::CloseDelim(token::Brace)).unwrap();
                blocks.push(block);
            },

            "it" | "test" => {
                let (name, _) = parser.parse_str().unwrap();
                let block = parse_block(parser);

                blocks.push(Block::It(It {
                    name: name.to_string(),
                    block: block
                }))
            },

            "bench" => {
                let (name, _) = parser.parse_str().unwrap();
                parser.expect(&token::BinOp(token::Or)).unwrap();
                let ident = parser.parse_ident().unwrap();
                parser.expect(&token::BinOp(token::Or)).unwrap();
                let block = parse_block(parser);

                blocks.push(Block::Bench(Bench {
                    name: name.to_string(),
                    ident: ident,
                    block: block
                }))
            },

            "before" => {
                before.push(parse_block(parser));
            },

            "after" => {
                after.push(parse_block(parser));
            },

            otherwise => {
                let message = format!("Expected `describe`, `context`, \
`before`, `after`, `it`, `test`, or `bench`, found `{}`", otherwise);
                panic!("{}", parser.span_fatal(span, &message))
            }
        }
    }

    Describe {
        name: name.to_string(),
        before: before,
        after: after,
        blocks: blocks
    }
}

fn parse_block(parser: &mut Parser) -> P<ast::Block> {
    let span = parser.span;
    let block = parser.parse_block().unwrap();
    if block.expr.is_some() {
        panic!("{}", parser.span_fatal(
            span,
            "last expression in this block must be terminated by `;`"))
    }
    block
}
<|endoftext|>


<commit_before>//! AWS Regions and helper functions.
//!
//! Mostly used for translating the Region enum to a string AWS accepts.
//!
//! For example: `UsEast1` to "us-east-1"

use std::str::FromStr;
use std::fmt::{Display, Error as FmtError, Formatter};

/// An AWS region.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Region {
    ApNortheast1,
    ApSoutheast1,
    ApSoutheast2,
    EuCentral1,
    EuWest1,
    SaEast1,
    UsEast1,
    UsWest1,
    UsWest2,
}

/// An error produced when attempting to convert a `str` into a `Region` fails.
#[derive(Debug,PartialEq)]
pub struct ParseRegionError;

impl Display for Region {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        let region_str = match *self {
            Region::ApNortheast1 => "ap-northeast-1",
            Region::ApSoutheast1 => "ap-southeast-1",
            Region::ApSoutheast2 => "ap-southeast-2",
            Region::EuCentral1 => "eu-central-1",
            Region::EuWest1 => "eu-west-1",
            Region::SaEast1 => "sa-east-1",
            Region::UsEast1 => "us-east-1",
            Region::UsWest1 => "us-west-1",
            Region::UsWest2 => "us-west-2",
        };

        write!(f, "{}", region_str)
    }
}

impl FromStr for Region {
    type Err = ParseRegionError;

    fn from_str(s: &str) -> Result<Region, ParseRegionError> {
        match s {
            "ap-northeast-1" => Ok(Region::ApNortheast1),
            "ap-southeast-1" => Ok(Region::ApSoutheast1),
            "ap-southeast-2" => Ok(Region::ApSoutheast2),
            "eu-central-1" => Ok(Region::EuCentral1),
            "eu-west-1" => Ok(Region::EuWest1),
            "sa-east-1" => Ok(Region::SaEast1),
            "us-east-1" => Ok(Region::UsEast1),
            "us-west-1" => Ok(Region::UsWest1),
            "us-west-2" => Ok(Region::UsWest2),
            _ => Err(ParseRegionError)
        }
    }
}

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

    #[test]
    fn from_str() {
        assert_eq!(<Region as FromStr>::from_str("not an AWS region"), Err(ParseRegionError));
        assert_eq!(FromStr::from_str("ap-northeast-1"), Ok(Region::ApNortheast1));
        assert_eq!(FromStr::from_str("ap-southeast-1"), Ok(Region::ApSoutheast1));
        assert_eq!(FromStr::from_str("ap-southeast-2"), Ok(Region::ApSoutheast2));
        assert_eq!(FromStr::from_str("eu-central-1"), Ok(Region::EuCentral1));
        assert_eq!(FromStr::from_str("eu-west-1"), Ok(Region::EuWest1));
        assert_eq!(FromStr::from_str("sa-east-1"), Ok(Region::SaEast1));
        assert_eq!(FromStr::from_str("us-east-1"), Ok(Region::UsEast1));
        assert_eq!(FromStr::from_str("us-west-1"), Ok(Region::UsWest1));
        assert_eq!(FromStr::from_str("us-west-2"), Ok(Region::UsWest2));
    }

    #[test]
    fn region_display() {
        assert_eq!(Region::ApNortheast1.to_string(), "ap-northeast-1".to_owned());
        assert_eq!(Region::ApSoutheast1.to_string(), "ap-southeast-1".to_owned());
        assert_eq!(Region::ApSoutheast2.to_string(), "ap-southeast-2".to_owned());
        assert_eq!(Region::EuCentral1.to_string(), "eu-central-1".to_owned());
        assert_eq!(Region::EuWest1.to_string(), "eu-west-1".to_owned());
        assert_eq!(Region::SaEast1.to_string(), "sa-east-1".to_owned());
        assert_eq!(Region::UsEast1.to_string(), "us-east-1".to_owned());
        assert_eq!(Region::UsWest1.to_string(), "us-west-1".to_owned());
        assert_eq!(Region::UsWest2.to_string(), "us-west-2".to_owned());
    }
}
<commit_msg>Make ParseRegionError more useful.<commit_after>//! AWS Regions and helper functions.
//!
//! Mostly used for translating the Region enum to a string AWS accepts.
//!
//! For example: `UsEast1` to "us-east-1"

use std::error::Error;
use std::str::FromStr;
use std::fmt::{Display, Error as FmtError, Formatter};

/// An AWS region.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Region {
    ApNortheast1,
    ApSoutheast1,
    ApSoutheast2,
    EuCentral1,
    EuWest1,
    SaEast1,
    UsEast1,
    UsWest1,
    UsWest2,
}

/// An error produced when attempting to convert a `str` into a `Region` fails.
#[derive(Debug,PartialEq)]
pub struct ParseRegionError {
    message: String,
}

impl Display for Region {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        let region_str = match *self {
            Region::ApNortheast1 => "ap-northeast-1",
            Region::ApSoutheast1 => "ap-southeast-1",
            Region::ApSoutheast2 => "ap-southeast-2",
            Region::EuCentral1 => "eu-central-1",
            Region::EuWest1 => "eu-west-1",
            Region::SaEast1 => "sa-east-1",
            Region::UsEast1 => "us-east-1",
            Region::UsWest1 => "us-west-1",
            Region::UsWest2 => "us-west-2",
        };

        write!(f, "{}", region_str)
    }
}

impl FromStr for Region {
    type Err = ParseRegionError;

    fn from_str(s: &str) -> Result<Region, ParseRegionError> {
        match s {
            "ap-northeast-1" => Ok(Region::ApNortheast1),
            "ap-southeast-1" => Ok(Region::ApSoutheast1),
            "ap-southeast-2" => Ok(Region::ApSoutheast2),
            "eu-central-1" => Ok(Region::EuCentral1),
            "eu-west-1" => Ok(Region::EuWest1),
            "sa-east-1" => Ok(Region::SaEast1),
            "us-east-1" => Ok(Region::UsEast1),
            "us-west-1" => Ok(Region::UsWest1),
            "us-west-2" => Ok(Region::UsWest2),
            s => Err(ParseRegionError::new(s))
        }
    }
}

impl ParseRegionError {
    pub fn new(input: &str) -> Self {
        ParseRegionError {
            message: format!("Not a valid AWS region: {}", input)
        }
    }
}

impl Error for ParseRegionError {
    fn description(&self) -> &str {
        &self.message
    }
}

impl Display for ParseRegionError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
        write!(f, "{}", self.message)
    }
}

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

    #[test]
    fn from_str() {
        assert_eq!(
            "foo".parse::<Region>().err().expect(
                "Parsing foo as a Region was not an error"
            ).to_string(),
            "Not a valid AWS region: foo".to_owned()
        );
        assert_eq!("ap-northeast-1".parse(), Ok(Region::ApNortheast1));
        assert_eq!("ap-southeast-1".parse(), Ok(Region::ApSoutheast1));
        assert_eq!("ap-southeast-2".parse(), Ok(Region::ApSoutheast2));
        assert_eq!("eu-central-1".parse(), Ok(Region::EuCentral1));
        assert_eq!("eu-west-1".parse(), Ok(Region::EuWest1));
        assert_eq!("sa-east-1".parse(), Ok(Region::SaEast1));
        assert_eq!("us-east-1".parse(), Ok(Region::UsEast1));
        assert_eq!("us-west-1".parse(), Ok(Region::UsWest1));
        assert_eq!("us-west-2".parse(), Ok(Region::UsWest2));
    }

    #[test]
    fn region_display() {
        assert_eq!(Region::ApNortheast1.to_string(), "ap-northeast-1".to_owned());
        assert_eq!(Region::ApSoutheast1.to_string(), "ap-southeast-1".to_owned());
        assert_eq!(Region::ApSoutheast2.to_string(), "ap-southeast-2".to_owned());
        assert_eq!(Region::EuCentral1.to_string(), "eu-central-1".to_owned());
        assert_eq!(Region::EuWest1.to_string(), "eu-west-1".to_owned());
        assert_eq!(Region::SaEast1.to_string(), "sa-east-1".to_owned());
        assert_eq!(Region::UsEast1.to_string(), "us-east-1".to_owned());
        assert_eq!(Region::UsWest1.to_string(), "us-west-1".to_owned());
        assert_eq!(Region::UsWest2.to_string(), "us-west-2".to_owned());
    }
}
<|endoftext|>


<commit_before>use ammonia::{Builder, UrlRelative};
use comrak;
use std::borrow::Cow;
use url::Url;

use util::CargoResult;

/// Context for markdown to HTML rendering.
#[allow(missing_debug_implementations)]
pub struct MarkdownRenderer<'a> {
    html_sanitizer: Builder<'a>,
}

impl<'a> MarkdownRenderer<'a> {
    /// Creates a new renderer instance.
    ///
    /// Per `markdown_to_html`, `base_url` is the base URL prepended to any
    /// relative links in the input document.  See that function for more detail.
    fn new(base_url: Option<&'a str>) -> MarkdownRenderer<'a> {
        let tags = [
            "a",
            "b",
            "blockquote",
            "br",
            "code",
            "dd",
            "del",
            "dl",
            "dt",
            "em",
            "h1",
            "h2",
            "h3",
            "hr",
            "i",
            "img",
            "input",
            "kbd",
            "li",
            "ol",
            "p",
            "pre",
            "s",
            "strike",
            "strong",
            "sub",
            "sup",
            "table",
            "tbody",
            "td",
            "th",
            "thead",
            "tr",
            "ul",
            "hr",
            "span",
        ].iter()
            .cloned()
            .collect();
        let tag_attributes = [
            ("a", ["href", "target"].iter().cloned().collect()),
            (
                "img",
                ["width", "height", "src", "alt", "align"]
                    .iter()
                    .cloned()
                    .collect(),
            ),
            (
                "input",
                ["checked", "disabled", "type"].iter().cloned().collect(),
            ),
        ].iter()
            .cloned()
            .collect();
        let allowed_classes = [
            (
                "code",
                [
                    "language-bash",
                    "language-clike",
                    "language-glsl",
                    "language-go",
                    "language-ini",
                    "language-javascript",
                    "language-json",
                    "language-markup",
                    "language-protobuf",
                    "language-ruby",
                    "language-rust",
                    "language-scss",
                    "language-sql",
                    "yaml",
                ].iter()
                    .cloned()
                    .collect(),
            ),
        ].iter()
            .cloned()
            .collect();

        let sanitizer_base_url = base_url.map(|s| s.to_string());

        fn constrain_closure<F>(f: F) -> F
        where
            F: for<'a> Fn(&'a str) -> Option<Cow<'a, str>> + Send + Sync,
        {
            f
        }

        let relative_url_sanitizer = constrain_closure(move |url| {
            let mut new_url = sanitizer_base_url.clone().unwrap();
            if !new_url.ends_with('/') {
                new_url.push('/');
            }
            new_url += "blob/master";
            if !url.starts_with('/') {
                new_url.push('/');
            }
            new_url += url;
            Some(Cow::Owned(new_url))
        });

        let use_relative = if let Some(base_url) = base_url {
            if let Ok(url) = Url::parse(base_url) {
                url.host_str() == Some("github.com") || url.host_str() == Some("gitlab.com")
                    || url.host_str() == Some("bitbucket.org")
            } else {
                false
            }
        } else {
            false
        };

        let mut html_sanitizer = Builder::new();
        html_sanitizer
            .link_rel(Some("nofollow noopener noreferrer"))
            .tags(tags)
            .tag_attributes(tag_attributes)
            .allowed_classes(allowed_classes)
            .url_relative(if use_relative {
                UrlRelative::Custom(Box::new(relative_url_sanitizer))
            } else {
                UrlRelative::Deny
            });

        MarkdownRenderer {
            html_sanitizer: html_sanitizer,
        }
    }

    /// Renders the given markdown to HTML using the current settings.
    fn to_html(&self, text: &str) -> CargoResult<String> {
        let options = comrak::ComrakOptions {
            ext_autolink: true,
            ext_strikethrough: true,
            ext_table: true,
            ext_tagfilter: true,
            ext_tasklist: true,
            ..comrak::ComrakOptions::default()
        };
        let rendered = comrak::markdown_to_html(text, &options);
        Ok(self.html_sanitizer.clean(&rendered).to_string())
    }
}

/// Renders a markdown text to sanitized HTML.
///
/// The returned text should not contain any harmful HTML tag or attribute (such as iframe,
/// onclick, onmouseover, etc.).
///
/// The `base_url` parameter will be used as the base for any relative links found in the
/// Markdown, as long as its host part is github.com, gitlab.com, or bitbucket.org.  The
/// supplied URL will be used as a directory base whether or not the relative link is
/// prefixed with '/'.  If `None` is passed, relative links will be omitted.
///
/// # Examples
///
/// ```
/// use render::markdown_to_html;
///
/// let text = "[Rust](https://rust-lang.org/) is an awesome *systems programming* language!";
/// let rendered = markdown_to_html(text, None)?;
/// ```
pub fn markdown_to_html(text: &str, base_url: Option<&str>) -> CargoResult<String> {
    let renderer = MarkdownRenderer::new(base_url);
    renderer.to_html(text)
}

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

    #[test]
    fn empty_text() {
        let text = "";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(result, "");
    }

    #[test]
    fn text_with_script_tag() {
        let text = "foo_readme\n\n";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(
            result,
            "
foo_readme
\n<script>alert(\'Hello World\')</script>\n"
        );
    }

    #[test]
    fn text_with_iframe_tag() {
        let text = "foo_readme\n\nalert('Hello World')";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(
            result,
            "
foo_readme
\n<iframe>alert(\'Hello World\')</iframe>\n"
        );
    }

    #[test]
    fn text_with_unknown_tag() {
        let text = "foo_readme\n\n<unknown>alert('Hello World')</unknown>";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(result, "
foo_readme
\n
alert(\'Hello World\')
\n");
    }

    #[test]
    fn text_with_inline_javascript() {
        let text = r#"foo_readme\n\nCrate page"#;
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(
            result,
            "
foo_readme\\n\\nCrate page
\n"
        );
    }

    // See https://github.com/kivikakk/comrak/issues/37. This panic happened
    // in comrak 0.1.8 but was fixed in 0.1.9.
    #[test]
    fn text_with_fancy_single_quotes() {
        let text = r#"wb’"#;
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(result, "
wb’
\n");
    }

    #[test]
    fn code_block_with_syntax_highlighting() {
        let code_block = r#"```rust \
                            println!("Hello World"); \
                           ```"#;
        let result = markdown_to_html(code_block, None).unwrap();
        assert!(result.contains(""));
    }

    #[test]
    fn text_with_forbidden_class_attribute() {
        let text = "
Hello World!
";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(result, "
Hello World!
\n");
    }

    #[test]
    fn relative_links() {
        let absolute = "[hi](/hi)";
        let relative = "[there](there)";

        for url in &[
            "https://github.com/rust-lang/test",
            "https://github.com/rust-lang/test/",
        ] {
            let result = markdown_to_html(absolute, Some(url)).unwrap();
            assert_eq!(
                result,
                "
hi
\n"
            );

            let result = markdown_to_html(relative, Some(url)).unwrap();
            assert_eq!(
                result,
                "
there
\n"
            );
        }

        let result = markdown_to_html(absolute, Some("https://google.com/")).unwrap();
        assert_eq!(
            result,
            "
hi
\n"
        );
    }
}
<commit_msg>include gitlab/bitbucket in tests<commit_after>use ammonia::{Builder, UrlRelative};
use comrak;
use std::borrow::Cow;
use url::Url;

use util::CargoResult;

/// Context for markdown to HTML rendering.
#[allow(missing_debug_implementations)]
pub struct MarkdownRenderer<'a> {
    html_sanitizer: Builder<'a>,
}

impl<'a> MarkdownRenderer<'a> {
    /// Creates a new renderer instance.
    ///
    /// Per `markdown_to_html`, `base_url` is the base URL prepended to any
    /// relative links in the input document.  See that function for more detail.
    fn new(base_url: Option<&'a str>) -> MarkdownRenderer<'a> {
        let tags = [
            "a",
            "b",
            "blockquote",
            "br",
            "code",
            "dd",
            "del",
            "dl",
            "dt",
            "em",
            "h1",
            "h2",
            "h3",
            "hr",
            "i",
            "img",
            "input",
            "kbd",
            "li",
            "ol",
            "p",
            "pre",
            "s",
            "strike",
            "strong",
            "sub",
            "sup",
            "table",
            "tbody",
            "td",
            "th",
            "thead",
            "tr",
            "ul",
            "hr",
            "span",
        ].iter()
            .cloned()
            .collect();
        let tag_attributes = [
            ("a", ["href", "target"].iter().cloned().collect()),
            (
                "img",
                ["width", "height", "src", "alt", "align"]
                    .iter()
                    .cloned()
                    .collect(),
            ),
            (
                "input",
                ["checked", "disabled", "type"].iter().cloned().collect(),
            ),
        ].iter()
            .cloned()
            .collect();
        let allowed_classes = [
            (
                "code",
                [
                    "language-bash",
                    "language-clike",
                    "language-glsl",
                    "language-go",
                    "language-ini",
                    "language-javascript",
                    "language-json",
                    "language-markup",
                    "language-protobuf",
                    "language-ruby",
                    "language-rust",
                    "language-scss",
                    "language-sql",
                    "yaml",
                ].iter()
                    .cloned()
                    .collect(),
            ),
        ].iter()
            .cloned()
            .collect();

        let sanitizer_base_url = base_url.map(|s| s.to_string());

        fn constrain_closure<F>(f: F) -> F
        where
            F: for<'a> Fn(&'a str) -> Option<Cow<'a, str>> + Send + Sync,
        {
            f
        }

        let relative_url_sanitizer = constrain_closure(move |url| {
            let mut new_url = sanitizer_base_url.clone().unwrap();
            if !new_url.ends_with('/') {
                new_url.push('/');
            }
            new_url += "blob/master";
            if !url.starts_with('/') {
                new_url.push('/');
            }
            new_url += url;
            Some(Cow::Owned(new_url))
        });

        let use_relative = if let Some(base_url) = base_url {
            if let Ok(url) = Url::parse(base_url) {
                url.host_str() == Some("github.com") || url.host_str() == Some("gitlab.com")
                    || url.host_str() == Some("bitbucket.org")
            } else {
                false
            }
        } else {
            false
        };

        let mut html_sanitizer = Builder::new();
        html_sanitizer
            .link_rel(Some("nofollow noopener noreferrer"))
            .tags(tags)
            .tag_attributes(tag_attributes)
            .allowed_classes(allowed_classes)
            .url_relative(if use_relative {
                UrlRelative::Custom(Box::new(relative_url_sanitizer))
            } else {
                UrlRelative::Deny
            });

        MarkdownRenderer {
            html_sanitizer: html_sanitizer,
        }
    }

    /// Renders the given markdown to HTML using the current settings.
    fn to_html(&self, text: &str) -> CargoResult<String> {
        let options = comrak::ComrakOptions {
            ext_autolink: true,
            ext_strikethrough: true,
            ext_table: true,
            ext_tagfilter: true,
            ext_tasklist: true,
            ..comrak::ComrakOptions::default()
        };
        let rendered = comrak::markdown_to_html(text, &options);
        Ok(self.html_sanitizer.clean(&rendered).to_string())
    }
}

/// Renders a markdown text to sanitized HTML.
///
/// The returned text should not contain any harmful HTML tag or attribute (such as iframe,
/// onclick, onmouseover, etc.).
///
/// The `base_url` parameter will be used as the base for any relative links found in the
/// Markdown, as long as its host part is github.com, gitlab.com, or bitbucket.org.  The
/// supplied URL will be used as a directory base whether or not the relative link is
/// prefixed with '/'.  If `None` is passed, relative links will be omitted.
///
/// # Examples
///
/// ```
/// use render::markdown_to_html;
///
/// let text = "[Rust](https://rust-lang.org/) is an awesome *systems programming* language!";
/// let rendered = markdown_to_html(text, None)?;
/// ```
pub fn markdown_to_html(text: &str, base_url: Option<&str>) -> CargoResult<String> {
    let renderer = MarkdownRenderer::new(base_url);
    renderer.to_html(text)
}

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

    #[test]
    fn empty_text() {
        let text = "";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(result, "");
    }

    #[test]
    fn text_with_script_tag() {
        let text = "foo_readme\n\n";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(
            result,
            "
foo_readme
\n<script>alert(\'Hello World\')</script>\n"
        );
    }

    #[test]
    fn text_with_iframe_tag() {
        let text = "foo_readme\n\nalert('Hello World')";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(
            result,
            "
foo_readme
\n<iframe>alert(\'Hello World\')</iframe>\n"
        );
    }

    #[test]
    fn text_with_unknown_tag() {
        let text = "foo_readme\n\n<unknown>alert('Hello World')</unknown>";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(result, "
foo_readme
\n
alert(\'Hello World\')
\n");
    }

    #[test]
    fn text_with_inline_javascript() {
        let text = r#"foo_readme\n\nCrate page"#;
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(
            result,
            "
foo_readme\\n\\nCrate page
\n"
        );
    }

    // See https://github.com/kivikakk/comrak/issues/37. This panic happened
    // in comrak 0.1.8 but was fixed in 0.1.9.
    #[test]
    fn text_with_fancy_single_quotes() {
        let text = r#"wb’"#;
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(result, "
wb’
\n");
    }

    #[test]
    fn code_block_with_syntax_highlighting() {
        let code_block = r#"```rust \
                            println!("Hello World"); \
                           ```"#;
        let result = markdown_to_html(code_block, None).unwrap();
        assert!(result.contains(""));
    }

    #[test]
    fn text_with_forbidden_class_attribute() {
        let text = "
Hello World!
";
        let result = markdown_to_html(text, None).unwrap();
        assert_eq!(result, "
Hello World!
\n");
    }

    #[test]
    fn relative_links() {
        let absolute = "[hi](/hi)";
        let relative = "[there](there)";

        for host in &["github.com", "gitlab.com", "bitbucket.org"] {
            for &extra_slash in &[true, false] {
                let url = format!(
                    "https://{}/rust-lang/test{}",
                    host,
                    if extra_slash { "/" } else { "" }
                );

                let result = markdown_to_html(absolute, Some(&url)).unwrap();
                assert_eq!(
                    result,
                    format!(
                        "
hi
\n",
                        host
                    )
                );

                let result = markdown_to_html(relative, Some(&url)).unwrap();
                assert_eq!(
                    result,
                    format!(
                        "
there
\n",
                        host
                    )
                );
            }
        }

        let result = markdown_to_html(absolute, Some("https://google.com/")).unwrap();
        assert_eq!(
            result,
            "
hi
\n"
        );
    }
}
<|endoftext|>


<commit_before>use std;
use std::cmp;
use std::io::stdout;
use std::io::Write;
use std::thread;
use std::time;

use termion;
use termion::clear;
use termion::cursor;
use termion::input::MouseTerminal;
use termion::raw::IntoRawMode;
use termion::raw::RawTerminal;

use core::Core;
use update::Update;
use view::View;

pub struct Screen {
    pub stdout: MouseTerminal<RawTerminal<std::io::Stdout>>,
    pub size: (u16, u16),
}

impl Screen {
    pub fn new() -> Screen {
        let mut stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap());
        write!(stdout, "{}", clear::All).unwrap();
        stdout.flush().unwrap();
        Screen {
            size: termion::terminal_size().unwrap(),
            stdout: stdout,
        }
    }

    pub fn draw(&mut self, view: &View) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();

        let range = 0..(cmp::min(view.lines.len(), self.size.1 as usize));
        for (lineno, line) in range.zip(view.lines.iter()) {
            write!(self.stdout, "{}", line.text.clone().unwrap()).unwrap();
            self.scroll(0, lineno as u64);
        }
    }

    pub fn scroll(&mut self, col: u64, line: u64) {
        write!(self.stdout, "{}", cursor::Goto((col + 1) as u16, (line + 1) as u16)).unwrap();
        self.stdout.flush().unwrap();
    }

    pub fn init(&mut self) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        self.stdout.flush().unwrap();
    }

    pub fn update(&mut self, core: &mut Core) {
        // TODO(#27): check if terminal size changed. If so, send a `render_line` command to the backend,
        // and a `scroll` command for future updates.
        if let Ok(msg) = core.update_rx.try_recv() {
            let msg_list = msg.as_array().unwrap();
            let (method, params) = (msg_list[0].as_str().unwrap(),
                                    msg_list[1].as_object().unwrap());
            if method == "update" {
                let update = Update::from_value(params.get("update").unwrap());
                core.update(&update);

                let view = core.view();
                self.draw(&view);
            } else if method == "scroll_to" {
                let (col, line) = (params.get("col").unwrap().as_u64().unwrap(),
                                   params.get("line").unwrap().as_u64().unwrap());
                self.scroll(col, line);
            } else if method == "set_style" {
                // TODO(#26): ???
            } else {
                info!("Unknown request from backend {:?}", method);
            }
        } else {
            thread::sleep(time::Duration::from_millis(10));
        }
    }
}
<commit_msg>Cleans up length comment<commit_after>use std;
use std::cmp;
use std::io::stdout;
use std::io::Write;
use std::thread;
use std::time;

use termion;
use termion::clear;
use termion::cursor;
use termion::input::MouseTerminal;
use termion::raw::IntoRawMode;
use termion::raw::RawTerminal;

use core::Core;
use update::Update;
use view::View;

pub struct Screen {
    pub stdout: MouseTerminal<RawTerminal<std::io::Stdout>>,
    pub size: (u16, u16),
}

impl Screen {
    pub fn new() -> Screen {
        let mut stdout = MouseTerminal::from(stdout().into_raw_mode().unwrap());
        write!(stdout, "{}", clear::All).unwrap();
        stdout.flush().unwrap();
        Screen {
            size: termion::terminal_size().unwrap(),
            stdout: stdout,
        }
    }

    pub fn draw(&mut self, view: &View) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();

        let range = 0..(cmp::min(view.lines.len(), self.size.1 as usize));
        for (lineno, line) in range.zip(view.lines.iter()) {
            write!(self.stdout, "{}", line.text.clone().unwrap()).unwrap();
            self.scroll(0, lineno as u64);
        }
    }

    pub fn scroll(&mut self, col: u64, line: u64) {
        write!(self.stdout, "{}", cursor::Goto((col + 1) as u16, (line + 1) as u16)).unwrap();
        self.stdout.flush().unwrap();
    }

    pub fn init(&mut self) {
        write!(self.stdout, "{}", termion::clear::All).unwrap();
        write!(self.stdout, "{}", cursor::Up(self.size.1)).unwrap();
        self.stdout.flush().unwrap();
    }

    pub fn update(&mut self, core: &mut Core) {
        // TODO(#27): check if terminal size changed. If so, send a `render_line` command to the
        // backend, and a `scroll` command for future updates.
        if let Ok(msg) = core.update_rx.try_recv() {
            let msg_list = msg.as_array().unwrap();
            let (method, params) = (msg_list[0].as_str().unwrap(),
                                    msg_list[1].as_object().unwrap());
            if method == "update" {
                let update = Update::from_value(params.get("update").unwrap());
                core.update(&update);

                let view = core.view();
                self.draw(&view);
            } else if method == "scroll_to" {
                let (col, line) = (params.get("col").unwrap().as_u64().unwrap(),
                                   params.get("line").unwrap().as_u64().unwrap());
                self.scroll(col, line);
            } else if method == "set_style" {
                // TODO(#26): ???
            } else {
                info!("Unknown request from backend {:?}", method);
            }
        } else {
            thread::sleep(time::Duration::from_millis(10));
        }
    }
}
<|endoftext|>


<commit_before>use self::super::{Github, Result};
use rep::{SearchIssuesOptions, SearchResult, SearchIssuesItem};
use serde::Deserialize;
use std::fmt;
use url::form_urlencoded;

/// Sort directions for pull requests
#[derive(Debug, PartialEq)]
pub enum SearchIssuesSort {
    /// Sort by time created
    Created,
    /// Sort by last updated
    Updated,
    /// Sort by number of comments
    Comments,
}

impl fmt::Display for SearchIssuesSort {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   SearchIssuesSort::Comments => "comments",
                   SearchIssuesSort::Created => "created",
                   SearchIssuesSort::Updated => "updated",
               })
    }
}

// https://developer.github.com/v3/search/#search-issues
pub struct Search<'a> {
    github: &'a Github<'a>,
}

impl<'a> Search<'a> {
    pub fn new(github: &'a Github<'a>) -> Search<'a> {
        Search { github: github }
    }

    pub fn issues(&self) -> SearchIssues {
        SearchIssues::new(&self)
    }

    fn search<D: Deserialize>(&self, url: &str) -> Result<SearchResult<D>> {
        self.github.get::<SearchResult<D>>(url)
    }
}

// https://developer.github.com/v3/search/#search-issues
pub struct SearchIssues<'a> {
    search: &'a Search<'a>,
}

impl<'a> SearchIssues<'a> {
    pub fn new(search: &'a Search<'a>) -> SearchIssues<'a> {
        SearchIssues { search: search }
    }

    pub fn list<Q>(&self,
                   q: Q,
                   options: &SearchIssuesOptions)
                   -> Result<SearchResult<SearchIssuesItem>>
        where Q: Into<String>
    {
        let mut uri = vec!["/search/issues".to_string()];
        let query_options = options.serialize().unwrap_or(String::new());
        let query =
            form_urlencoded::Serializer::new(query_options).append_pair("q", &q.into()).finish();
        uri.push(query);
        self.search.search::<SearchIssuesItem>(&uri.join("?"))
    }
}
<commit_msg>impl  iter for search issues<commit_after>use self::super::{Github, Result, Iter};
use rep::{SearchIssuesOptions, SearchResult, SearchIssuesItem};
use serde::Deserialize;
use std::fmt;
use url::form_urlencoded;

/// Sort directions for pull requests
#[derive(Debug, PartialEq)]
pub enum SearchIssuesSort {
    /// Sort by time created
    Created,
    /// Sort by last updated
    Updated,
    /// Sort by number of comments
    Comments,
}

impl fmt::Display for SearchIssuesSort {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "{}",
               match *self {
                   SearchIssuesSort::Comments => "comments",
                   SearchIssuesSort::Created => "created",
                   SearchIssuesSort::Updated => "updated",
               })
    }
}

// https://developer.github.com/v3/search/#search-issues
pub struct Search<'a> {
    github: &'a Github<'a>,
}

fn items<D: Deserialize>(result: SearchResult<D>) -> Vec<D> {
    result.items
}

impl<'a> Search<'a> {
    pub fn new(github: &'a Github<'a>) -> Search<'a> {
        Search { github: github }
    }

    pub fn issues(&self) -> SearchIssues {
        SearchIssues::new(&self)
    }

    fn iter<D: Deserialize>(&'a self, url: &str) -> Result<Iter<'a, SearchResult<D>, D>> {
        self.github.iter(url.to_owned(), items)
    }

    fn search<D: Deserialize>(&self, url: &str) -> Result<SearchResult<D>> {
        self.github.get::<SearchResult<D>>(url)
    }
}

// https://developer.github.com/v3/search/#search-issues
pub struct SearchIssues<'a> {
    search: &'a Search<'a>,
}

impl<'a> SearchIssues<'a> {
    pub fn new(search: &'a Search<'a>) -> SearchIssues<'a> {
        SearchIssues { search: search }
    }

    pub fn iter<Q>(&'a self,
                   q: Q,
                   options: &SearchIssuesOptions)
                   -> Result<Iter<'a, SearchResult<SearchIssuesItem>, SearchIssuesItem>>
        where Q: Into<String>
    {
        let mut uri = vec!["/search/issues".to_string()];
        let query_options = options.serialize().unwrap_or(String::new());
        let query =
            form_urlencoded::Serializer::new(query_options).append_pair("q", &q.into()).finish();
        uri.push(query);
        self.search.iter::<SearchIssuesItem>(&uri.join("?"))
    }

    pub fn list<Q>(&self,
                   q: Q,
                   options: &SearchIssuesOptions)
                   -> Result<SearchResult<SearchIssuesItem>>
        where Q: Into<String>
    {
        let mut uri = vec!["/search/issues".to_string()];
        let query_options = options.serialize().unwrap_or(String::new());
        let query =
            form_urlencoded::Serializer::new(query_options).append_pair("q", &q.into()).finish();
        uri.push(query);
        self.search.search::<SearchIssuesItem>(&uri.join("?"))
    }
}
<|endoftext|>