<commit_before>use super::{Height, Width};
use std::os::windows::io::RawHandle;

/// Returns the size of the terminal defaulting to STDOUT, if available.
///
/// Note that this returns the size of the actual command window, and
/// not the overall size of the command window buffer
pub fn terminal_size() -> Option<(Width, Height)> {
    use winapi::um::processenv::GetStdHandle;
    use winapi::um::winbase::STD_OUTPUT_HANDLE;

    let handle = unsafe { GetStdHandle(STD_OUTPUT_HANDLE) as RawHandle };

    terminal_size_using_handle(handle)
}

/// Returns the size of the terminal using the given handle, if available.
///
/// If the given handle is not a tty, returns `None`
pub fn terminal_size_using_handle(handle: RawHandle) -> Option<(Width, Height)> {
    use winapi::um::handleapi::INVALID_HANDLE_VALUE;
    use winapi::um::wincon::{
        GetConsoleScreenBufferInfo, CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT,
    };

    // convert between winapi::um::winnt::HANDLE and std::os::windows::raw::HANDLE
    let hand = unsafe { std::mem::transmute(handle) };

    if hand == INVALID_HANDLE_VALUE {
        return None;
    }

    let zc = COORD { X: 0, Y: 0 };
    let mut csbi = CONSOLE_SCREEN_BUFFER_INFO {
        dwSize: zc,
        dwCursorPosition: zc,
        wAttributes: 0,
        srWindow: SMALL_RECT {
            Left: 0,
            Top: 0,
            Right: 0,
            Bottom: 0,
        },
        dwMaximumWindowSize: zc,
    };
    if unsafe { GetConsoleScreenBufferInfo(hand, &mut csbi) } == 0 {
        return None;
    }

    let w: Width = Width((csbi.srWindow.Right - csbi.srWindow.Left + 1) as u16);
    let h: Height = Height((csbi.srWindow.Bottom - csbi.srWindow.Top + 1) as u16);
    Some((w, h))
}
<commit_msg>Apply suggestions from code review<commit_after>use super::{Height, Width};
use std::os::windows::io::RawHandle;

/// Returns the size of the terminal defaulting to STDOUT, if available.
///
/// Note that this returns the size of the actual command window, and
/// not the overall size of the command window buffer
pub fn terminal_size() -> Option<(Width, Height)> {
    use winapi::um::processenv::GetStdHandle;
    use winapi::um::winbase::STD_OUTPUT_HANDLE;

    let handle = unsafe { GetStdHandle(STD_OUTPUT_HANDLE) as RawHandle };

    terminal_size_using_handle(handle)
}

/// Returns the size of the terminal using the given handle, if available.
///
/// If the given handle is not a tty, returns `None`
pub fn terminal_size_using_handle(handle: RawHandle) -> Option<(Width, Height)> {
    use winapi::um::handleapi::INVALID_HANDLE_VALUE;
    use winapi::um::wincon::{
        GetConsoleScreenBufferInfo, CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT,
    };

    // convert between winapi::um::winnt::HANDLE and std::os::windows::raw::HANDLE
    let hand = handle as winapi::um::winnt::HANDLE;

    if hand == INVALID_HANDLE_VALUE {
        return None;
    }

    let zc = COORD { X: 0, Y: 0 };
    let mut csbi = CONSOLE_SCREEN_BUFFER_INFO {
        dwSize: zc,
        dwCursorPosition: zc,
        wAttributes: 0,
        srWindow: SMALL_RECT {
            Left: 0,
            Top: 0,
            Right: 0,
            Bottom: 0,
        },
        dwMaximumWindowSize: zc,
    };
    if unsafe { GetConsoleScreenBufferInfo(hand, &mut csbi) } == 0 {
        return None;
    }

    let w: Width = Width((csbi.srWindow.Right - csbi.srWindow.Left + 1) as u16);
    let h: Height = Height((csbi.srWindow.Bottom - csbi.srWindow.Top + 1) as u16);
    Some((w, h))
}
<|endoftext|>


<commit_before>

struct CircularBuffer<T : Copy> {
  seqno : usize,
  data  : Vec<T>,
}

impl <T : Copy> CircularBuffer<T> {
  fn new(size : usize, default_value : T) -> CircularBuffer<T> {

    if size == 0 { panic!("size cannot be zero"); }

    let mut ret = CircularBuffer {
      seqno : 0,
      data  : vec![],
    };

    // make sure there is enough place and fill it with the
    // default value
    ret.data.resize(size, default_value);

    // hand over the object
    ret
  }

  fn put<F>(&mut self, setter: F) -> usize
    where F : Fn(&mut T)
  {
    // calculate where to put the data
    let pos = self.seqno % self.data.len();

    // get a reference to the data
    let mut opt : Option<&mut T> = self.data.get_mut(pos);

    // make sure the index worked
    match opt.as_mut() {
      Some(v) => setter(v),
      None    => { panic!("out of bounds {}", pos); }
    }

    // increase sequence number
    self.seqno = self.seqno + 1;
    self.seqno
  }

  fn get<F>(&mut self, from: &usize, to: &usize, getter: F) -> usize
    where F : Fn(&T)
  {
    if from > to { panic!("from:{} > to:{}", from, to); }

    // figure out the minimum and maximum position
    let min_pos : usize = if self.seqno < self.data.len() {
      0
    } else {
      (self.seqno - self.data.len()) as usize
    };

    let max_pos : usize = self.seqno;

    // cannot return past (overwritten) elements
    if *to < min_pos { return min_pos; }

    // cannot return future elements
    if *from >= max_pos { return max_pos; }

    // constrain start to min_pos
    let start : usize = if *from > min_pos {
      *from
    } else {
      min_pos
    };

    // constrain end to max_pos
    let end : usize = if *to > max_pos {
      max_pos
    } else {
      *to
    };

    let start_pos = start % self.data.len();
    let end_pos   = end % self.data.len();

    let get_range = |from_pos: usize, to_pos: usize| {
      for i in from_pos..to_pos {
        let act_value : Option<&T> = self.data.get(i);
        match act_value {
          Some(v) => { getter(v); }
          None => { panic!("index is out of range i={}",i); }
        };
      }
    };

    if end_pos > start_pos {
      // one contigous range
      get_range(start_pos, end_pos);
    } else {
      // range split into two
      get_range(start_pos, self.data.len());
      get_range(0, end_pos);
    }

    end
  }
}

pub fn tests() {
  let mut x = CircularBuffer::new(4, 0 as i32);
  x.put(|v| *v = 1);
  x.put(|v| *v = 2);
  x.put(|v| *v = 3);

  let ret = x.get( &0, &100, |val : &i32| {
    println!("A: {}",*val);
  });

  println!("A: ret={} {} {}",ret,x.seqno,x.data.len());

  x.put(|v| *v = 4);
  x.put(|v| *v = 5);
  x.put(|v| *v = 6);

  let ret2 = x.get( &ret, &100, |val : &i32| {
    println!("B: {}",*val);
  });

  println!("B: ret2={} {} {}",ret2,x.seqno,x.data.len());
}

#[test]
#[should_panic]
fn create_zero_sized() {
  let _x = CircularBuffer::new(0, 0 as i32);
}

#[test]
fn create_non_zero_sized() {
  let _x = CircularBuffer::new(1, 0 as i32);
}
<commit_msg>saving<commit_after>

struct CircularBuffer<T : Copy> {
  seqno : usize,
  data  : Vec<T>,
}

impl <T : Copy> CircularBuffer<T> {
  fn new(size : usize, default_value : T) -> CircularBuffer<T> {

    if size == 0 { panic!("size cannot be zero"); }

    let mut ret = CircularBuffer {
      seqno : 0,
      data  : vec![],
    };

    // make sure there is enough place and fill it with the
    // default value
    ret.data.resize(size, default_value);

    // hand over the object
    ret
  }

  fn put<F>(&mut self, setter: F) -> usize
    where F : Fn(&mut T)
  {
    // calculate where to put the data
    let pos = self.seqno % self.data.len();

    // get a reference to the data
    let mut opt : Option<&mut T> = self.data.get_mut(pos);

    // make sure the index worked
    match opt.as_mut() {
      Some(v) => setter(v),
      None    => { panic!("out of bounds {}", pos); }
    }

    // increase sequence number
    self.seqno = self.seqno + 1;
    self.seqno
  }

  fn get<F>(&self, from: &usize, to: &usize, mut getter: F) -> usize
    where F : Fn(&T)
  {
    if from > to { panic!("from:{} > to:{}", from, to); }

    // figure out the minimum and maximum position
    let min_pos : usize = if self.seqno < self.data.len() {
      0
    } else {
      (self.seqno - self.data.len()) as usize
    };

    let max_pos : usize = self.seqno;

    // cannot return past (overwritten) elements
    if *to < min_pos { return min_pos; }

    // cannot return future elements
    if *from >= max_pos { return max_pos; }

    // constrain start to min_pos
    let start : usize = if *from > min_pos {
      *from
    } else {
      min_pos
    };

    // constrain end to max_pos
    let end : usize = if *to > max_pos {
      max_pos
    } else {
      *to
    };

    let start_pos = start % self.data.len();
    let end_pos   = end % self.data.len();

    let get_range = |from_pos: usize, to_pos: usize| {
      for i in from_pos..to_pos {
        let act_value : Option<&T> = self.data.get(i);
        match act_value {
          Some(v) => { getter(v); }
          None => { panic!("index is out of range i={}",i); }
        };
      }
    };

    if end_pos > start_pos {
      // one contigous range
      get_range(start_pos, end_pos);
    } else {
      // range split into two
      get_range(start_pos, self.data.len());
      get_range(0, end_pos);
    }

    end
  }
}

pub fn tests() {
  let mut x = CircularBuffer::new(4, 0 as i32);
  x.put(|v| *v = 1);
  x.put(|v| *v = 2);
  x.put(|v| *v = 3);

  let ret = x.get( &0, &100, |val : &i32| {
    println!("A: {}",*val);
  });

  println!("A: ret={} {} {}",ret,x.seqno,x.data.len());

  x.put(|v| *v = 4);
  x.put(|v| *v = 5);
  x.put(|v| *v = 6);

  let ret2 = x.get( &ret, &100, |val : &i32| {
    println!("B: {}",*val);
  });

  println!("B: ret2={} {} {}",ret2,x.seqno,x.data.len());

  empty_buffer();
}

#[test]
#[should_panic]
fn create_zero_sized() {
  let _x = CircularBuffer::new(0, 0 as i32);
}

#[test]
fn create_non_zero_sized() {
  let _x = CircularBuffer::new(1, 0 as i32);
}

//#[test]
fn empty_buffer() {
  let x = CircularBuffer::new(1, 0 as i32);
  let mut n_elems = 0;
  let mut sum = 0;
  let max = x.seqno + 100;

  {
    let mut n_elems_ref = &n_elems;
    let mut sum_ref = ∑

    let expr = |v| {
      //*n_elems_ref = *n_elems_ref + 1;
      //*sum_ref = *sum_ref + v;
      println!("{:?}", v);
    };

    x.get(&0, &max, expr);
  }
  assert_eq!(n_elems, 0);
  assert_eq!(sum, 0);
}
<|endoftext|>


<commit_before>// Copyright (C) 2015-2017 Florian Wilkens
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial
// portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//! Wrapped FFI bindings to Linux-PAM
//!
//! This module provides wrapped versions of some of the functions from
//! the [`raw`](../raw/index.html) module which use the appropriate enums
//! instead of `c_int`. These wrappers should always be preferred as one
//! can safely match on their return types and prevent illegal arguments
//! from beeing passed to the native library.
//!
//! Note: These wrappers get added as I need them. Feel free to open an issue
//! or PR for the ones that you require which haven't been added yet.

use libc::{c_char, c_int, c_void};
use std::ffi::{CStr, CString};
use std::ptr::null;

use types::*;
use raw::*;

/* ------------------------ pam_appl.h -------------------------- */
#[inline]
pub fn start(service: &str,
             user: Option<&str>,
             conversation: &PamConversation,
             handle: *mut *mut PamHandle)
             -> PamReturnCode {
    if let Ok(service) = CString::new(service) {
        if let Some(usr) = user {
            if let Ok(user) = CString::new(usr) {
                unsafe {
                    From::from(pam_start(service.as_ptr(),
                                         user.as_ptr(),
                                         conversation,
                                         handle as *mut *const PamHandle))
                }
            } else {
                PamReturnCode::BUF_ERR
            }
        } else {
            unsafe {
                From::from(pam_start(service.as_ptr(),
                                     null(),
                                     conversation,
                                     handle as *mut *const PamHandle))
            }
        }
    } else {
        PamReturnCode::SERVICE_ERR
    }
}

#[inline]
pub fn end(handle: &mut PamHandle, status: PamReturnCode) -> PamReturnCode {
    From::from(unsafe { pam_end(handle, status as c_int) })
}

#[inline]
pub fn authenticate(handle: &mut PamHandle, flags: PamFlag) -> PamReturnCode {
    From::from(unsafe { pam_authenticate(handle, flags as c_int) })
}

#[inline]
pub fn setcred(handle: &mut PamHandle, flags: PamFlag) -> PamReturnCode {
    From::from(unsafe { pam_setcred(handle, flags as c_int) })
}

#[inline]
pub fn acct_mgmt(handle: &mut PamHandle, flags: PamFlag) -> PamReturnCode {
    From::from(unsafe { pam_acct_mgmt(handle, flags as c_int) })
}

#[inline]
pub fn open_session(handle: &mut PamHandle, flags: PamFlag) -> PamReturnCode {
    From::from(unsafe { pam_open_session(handle, flags as c_int) })
}

#[inline]
pub fn close_session(handle: &mut PamHandle, flags: PamFlag) -> PamReturnCode {
    From::from(unsafe { pam_close_session(handle, flags as c_int) })
}

#[inline]
pub fn chauthtok(handle: &mut PamHandle, flags: PamFlag) -> PamReturnCode {
    From::from(unsafe { pam_chauthtok(handle, flags as c_int) })
}
/* ------------------------ pam_appl.h -------------------------- */

/* ----------------------- _pam_types.h ------------------------- */
#[inline]
pub fn set_item(handle: &mut PamHandle, item_type: PamItemType, item: &c_void) -> PamReturnCode {
    From::from(unsafe { pam_set_item(handle, item_type as c_int, item) })
}

#[inline]
pub fn get_item(handle: &PamHandle,
                item_type: PamItemType,
                item: &mut *const c_void)
                -> PamReturnCode {
    From::from(unsafe { pam_get_item(handle, item_type as c_int, item) })
}

#[inline]
pub fn strerror(handle: &mut PamHandle, errnum: PamReturnCode) -> Option<&str> {
    unsafe { CStr::from_ptr(pam_strerror(handle, errnum as c_int)) }.to_str().ok()
}

#[inline]
pub fn putenv(handle: &mut PamHandle, name_value: &str) -> PamReturnCode {
    if let Ok(name_value) = CString::new(name_value) {
        From::from(unsafe { pam_putenv(handle, name_value.as_ptr()) })
    } else {
        // Not sure whether this is the correct return value
        PamReturnCode::BUF_ERR
    }
}

#[inline]
pub fn getenv<'a>(handle: &'a mut PamHandle, name: &str) -> Option<&'a str> {
    use std::ptr;
    if let Ok(name) = CString::new(name) {
		let env = unsafe{pam_getenv(handle, name.as_ptr())};
		if env != ptr::null(){
			unsafe { CStr::from_ptr(env) }.to_str().ok()
		}
		else{
			None
		}
	} else {
        None
    }
}

#[inline]
pub fn getenvlist(handle: &mut PamHandle) -> *const *const c_char {
    //TODO: find a convenient way to handle this with Rust types
    unsafe { pam_getenvlist(handle) }
}
/* ----------------------- _pam_types.h ------------------------- */

/* ----------------------- pam_misc.h --------------------------- */
#[inline]
#[cfg(target_os = "linux")]
pub fn misc_paste_env(handle: &mut PamHandle, user_env: &[&str]) -> PamReturnCode {
    // Taken from: https://github.com/rust-lang/rust/issues/9564#issuecomment-95354558
    let user_env: Vec<_> = user_env.iter()
        .map(|&env| CString::new(env).unwrap())
        .collect();
    let env_ptrs: Vec<_> = user_env.iter()
        .map(|env| env.as_ptr())
        .chain(Some(null()))
        .collect();
    From::from(unsafe { pam_misc_paste_env(handle, env_ptrs.as_ptr()) })
}

#[inline]
#[cfg(target_os = "linux")]
pub fn misc_drop_env(env: &mut *mut c_char) -> PamReturnCode {
    From::from(unsafe { pam_misc_drop_env(env) })
}

#[inline]
#[cfg(target_os = "linux")]
pub fn misc_setenv(handle: &mut PamHandle,
                   name: &str,
                   value: &str,
                   readonly: bool)
                   -> PamReturnCode {
    if let (Ok(name), Ok(value)) = (CString::new(name), CString::new(value)) {
        From::from(unsafe {
            pam_misc_setenv(handle,
                            name.as_ptr(),
                            value.as_ptr(),
                            if readonly { 0 } else { 1 })
        })
    } else {
        PamReturnCode::BUF_ERR
    }
}
/* ----------------------- pam_misc.h --------------------------- */

/* ----------------------- pam_modules.h ------------------------ */
#[inline]
pub fn set_data(handle: &mut PamHandle,
                module_data_name: &str,
                data: &mut c_void,
                cleanup: Option<extern "C" fn(*mut PamHandle, *mut c_void, c_int)>)
                -> PamReturnCode {
    if let Ok(module_data_name) = CString::new(module_data_name) {
        From::from(unsafe { pam_set_data(handle, module_data_name.as_ptr(), data, cleanup) })

    } else {
        PamReturnCode::BUF_ERR
    }
}

//pub fn get_data(handle: *const PamHandle, module_data_name: *const c_char, data: *const *const c_void);

pub fn get_user(handle: &PamHandle,
                user: &mut *const c_char,
                prompt: *const c_char)
                -> PamReturnCode {

    From::from(
        unsafe {
            pam_get_user(
                handle,
                user,
                prompt
            )
        }
    )
}

/* ----------------------- pam_modules.h ------------------------ */
<commit_msg>Changed Tab to spaces<commit_after>// Copyright (C) 2015-2017 Florian Wilkens
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial
// portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
// OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//! Wrapped FFI bindings to Linux-PAM
//!
//! This module provides wrapped versions of some of the functions from
//! the [`raw`](../raw/index.html) module which use the appropriate enums
//! instead of `c_int`. These wrappers should always be preferred as one
//! can safely match on their return types and prevent illegal arguments
//! from beeing passed to the native library.
//!
//! Note: These wrappers get added as I need them. Feel free to open an issue
//! or PR for the ones that you require which haven't been added yet.

use libc::{c_char, c_int, c_void};
use std::ffi::{CStr, CString};
use std::ptr::null;

use types::*;
use raw::*;

/* ------------------------ pam_appl.h -------------------------- */
#[inline]
pub fn start(service: &str,
             user: Option<&str>,
             conversation: &PamConversation,
             handle: *mut *mut PamHandle)
             -> PamReturnCode {
    if let Ok(service) = CString::new(service) {
        if let Some(usr) = user {
            if let Ok(user) = CString::new(usr) {
                unsafe {
                    From::from(pam_start(service.as_ptr(),
                                         user.as_ptr(),
                                         conversation,
                                         handle as *mut *const PamHandle))
                }
            } else {
                PamReturnCode::BUF_ERR
            }
        } else {
            unsafe {
                From::from(pam_start(service.as_ptr(),
                                     null(),
                                     conversation,
                                     handle as *mut *const PamHandle))
            }
        }
    } else {
        PamReturnCode::SERVICE_ERR
    }
}

#[inline]
pub fn end(handle: &mut PamHandle, status: PamReturnCode) -> PamReturnCode {
    From::from(unsafe { pam_end(handle, status as c_int) })
}

#[inline]
pub fn authenticate(handle: &mut PamHandle, flags: PamFlag) -> PamReturnCode {
    From::from(unsafe { pam_authenticate(handle, flags as c_int) })
}

#[inline]
pub fn setcred(handle: &mut PamHandle, flags: PamFlag) -> PamReturnCode {
    From::from(unsafe { pam_setcred(handle, flags as c_int) })
}

#[inline]
pub fn acct_mgmt(handle: &mut PamHandle, flags: PamFlag) -> PamReturnCode {
    From::from(unsafe { pam_acct_mgmt(handle, flags as c_int) })
}

#[inline]
pub fn open_session(handle: &mut PamHandle, flags: PamFlag) -> PamReturnCode {
    From::from(unsafe { pam_open_session(handle, flags as c_int) })
}

#[inline]
pub fn close_session(handle: &mut PamHandle, flags: PamFlag) -> PamReturnCode {
    From::from(unsafe { pam_close_session(handle, flags as c_int) })
}

#[inline]
pub fn chauthtok(handle: &mut PamHandle, flags: PamFlag) -> PamReturnCode {
    From::from(unsafe { pam_chauthtok(handle, flags as c_int) })
}
/* ------------------------ pam_appl.h -------------------------- */

/* ----------------------- _pam_types.h ------------------------- */
#[inline]
pub fn set_item(handle: &mut PamHandle, item_type: PamItemType, item: &c_void) -> PamReturnCode {
    From::from(unsafe { pam_set_item(handle, item_type as c_int, item) })
}

#[inline]
pub fn get_item(handle: &PamHandle,
                item_type: PamItemType,
                item: &mut *const c_void)
                -> PamReturnCode {
    From::from(unsafe { pam_get_item(handle, item_type as c_int, item) })
}

#[inline]
pub fn strerror(handle: &mut PamHandle, errnum: PamReturnCode) -> Option<&str> {
    unsafe { CStr::from_ptr(pam_strerror(handle, errnum as c_int)) }.to_str().ok()
}

#[inline]
pub fn putenv(handle: &mut PamHandle, name_value: &str) -> PamReturnCode {
    if let Ok(name_value) = CString::new(name_value) {
        From::from(unsafe { pam_putenv(handle, name_value.as_ptr()) })
    } else {
        // Not sure whether this is the correct return value
        PamReturnCode::BUF_ERR
    }
}

#[inline]
pub fn getenv<'a>(handle: &'a mut PamHandle, name: &str) -> Option<&'a str> {
    use std::ptr;
    use std::io;
    if let Ok(name) = CString::new(name) {
        let env = unsafe{pam_getenv(handle, name.as_ptr())};
        if env != ptr::null(){
            unsafe { CStr::from_ptr(env) }.to_str().ok()
        }
        else{
            None
        }
    } else {
        None
    }
}

#[inline]
pub fn getenvlist(handle: &mut PamHandle) -> *const *const c_char {
    //TODO: find a convenient way to handle this with Rust types
    unsafe { pam_getenvlist(handle) }
}
/* ----------------------- _pam_types.h ------------------------- */

/* ----------------------- pam_misc.h --------------------------- */
#[inline]
#[cfg(target_os = "linux")]
pub fn misc_paste_env(handle: &mut PamHandle, user_env: &[&str]) -> PamReturnCode {
    // Taken from: https://github.com/rust-lang/rust/issues/9564#issuecomment-95354558
    let user_env: Vec<_> = user_env.iter()
        .map(|&env| CString::new(env).unwrap())
        .collect();
    let env_ptrs: Vec<_> = user_env.iter()
        .map(|env| env.as_ptr())
        .chain(Some(null()))
        .collect();
    From::from(unsafe { pam_misc_paste_env(handle, env_ptrs.as_ptr()) })
}

#[inline]
#[cfg(target_os = "linux")]
pub fn misc_drop_env(env: &mut *mut c_char) -> PamReturnCode {
    From::from(unsafe { pam_misc_drop_env(env) })
}

#[inline]
#[cfg(target_os = "linux")]
pub fn misc_setenv(handle: &mut PamHandle,
                   name: &str,
                   value: &str,
                   readonly: bool)
                   -> PamReturnCode {
    if let (Ok(name), Ok(value)) = (CString::new(name), CString::new(value)) {
        From::from(unsafe {
            pam_misc_setenv(handle,
                            name.as_ptr(),
                            value.as_ptr(),
                            if readonly { 0 } else { 1 })
        })
    } else {
        PamReturnCode::BUF_ERR
    }
}
/* ----------------------- pam_misc.h --------------------------- */

/* ----------------------- pam_modules.h ------------------------ */
#[inline]
pub fn set_data(handle: &mut PamHandle,
                module_data_name: &str,
                data: &mut c_void,
                cleanup: Option<extern "C" fn(*mut PamHandle, *mut c_void, c_int)>)
                -> PamReturnCode {
    if let Ok(module_data_name) = CString::new(module_data_name) {
        From::from(unsafe { pam_set_data(handle, module_data_name.as_ptr(), data, cleanup) })

    } else {
        PamReturnCode::BUF_ERR
    }
}

//pub fn get_data(handle: *const PamHandle, module_data_name: *const c_char, data: *const *const c_void);

pub fn get_user(handle: &PamHandle,
                user: &mut *const c_char,
                prompt: *const c_char)
                -> PamReturnCode {

    From::from(
        unsafe {
            pam_get_user(
                handle,
                user,
                prompt
            )
        }
    )
}

/* ----------------------- pam_modules.h ------------------------ */
<|endoftext|>


<commit_before>// Copyright 2014 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.

use std::default::Default;
use std::fs::File;
use std::io::prelude::*;
use std::io;
use std::path::{PathBuf, Path};

use getopts;
use testing;
use rustc::session::search_paths::SearchPaths;
use rustc::session::config::Externs;
use syntax::codemap::DUMMY_SP;

use externalfiles::{ExternalHtml, LoadStringError, load_string};

use html::render::reset_ids;
use html::escape::Escape;
use html::markdown;
use html::markdown::{Markdown, MarkdownWithToc, find_testable_code};
use test::{TestOptions, Collector};

/// Separate any lines at the start of the file that begin with `%`.
fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) {
    let mut metadata = Vec::new();
    let mut count = 0;
    for line in s.lines() {
        if line.starts_with("%") {
            // remove %<whitespace>
            metadata.push(line[1..].trim_left());
            count += line.len() + 1;
        } else {
            return (metadata, &s[count..]);
        }
    }
    // if we're here, then all lines were metadata % lines.
    (metadata, "")
}

/// Render `input` (e.g. "foo.md") into an HTML file in `output`
/// (e.g. output = "bar" => "bar/foo.html").
pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
              external_html: &ExternalHtml, include_toc: bool) -> isize {
    let input_p = Path::new(input);
    output.push(input_p.file_stem().unwrap());
    output.set_extension("html");

    let mut css = String::new();
    for name in &matches.opt_strs("markdown-css") {
        let s = format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{}\">\n", name);
        css.push_str(&s)
    }

    let input_str = match load_string(input) {
        Ok(s) => s,
        Err(LoadStringError::ReadFail) => return 1,
        Err(LoadStringError::BadUtf8) => return 2,
    };
    if let Some(playground) = matches.opt_str("markdown-playground-url").or(
                              matches.opt_str("playground-url")) {
        markdown::PLAYGROUND.with(|s| { *s.borrow_mut() = Some((None, playground)); });
    }

    let mut out = match File::create(&output) {
        Err(e) => {
            let _ = writeln!(&mut io::stderr(),
                             "rustdoc: {}: {}",
                             output.display(), e);
            return 4;
        }
        Ok(f) => f
    };

    let (metadata, text) = extract_leading_metadata(&input_str);
    if metadata.is_empty() {
        let _ = writeln!(
            &mut io::stderr(),
            "rustdoc: invalid markdown file: expecting initial line with `% ...TITLE...`"
        );
        return 5;
    }
    let title = metadata[0];

    reset_ids(false);

    let rendered = if include_toc {
        format!("{}", MarkdownWithToc(text))
    } else {
        format!("{}", Markdown(text))
    };

    let err = write!(
        &mut out,
        r#"<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="generator" content="rustdoc">
    <title>{title}</title>

    {css}
    {in_header}

    {before_content}

{title}

    {text}
    {after_content}

"#,
        title = Escape(title),
        css = css,
        in_header = external_html.in_header,
        before_content = external_html.before_content,
        text = rendered,
        after_content = external_html.after_content,
        );

    match err {
        Err(e) => {
            let _ = writeln!(&mut io::stderr(),
                             "rustdoc: cannot write to `{}`: {}",
                             output.display(), e);
            6
        }
        Ok(_) => 0
    }
}

/// Run any tests/code examples in the markdown file `input`.
pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
            mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>) -> isize {
    let input_str = match load_string(input) {
        Ok(s) => s,
        Err(LoadStringError::ReadFail) => return 1,
        Err(LoadStringError::BadUtf8) => return 2,
    };

    let mut opts = TestOptions::default();
    opts.no_crate_inject = true;
    let mut collector = Collector::new(input.to_string(), cfgs, libs, externs,
                                       true, opts, maybe_sysroot, None,
                                       Some(input.to_owned()));
    find_testable_code(&input_str, &mut collector, DUMMY_SP);
    test_args.insert(0, "rustdoctest".to_string());
    testing::test_main(&test_args, collector.tests);
    0
}
<commit_msg>rustdoc to accept `#` at the start of a markdown file #40560<commit_after>// Copyright 2014 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.

use std::default::Default;
use std::fs::File;
use std::io::prelude::*;
use std::io;
use std::path::{PathBuf, Path};

use getopts;
use testing;
use rustc::session::search_paths::SearchPaths;
use rustc::session::config::Externs;
use syntax::codemap::DUMMY_SP;

use externalfiles::{ExternalHtml, LoadStringError, load_string};

use html::render::reset_ids;
use html::escape::Escape;
use html::markdown;
use html::markdown::{Markdown, MarkdownWithToc, find_testable_code};
use test::{TestOptions, Collector};

/// Separate any lines at the start of the file that begin with `# ` or `%`.
fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) {
    let mut metadata = Vec::new();
    let mut count = 0;

    for line in s.lines() {
        if line.starts_with("# ") || line.starts_with("%") {
            // trim the whitespace after the symbol
            metadata.push(line[1..].trim_left());
            count += line.len() + 1;
        } else {
            return (metadata, &s[count..]);
        }
    }

    // if we're here, then all lines were metadata `# ` or `%` lines.
    (metadata, "")
}

/// Render `input` (e.g. "foo.md") into an HTML file in `output`
/// (e.g. output = "bar" => "bar/foo.html").
pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
              external_html: &ExternalHtml, include_toc: bool) -> isize {
    let input_p = Path::new(input);
    output.push(input_p.file_stem().unwrap());
    output.set_extension("html");

    let mut css = String::new();
    for name in &matches.opt_strs("markdown-css") {
        let s = format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{}\">\n", name);
        css.push_str(&s)
    }

    let input_str = match load_string(input) {
        Ok(s) => s,
        Err(LoadStringError::ReadFail) => return 1,
        Err(LoadStringError::BadUtf8) => return 2,
    };
    if let Some(playground) = matches.opt_str("markdown-playground-url").or(
                              matches.opt_str("playground-url")) {
        markdown::PLAYGROUND.with(|s| { *s.borrow_mut() = Some((None, playground)); });
    }

    let mut out = match File::create(&output) {
        Err(e) => {
            let _ = writeln!(&mut io::stderr(),
                             "rustdoc: {}: {}",
                             output.display(), e);
            return 4;
        }
        Ok(f) => f
    };

    let (metadata, text) = extract_leading_metadata(&input_str);
    if metadata.is_empty() {
        let _ = writeln!(
            &mut io::stderr(),
            "rustdoc: invalid markdown file: no initial lines starting with `# ` or `%`"
        );
        return 5;
    }
    let title = metadata[0];

    reset_ids(false);

    let rendered = if include_toc {
        format!("{}", MarkdownWithToc(text))
    } else {
        format!("{}", Markdown(text))
    };

    let err = write!(
        &mut out,
        r#"<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="generator" content="rustdoc">
    <title>{title}</title>

    {css}
    {in_header}

    {before_content}

{title}

    {text}
    {after_content}

"#,
        title = Escape(title),
        css = css,
        in_header = external_html.in_header,
        before_content = external_html.before_content,
        text = rendered,
        after_content = external_html.after_content,
        );

    match err {
        Err(e) => {
            let _ = writeln!(&mut io::stderr(),
                             "rustdoc: cannot write to `{}`: {}",
                             output.display(), e);
            6
        }
        Ok(_) => 0
    }
}

/// Run any tests/code examples in the markdown file `input`.
pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
            mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>) -> isize {
    let input_str = match load_string(input) {
        Ok(s) => s,
        Err(LoadStringError::ReadFail) => return 1,
        Err(LoadStringError::BadUtf8) => return 2,
    };

    let mut opts = TestOptions::default();
    opts.no_crate_inject = true;
    let mut collector = Collector::new(input.to_string(), cfgs, libs, externs,
                                       true, opts, maybe_sysroot, None,
                                       Some(input.to_owned()));
    find_testable_code(&input_str, &mut collector, DUMMY_SP);
    test_args.insert(0, "rustdoctest".to_string());
    testing::test_main(&test_args, collector.tests);
    0
}
<|endoftext|>


<commit_before>use memory::Memory;
use std::vec::Vec;
use std::sync::atomic::{AtomicIsize, Ordering};

/// Maps multiple `Memory`s into a single address space.
///
/// The `MappedMemory` allows to unify multiple `Memory`s in one address space.
/// A `Memory` is mounted at a certain address and is from now on responsible
/// for all reads and writes between that starting at that address (the “mount
/// point”) and ending where the mounted memory ends.
/// The read and write calls for the responsible `Memory` will be given an
/// address _relative_ to the mount point.
///
/// ```text
///                   Unmapped
///                <-------->
///       mem_a                   mem_b
/// |--------------|            |------|
///                            NullMemory
///                         |--------------
/// |------------- mapped_mem ----------->
/// |              |            |      |
/// 0            0x100        0x200  0x280
/// ```
///
/// For example: `mapped_mem.get(0x208)` would yield the same value as
/// `mem_b.get(0x008)`.
///
/// # Examples
///
/// ```
/// use osciemu::memory::{Memory, SliceMemory, MappedMemory};
///
/// let mut mm = MappedMemory::new();
/// let m1 = mm.mount(0, Box::new(SliceMemory::from_slice(Box::new([1]))));
/// let m2 = mm.mount(2, Box::new(SliceMemory::from_slice(Box::new([2, 2]))));
/// // Now mm =~ [1, _, 2, 2]
/// assert_eq!(mm.get(0), 1);
/// assert_eq!(mm.get(3), 2);
/// ```
///
/// The `MemoryToken`s can be used to access the `Memory` even if it has been
/// mounted. They work like `std::cell::RefCell`.
///
/// ```
/// use osciemu::memory::{Memory, NullMemory, SliceMemory, MappedMemory};
/// use osciemu::memory::mappedmemory::MemoryToken;
///
/// let mut mm = MappedMemory::new();
/// let m1 = mm.mount(0, Box::new(NullMemory::new()));
/// let m2 = mm.mount(0, Box::new(SliceMemory::from_slice(Box::new([1, 2, 3, 4]))));
/// mm.set(0, 99);
/// assert_eq!(mm.get(0), 99);
/// // assert_eq!(m2.borrow().get(0), 99);
/// ```
///
/// The `MemoryToken`s are also used to unmount a mounted `Memory`.
///
/// ```
/// # use osciemu::memory::{Memory, NullMemory, SliceMemory, MappedMemory};
/// # use osciemu::memory::mappedmemory::MemoryToken;
/// # let mut mm = MappedMemory::new();
/// # let m1 = mm.mount(0, Box::new(NullMemory::new()));
/// # let m2 = mm.mount(0, Box::new(SliceMemory::from_slice(Box::new([1, 2, 3, 4]))));
/// # mm.set(0, 99);
/// // ...
/// // mm.unmount(&m2);
/// // assert_eq!(mm.get(0), 0);
/// // assert_eq!(m2.borrow().get(0), 99);
/// ```
///
/// # Panics
/// `MappedMemory` panics when an unmapped address is read or written.
pub struct MappedMemory {
    mounted_memories: Vec<Entry>,
    unmounted_memories: Vec<Entry>,
}

static id_counter: AtomicIsize = AtomicIsize::new(0);

struct Entry {
    id: isize,
    start_address: usize,
    size: usize,
    memory: Box<Memory>,
}

#[derive(Clone)]
pub struct MemoryToken {
    id: isize,
}

impl MappedMemory {
    pub fn new() -> MappedMemory {
        MappedMemory {
            mounted_memories: Vec::new(),
            unmounted_memories: Vec::new(),
        }
    }

    /// Mounts a `Memory` at the given address.
    pub fn mount(&mut self, start_address: usize, memory: Box<Memory>) -> MemoryToken {
        let size = memory.size();
        let id = id_counter.fetch_add(1, Ordering::Relaxed);
        let new_entry = Entry {
            id,
            start_address,
            size,
            memory,
        };
        self.mounted_memories.push(new_entry);
        MemoryToken{id}
    }

    /// Unmounts the `Memory` references by the `MemoryToken`. After unmounting,
    /// `MappedMemory` does not hold any references to the `Memory`.
    pub fn unmount(&mut self, token: &MemoryToken) {
        let entry = self.mounted_memories
            .iter()
            .enumerate()
            .find(|&(_, entry)| entry.id == token.id)
            .map(|(idx, _)| idx)
            .map(|idx| {
                self.mounted_memories.remove(idx)
            }).unwrap();
        self.unmounted_memories.push(entry);
    }

    pub fn borrow(&self, token: &MemoryToken) -> &Box<Memory> {
        let idx = self.mounted_memories
            .iter()
            .enumerate()
            .find(|&(idx, entry)| entry.id == token.id)
            .map(|(idx, _)| idx)
            .unwrap();
        &self.mounted_memories.get(idx).unwrap().memory
    }

    pub fn borrow_mut(&mut self, token: &MemoryToken) -> &mut Box<Memory> {
        let idx = self.mounted_memories
            .iter()
            .enumerate()
            .find(|&(idx, entry)| entry.id == token.id)
            .map(|(idx, _)| idx)
            .unwrap();
        &mut self.mounted_memories.get_mut(idx).unwrap().memory
    }

    // fn memory_for_token(&self, token: &MemoryToken): &Entry {
    // }

    fn entry_at_addr(&self, addr: usize) -> Option<&Entry> {
        self.mounted_memories
            .iter()
            .rev()
            .find(|entry| entry.start_address <= addr && entry.start_address + entry.size > addr)
    }

    fn entry_at_addr_mut(&mut self, addr: usize) -> Option<&mut Entry> {
        self.mounted_memories
            .iter_mut()
            .rev()
            .find(|entry| entry.start_address <= addr && entry.start_address + entry.size > addr)
    }
}

impl Memory for MappedMemory {
    fn get(&self, addr: usize) -> u32 {
        self.entry_at_addr(addr)
            .map(|entry| entry.memory.get(addr - entry.start_address))
            .expect("Out of bounds")
    }

    fn set(&mut self, addr: usize, value: u32) {
        self.entry_at_addr_mut(addr)
            .map(|entry| entry.memory.set(addr - entry.start_address, value))
            .expect("Out of bounds")
    }

    fn size(&self) -> usize {
        self.mounted_memories
            .iter()
            .map(|entry| entry.start_address + entry.size)
            .max()
            .unwrap_or(0)
    }
}

#[cfg(test)]
mod tests {
    use memory::{Memory, SliceMemory, NullMemory};

    // #[test]
    // fn memory_at_addr() {
    //     let m1 = SliceMemory::from_slice(Box::new([1]));
    //     let m2 = SliceMemory::from_slice(Box::new([2, 2]));
    //     let mut mm = super::MappedMemory::new();
    //     let m1 = mm.mount(0, &m1);
    //     let m2 = mm.mount(2, &m2);

    //     assert!(mm.memory_at_addr(0)
    //         .map_or(false, |entry| entry.memory.get(0) == 1));
    //     assert!(mm.memory_at_addr(1).is_none());
    //     assert!(mm.memory_at_addr(2)
    //         .map_or(false, |entry| entry.memory.get(0) == 2));
    //     assert!(mm.memory_at_addr(3)
    //         .map_or(false, |entry| entry.memory.get(0) == 2));
    //     assert!(mm.memory_at_addr(4).is_none());
    // }

    // #[test]
    // fn overlapping_mounts() {
    //     let m1 = super::MemoryToken::new(NullMemory::new());
    //     let m2 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([2, 2])));
    //     let m3 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([3])));
    //     let mut mm = super::MappedMemory::new();
    //     mm.mount(0, &m1);
    //     mm.mount(1, &m2);
    //     mm.mount(2, &m3);
    //     assert_eq!(mm.get(0), 0);
    //     assert_eq!(mm.get(1), 2);
    //     assert_eq!(mm.get(2), 3);
    //     assert_eq!(mm.get(3), 0);
    // }

    // #[test]
    // fn get_and_set() {
    //     let m1 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([1])));
    //     let m2 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([2, 2])));
    //     let mut mm = super::MappedMemory::new();

    //     mm.mount(0, &m1);
    //     mm.mount(2, &m2);
    //     assert_eq!(mm.get(0), 1);
    //     assert_eq!(mm.get(2), 2);

    //     mm.set(0, 3);
    //     assert_eq!(mm.get(0), 3);

    //     mm.set(3, 0);
    //     assert_eq!(mm.get(3), 0);
    //     assert_eq!(m1.borrow().get(0), 3);
    //     assert_eq!(m2.borrow().get(1), 0);
    // }

    // #[test]
    // fn size() {
    //     let m1 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([1])));
    //     let m2 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([2, 2])));
    //     let mut mm = super::MappedMemory::new();
    //     assert_eq!(mm.size(), 0);

    //     mm.mount(0, &m1);
    //     assert_eq!(mm.size(), 1);

    //     mm.mount(2, &m2);
    //     assert_eq!(mm.size(), 4);
    // }

    // #[test]
    // fn size_with_overlap() {
    //     let m1 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([1, 1, 1, 1, 1])));
    //     let m2 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([2, 2])));
    //     let m3 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([3, 3, 3])));
    //     let mut mm = super::MappedMemory::new();

    //     mm.mount(0, &m1);
    //     mm.mount(2, &m2);
    //     assert_eq!(mm.size(), 5);

    //     mm.mount(6, &m3);
    //     assert_eq!(mm.size(), 9);
    // }

    // #[test]
    // fn unmount() {
    //     let m1 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([1, 1, 1, 1, 1])));
    //     let m2 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([2, 2, 2, 2, 2])));
    //     let m3 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([3, 3, 3, 3, 3])));
    //     let mut mm = super::MappedMemory::new();
    //     mm.mount(0, &m1);
    //     mm.mount(0, &m2);
    //     mm.mount(0, &m3);

    //     for i in 0..5 {
    //         assert_eq!(mm.get(i), 3);
    //     }
    //     mm.unmount(&m3);
    //     for i in 0..5 {
    //         assert_eq!(mm.get(i), 2);
    //     }
    //     mm.unmount(&m3);
    //     mm.unmount(&m3);
    //     for i in 0..5 {
    //         assert_eq!(mm.get(i), 2);
    //     }
    //     mm.unmount(&m1);
    //     for i in 0..5 {
    //         assert_eq!(mm.get(i), 2);
    //     }
    // }
}
<commit_msg>feat(mappedmemory): generic functions to find entries<commit_after>use memory::Memory;
use std::vec::Vec;
use std::sync::atomic::{AtomicIsize, Ordering};

/// Maps multiple `Memory`s into a single address space.
///
/// The `MappedMemory` allows to unify multiple `Memory`s in one address space.
/// A `Memory` is mounted at a certain address and is from now on responsible
/// for all reads and writes between that starting at that address (the “mount
/// point”) and ending where the mounted memory ends.
/// The read and write calls for the responsible `Memory` will be given an
/// address _relative_ to the mount point.
///
/// ```text
///                   Unmapped
///                <-------->
///       mem_a                   mem_b
/// |--------------|            |------|
///                            NullMemory
///                         |--------------
/// |------------- mapped_mem ----------->
/// |              |            |      |
/// 0            0x100        0x200  0x280
/// ```
///
/// For example: `mapped_mem.get(0x208)` would yield the same value as
/// `mem_b.get(0x008)`.
///
/// # Examples
///
/// ```
/// use osciemu::memory::{Memory, SliceMemory, MappedMemory};
///
/// let mut mm = MappedMemory::new();
/// let m1 = mm.mount(0, Box::new(SliceMemory::from_slice(Box::new([1]))));
/// let m2 = mm.mount(2, Box::new(SliceMemory::from_slice(Box::new([2, 2]))));
/// // Now mm =~ [1, _, 2, 2]
/// assert_eq!(mm.get(0), 1);
/// assert_eq!(mm.get(3), 2);
/// ```
///
/// The `MemoryToken`s can be used to access the `Memory` even if it has been
/// mounted. They work like `std::cell::RefCell`.
///
/// ```
/// use osciemu::memory::{Memory, NullMemory, SliceMemory, MappedMemory};
/// use osciemu::memory::mappedmemory::MemoryToken;
///
/// let mut mm = MappedMemory::new();
/// let m1 = mm.mount(0, Box::new(NullMemory::new()));
/// let m2 = mm.mount(0, Box::new(SliceMemory::from_slice(Box::new([1, 2, 3, 4]))));
/// mm.set(0, 99);
/// assert_eq!(mm.get(0), 99);
/// assert_eq!(mm.borrow(&m2).get(0), 99);
/// ```
///
/// The `MemoryToken`s are also used to unmount a mounted `Memory`.
///
/// ```
/// # use osciemu::memory::{Memory, NullMemory, SliceMemory, MappedMemory};
/// # use osciemu::memory::mappedmemory::MemoryToken;
/// # let mut mm = MappedMemory::new();
/// # let m1 = mm.mount(0, Box::new(NullMemory::new()));
/// # let m2 = mm.mount(0, Box::new(SliceMemory::from_slice(Box::new([1, 2, 3, 4]))));
/// # mm.set(0, 99);
/// // ...
/// mm.unmount(&m2);
/// assert_eq!(mm.get(0), 0);
/// assert_eq!(mm.borrow(&m2).get(0), 99);
/// ```
///
/// # Panics
/// `MappedMemory` panics when an unmapped address is read or written.
pub struct MappedMemory {
    mounted_memories: Vec<Entry>,
    unmounted_memories: Vec<Entry>,
}

static id_counter: AtomicIsize = AtomicIsize::new(0);

struct Entry {
    id: isize,
    start_address: usize,
    size: usize,
    memory: Box<Memory>,
}

#[derive(Clone)]
pub struct MemoryToken {
    id: isize,
}

impl MappedMemory {
    pub fn new() -> MappedMemory {
        MappedMemory {
            mounted_memories: Vec::new(),
            unmounted_memories: Vec::new(),
        }
    }

    /// Mounts a `Memory` at the given address.
    pub fn mount(&mut self, start_address: usize, memory: Box<Memory>) -> MemoryToken {
        let size = memory.size();
        let id = id_counter.fetch_add(1, Ordering::Relaxed);
        let new_entry = Entry {
            id,
            start_address,
            size,
            memory,
        };
        self.mounted_memories.push(new_entry);
        MemoryToken{id}
    }

    /// Unmounts the `Memory` references by the `MemoryToken`. After unmounting,
    /// `MappedMemory` does not hold any references to the `Memory`.
    pub fn unmount(&mut self, token: &MemoryToken) {
        let entry = self.mounted_memories
            .iter()
            .enumerate()
            .find(|&(_, entry)| entry.id == token.id)
            .map(|(idx, _)| idx)
            .map(|idx| {
                self.mounted_memories.remove(idx)
            }).unwrap();
        self.unmounted_memories.push(entry);
    }

    pub fn borrow(&self, token: &MemoryToken) -> &Box<Memory> {
        &self.entry_for_token(token).memory
    }

    pub fn borrow_mut(&mut self, token: &MemoryToken) -> &mut Box<Memory> {
        &mut self.entry_for_token_mut(token).memory
    }

    fn entry_for_token(&self, token: &MemoryToken) -> &Entry {
        let m = self.mounted_memories
            .iter()
            .find(|ref entry| entry.id == token.id);

        if m.is_some() {
            m.unwrap()
        } else {
            self.unmounted_memories
                .iter()
                .find(|ref entry| entry.id == token.id)
                .unwrap()
        }
    }

    fn entry_for_token_mut(&mut self, token: &MemoryToken) -> &mut Entry {
        let m = self.mounted_memories
            .iter_mut()
            .find(|ref mut entry| entry.id == token.id);

        if m.is_some() {
            m.unwrap()
        } else {
            self.unmounted_memories
                .iter_mut()
                .find(|ref mut entry| entry.id == token.id)
                .unwrap()
        }
    }

    fn entry_at_addr(&self, addr: usize) -> Option<&Entry> {
        self.mounted_memories
            .iter()
            .rev()
            .find(|entry| entry.start_address <= addr && entry.start_address + entry.size > addr)
    }

    fn entry_at_addr_mut(&mut self, addr: usize) -> Option<&mut Entry> {
        self.mounted_memories
            .iter_mut()
            .rev()
            .find(|entry| entry.start_address <= addr && entry.start_address + entry.size > addr)
    }
}

impl Memory for MappedMemory {
    fn get(&self, addr: usize) -> u32 {
        self.entry_at_addr(addr)
            .map(|entry| entry.memory.get(addr - entry.start_address))
            .expect("Out of bounds")
    }

    fn set(&mut self, addr: usize, value: u32) {
        self.entry_at_addr_mut(addr)
            .map(|entry| entry.memory.set(addr - entry.start_address, value))
            .expect("Out of bounds")
    }

    fn size(&self) -> usize {
        self.mounted_memories
            .iter()
            .map(|entry| entry.start_address + entry.size)
            .max()
            .unwrap_or(0)
    }
}

#[cfg(test)]
mod tests {
    use memory::{Memory, SliceMemory, NullMemory};

    // #[test]
    // fn memory_at_addr() {
    //     let m1 = SliceMemory::from_slice(Box::new([1]));
    //     let m2 = SliceMemory::from_slice(Box::new([2, 2]));
    //     let mut mm = super::MappedMemory::new();
    //     let m1 = mm.mount(0, &m1);
    //     let m2 = mm.mount(2, &m2);

    //     assert!(mm.memory_at_addr(0)
    //         .map_or(false, |entry| entry.memory.get(0) == 1));
    //     assert!(mm.memory_at_addr(1).is_none());
    //     assert!(mm.memory_at_addr(2)
    //         .map_or(false, |entry| entry.memory.get(0) == 2));
    //     assert!(mm.memory_at_addr(3)
    //         .map_or(false, |entry| entry.memory.get(0) == 2));
    //     assert!(mm.memory_at_addr(4).is_none());
    // }

    // #[test]
    // fn overlapping_mounts() {
    //     let m1 = super::MemoryToken::new(NullMemory::new());
    //     let m2 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([2, 2])));
    //     let m3 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([3])));
    //     let mut mm = super::MappedMemory::new();
    //     mm.mount(0, &m1);
    //     mm.mount(1, &m2);
    //     mm.mount(2, &m3);
    //     assert_eq!(mm.get(0), 0);
    //     assert_eq!(mm.get(1), 2);
    //     assert_eq!(mm.get(2), 3);
    //     assert_eq!(mm.get(3), 0);
    // }

    // #[test]
    // fn get_and_set() {
    //     let m1 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([1])));
    //     let m2 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([2, 2])));
    //     let mut mm = super::MappedMemory::new();

    //     mm.mount(0, &m1);
    //     mm.mount(2, &m2);
    //     assert_eq!(mm.get(0), 1);
    //     assert_eq!(mm.get(2), 2);

    //     mm.set(0, 3);
    //     assert_eq!(mm.get(0), 3);

    //     mm.set(3, 0);
    //     assert_eq!(mm.get(3), 0);
    //     assert_eq!(m1.borrow().get(0), 3);
    //     assert_eq!(m2.borrow().get(1), 0);
    // }

    // #[test]
    // fn size() {
    //     let m1 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([1])));
    //     let m2 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([2, 2])));
    //     let mut mm = super::MappedMemory::new();
    //     assert_eq!(mm.size(), 0);

    //     mm.mount(0, &m1);
    //     assert_eq!(mm.size(), 1);

    //     mm.mount(2, &m2);
    //     assert_eq!(mm.size(), 4);
    // }

    // #[test]
    // fn size_with_overlap() {
    //     let m1 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([1, 1, 1, 1, 1])));
    //     let m2 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([2, 2])));
    //     let m3 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([3, 3, 3])));
    //     let mut mm = super::MappedMemory::new();

    //     mm.mount(0, &m1);
    //     mm.mount(2, &m2);
    //     assert_eq!(mm.size(), 5);

    //     mm.mount(6, &m3);
    //     assert_eq!(mm.size(), 9);
    // }

    // #[test]
    // fn unmount() {
    //     let m1 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([1, 1, 1, 1, 1])));
    //     let m2 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([2, 2, 2, 2, 2])));
    //     let m3 = super::MemoryToken::new(SliceMemory::from_slice(Box::new([3, 3, 3, 3, 3])));
    //     let mut mm = super::MappedMemory::new();
    //     mm.mount(0, &m1);
    //     mm.mount(0, &m2);
    //     mm.mount(0, &m3);

    //     for i in 0..5 {
    //         assert_eq!(mm.get(i), 3);
    //     }
    //     mm.unmount(&m3);
    //     for i in 0..5 {
    //         assert_eq!(mm.get(i), 2);
    //     }
    //     mm.unmount(&m3);
    //     mm.unmount(&m3);
    //     for i in 0..5 {
    //         assert_eq!(mm.get(i), 2);
    //     }
    //     mm.unmount(&m1);
    //     for i in 0..5 {
    //         assert_eq!(mm.get(i), 2);
    //     }
    // }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate log;
extern crate futures;
extern crate tokio_uds;
extern crate tokio_core;
extern crate env_logger;
extern crate sozu_command_lib as sozu_command;
extern crate sozu_command_futures as command;

use futures::future::Future;
use tokio_uds::UnixStream;
use tokio_core::reactor::Core;
use command::SozuCommandClient;
use sozu_command::data::{ConfigCommand,ConfigMessage};

fn main() {
    env_logger::init().unwrap();
    let mut core   = Core::new().unwrap();
    let handle     = core.handle();

    let stream = UnixStream::connect("/Users/geal/dev/rust/projects/yxorp/bin/sock",  &handle).unwrap();
    let mut client = SozuCommandClient::new(stream);

    core.run(
        Box::new(futures::future::lazy( || {
            client.send(ConfigMessage::new(
                String::from("message-id-42"),
                ConfigCommand::ListWorkers,
                None,
            )).and_then(|answer| {
                info!("received answer: {:?}", answer);
                Ok(())
            })
        }))

    ).unwrap()
}

<commit_msg>fix compilation for the futures example<commit_after>#[macro_use] extern crate log;
extern crate futures;
extern crate tokio_uds;
extern crate tokio_core;
extern crate env_logger;
extern crate sozu_command_lib as sozu_command;
extern crate sozu_command_futures as command;

use futures::future::Future;
use tokio_uds::UnixStream;
use tokio_core::reactor::Core;
use command::SozuCommandClient;
use sozu_command::data::{ConfigCommand,ConfigMessage};

fn main() {
    env_logger::init();
    let mut core   = Core::new().unwrap();
    let handle     = core.handle();

    let stream = UnixStream::connect("/Users/geal/dev/rust/projects/yxorp/bin/sock",  &handle).unwrap();
    let mut client = SozuCommandClient::new(stream);

    core.run(
        Box::new(futures::future::lazy( || {
            client.send(ConfigMessage::new(
                String::from("message-id-42"),
                ConfigCommand::ListWorkers,
                None,
            )).and_then(|answer| {
                info!("received answer: {:?}", answer);
                Ok(())
            })
        }))

    ).unwrap()
}

<|endoftext|>


<commit_before>//! Types and traits for working with the Matrix protocol.
//!
//! This crate re-exports things from all of the other ruma crates so you don't
//! have to manually keep all the versions in sync.
//!
//! Which crates are re-exported can be configured through cargo features.
//! Depending on which parts of Matrix are relevant to you, activate the
//! following features:
//!
//! * `client-api` for the client-server API
//! * `federation-api` for the server-server (federation) API
//! * `appservice-api` for the application service API

#![deny(missing_docs)]

pub use ruma_common::*;
#[doc(inline)]
pub use ruma_identifiers as identifiers;
pub use ruma_identifiers_macros::*;

#[cfg(feature = "ruma-events")]
#[doc(inline)]
pub use ruma_events as events;
#[cfg(feature = "ruma-signatures")]
#[doc(inline)]
pub use ruma_signatures as signatures;

/// Rust types for various Matrix APIs requests and responses and abstractions for them.
#[cfg(feature = "ruma-api")]
#[doc(inline)]
pub mod api {
    // Everything except the `ruma_api!` macro
    pub use ruma_api::{error, Endpoint, EndpointError, Metadata};

    #[cfg(feature = "ruma-appservice-api")]
    #[doc(inline)]
    pub use ruma_appservice_api as appservice;
    #[cfg(feature = "ruma-client-api")]
    #[doc(inline)]
    pub use ruma_client_api as client;
    #[cfg(feature = "ruma-federation-api")]
    #[doc(inline)]
    pub use ruma_federation_api as federation;
}
<commit_msg>ruma: Reexport identifier types from the crate root<commit_after>//! Types and traits for working with the Matrix protocol.
//!
//! This crate re-exports things from all of the other ruma crates so you don't
//! have to manually keep all the versions in sync.
//!
//! Which crates are re-exported can be configured through cargo features.
//! Depending on which parts of Matrix are relevant to you, activate the
//! following features:
//!
//! * `client-api` for the client-server API
//! * `federation-api` for the server-server (federation) API
//! * `appservice-api` for the application service API

#![deny(missing_docs)]

pub use ruma_common::*;
#[doc(inline)]
pub use ruma_identifiers as identifiers;
pub use ruma_identifiers_macros::*;

pub use ruma_identifiers::{
    DeviceId, DeviceKeyAlgorithm, DeviceKeyId, EventId, RoomAliasId, RoomId, RoomIdOrAliasId,
    RoomVersionId, ServerKeyAlgorithm, ServerKeyId, ServerName, UserId,
};

#[cfg(feature = "ruma-events")]
#[doc(inline)]
pub use ruma_events as events;
#[cfg(feature = "ruma-signatures")]
#[doc(inline)]
pub use ruma_signatures as signatures;

/// Rust types for various Matrix APIs requests and responses and abstractions for them.
#[cfg(feature = "ruma-api")]
#[doc(inline)]
pub mod api {
    // Everything except the `ruma_api!` macro
    pub use ruma_api::{error, Endpoint, EndpointError, Metadata};

    #[cfg(feature = "ruma-appservice-api")]
    #[doc(inline)]
    pub use ruma_appservice_api as appservice;
    #[cfg(feature = "ruma-client-api")]
    #[doc(inline)]
    pub use ruma_client_api as client;
    #[cfg(feature = "ruma-federation-api")]
    #[doc(inline)]
    pub use ruma_federation_api as federation;
}
<|endoftext|>


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

#![allow(non_upper_case_globals)]

use core_foundation::array::CFArrayRef;
use core_foundation::base::{CFType, CFTypeID, CFTypeRef, TCFType};
use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
use core_foundation::number::{CFNumber, CFNumberRef};
use core_foundation::set::CFSetRef;
use core_foundation::string::{CFString, CFStringRef};
use core_foundation::url::CFURL;
use core_graphics::base::CGFloat;

use libc::c_void;
use std::mem;

/*
* CTFontTraits.h
*/
// actually, these are extern enums
pub type CTFontFormat = u32;
pub const kCTFontFormatUnrecognized: CTFontFormat = 0;
pub const kCTFontFormatOpenTypePostScript: CTFontFormat = 1;
pub const kCTFontFormatOpenTypeTrueType: CTFontFormat = 2;
pub const kCTFontFormatTrueType: CTFontFormat = 3;
pub const kCTFontFormatPostScript: CTFontFormat = 4;
pub const kCTFontFormatBitmap: CTFontFormat = 5;

pub const kCTFontClassMaskShift: u32 = 28;

pub type CTFontSymbolicTraits = u32;
pub const kCTFontItalicTrait: CTFontSymbolicTraits = (1 << 0);
pub const kCTFontBoldTrait: CTFontSymbolicTraits = (1 << 1);
pub const kCTFontExpandedTrait: CTFontSymbolicTraits = (1 << 5);
pub const kCTFontCondensedTrait: CTFontSymbolicTraits = (1 << 6);
pub const kCTFontMonoSpaceTrait: CTFontSymbolicTraits = (1 << 10);
pub const kCTFontVerticalTrait: CTFontSymbolicTraits = (1 << 11);
pub const kCTFontUIOptimizedTrait: CTFontSymbolicTraits = (1 << 12);
pub const kCTFontColorGlyphsTrait: CTFontSymbolicTraits = (1 << 13);
pub const kCTFontClassMaskTrait: CTFontSymbolicTraits = (15 << kCTFontClassMaskShift );

pub trait SymbolicTraitAccessors {
    fn is_italic(&self) -> bool;
    fn is_bold(&self) -> bool;
    fn is_expanded(&self) -> bool;
    fn is_condensed(&self) -> bool;
    fn is_monospace(&self) -> bool;
}

impl SymbolicTraitAccessors for CTFontSymbolicTraits {
    fn is_italic(&self) -> bool { (*self & kCTFontItalicTrait) != 0 }
    fn is_bold(&self) -> bool { (*self & kCTFontBoldTrait) != 0 }
    fn is_expanded(&self) -> bool { (*self & kCTFontExpandedTrait) != 0 }
    fn is_condensed(&self) -> bool { (*self & kCTFontCondensedTrait) != 0 }
    fn is_monospace(&self) -> bool { (*self & kCTFontMonoSpaceTrait) != 0 }
}

pub type CTFontStylisticClass = u32;
pub const kCTFontUnknownClass: CTFontStylisticClass = (0 << kCTFontClassMaskShift );
pub const kCTFontOldStyleSerifsClass: CTFontStylisticClass = (1 << kCTFontClassMaskShift );
pub const kCTFontTransitionalSerifsClass: CTFontStylisticClass = (2 << kCTFontClassMaskShift );
pub const kCTFontModernSerifsClass: CTFontStylisticClass = (3 << kCTFontClassMaskShift );
pub const kCTFontClarendonSerifsClass: CTFontStylisticClass = (4 << kCTFontClassMaskShift );
pub const kCTFontSlabSerifsClass: CTFontStylisticClass = (5 << kCTFontClassMaskShift );
pub const kCTFontFreeformSerifsClass: CTFontStylisticClass = (7 << kCTFontClassMaskShift );
pub const kCTFontSansSerifClass: CTFontStylisticClass = (8 << kCTFontClassMaskShift );
pub const kCTFontOrnamentalsClass: CTFontStylisticClass = (9 << kCTFontClassMaskShift );
pub const kCTFontScriptsClass: CTFontStylisticClass = (10 << kCTFontClassMaskShift );
pub const kCTFontSymbolicClass: CTFontStylisticClass = (12 << kCTFontClassMaskShift );

pub trait StylisticClassAccessors {
    fn is_serif(&self) -> bool;
    fn is_sans_serif(&self) -> bool;
    fn is_script(&self) -> bool;
    fn is_fantasy(&self) -> bool;
    fn is_symbols(&self) -> bool;
}

impl StylisticClassAccessors for CTFontStylisticClass {
    fn is_serif(&self) -> bool {
        let any_serif_class = kCTFontOldStyleSerifsClass
            | kCTFontTransitionalSerifsClass
            | kCTFontModernSerifsClass
            | kCTFontClarendonSerifsClass
            | kCTFontSlabSerifsClass
            | kCTFontFreeformSerifsClass;

        return (*self & any_serif_class) != 0;
    }

    fn is_sans_serif(&self) -> bool {
        return (*self & kCTFontSansSerifClass) != 0;
    }

    fn is_script(&self) -> bool {
        return (*self & kCTFontScriptsClass) != 0;
    }

    fn is_fantasy(&self) -> bool {
        return (*self & kCTFontOrnamentalsClass) != 0;
    }

    fn is_symbols(&self) -> bool {
        return (*self & kCTFontSymbolicClass) != 0;
    }
}

pub type CTFontAttributes = CFDictionary;

pub type CTFontTraits = CFDictionary;

pub trait TraitAccessors {
    fn symbolic_traits(&self) -> CTFontSymbolicTraits;
    fn normalized_weight(&self) -> f64;
    fn normalized_width(&self) -> f64;
    fn normalized_slant(&self) -> f64;
}

trait TraitAccessorPrivate {
    unsafe fn extract_number_for_key(&self, key: CFStringRef) -> CFNumber;
}

impl TraitAccessorPrivate for CTFontTraits {
    unsafe fn extract_number_for_key(&self, key: CFStringRef) -> CFNumber {
        let cftype = self.get_CFType(mem::transmute(key));
        assert!(cftype.instance_of::<CFNumber>());
        TCFType::wrap_under_get_rule(mem::transmute(cftype.as_CFTypeRef()))
    }

}

impl TraitAccessors for CTFontTraits {
    fn symbolic_traits(&self) -> CTFontSymbolicTraits {
        unsafe {
            let number = self.extract_number_for_key(kCTFontSymbolicTrait);
            number.to_i64().unwrap() as u32
        }
    }

    fn normalized_weight(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontWeightTrait);
            number.to_f64().unwrap()
        }
    }

    fn normalized_width(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontWidthTrait);
            number.to_f64().unwrap()
        }
    }

    fn normalized_slant(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontSlantTrait);
            number.to_f64().unwrap()
        }
    }
}

/*
* CTFontDescriptor.h
*/
pub type CTFontOrientation = u32;
pub const kCTFontDefaultOrientation: CTFontOrientation = 0;
pub const kCTFontHorizontalOrientation: CTFontOrientation = 1;
pub const kCTFontVerticalOrientation: CTFontOrientation = 2;

pub type CTFontPriority = u32;
pub const kCTFontPrioritySystem: CTFontPriority = 10000;
pub const kCTFontPriorityNetwork: CTFontPriority = 20000;
pub const kCTFontPriorityComputer: CTFontPriority = 30000;
pub const kCTFontPriorityUser: CTFontPriority = 40000;
pub const kCTFontPriorityDynamic: CTFontPriority = 50000;
pub const kCTFontPriorityProcess: CTFontPriority = 60000;

#[repr(C)]
pub struct __CTFontDescriptor(c_void);

pub type CTFontDescriptorRef = *const __CTFontDescriptor;

declare_TCFType! {
    CTFontDescriptor, CTFontDescriptorRef
}
impl_TCFType!(CTFontDescriptor, CTFontDescriptorRef, CTFontDescriptorGetTypeID);
impl_CFTypeDescription!(CTFontDescriptor);

impl CTFontDescriptor {
    fn get_string_attribute(&self, attribute: CFStringRef) -> Option<String> {
        unsafe {
            let value = CTFontDescriptorCopyAttribute(self.0, attribute);
            if value.is_null() {
                return None
            }

            let value: CFType = TCFType::wrap_under_create_rule(value);
            assert!(value.instance_of::<CFString>());
            let s: CFString = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            Some(s.to_string())
        }
    }

}

impl CTFontDescriptor {
    pub fn family_name(&self) -> String {
        unsafe {
            let value = self.get_string_attribute(kCTFontFamilyNameAttribute);
            value.expect("A font must have a non-null family name.")
        }
    }

    pub fn font_name(&self) -> String {
        unsafe {
            let value = self.get_string_attribute(kCTFontNameAttribute);
            value.expect("A font must have a non-null name.")
        }
    }

    pub fn style_name(&self) -> String {
        unsafe {
            let value = self.get_string_attribute(kCTFontStyleNameAttribute);
            value.expect("A font must have a non-null style name.")
        }
    }

    pub fn display_name(&self) -> String {
        unsafe {
            let value = self.get_string_attribute(kCTFontDisplayNameAttribute);
            value.expect("A font must have a non-null display name.")
        }
    }

    pub fn font_path(&self) -> Option<String> {
        unsafe {
            let value = CTFontDescriptorCopyAttribute(self.0, kCTFontURLAttribute);
            if value.is_null() {
                return None;
            }

            let value: CFType = TCFType::wrap_under_create_rule(value);
            assert!(value.instance_of::<CFURL>());
            let url: CFURL = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            Some(format!("{:?}", url))
        }
    }
}

pub fn new_from_attributes(attributes: &CFDictionary) -> CTFontDescriptor {
    unsafe {
        let result: CTFontDescriptorRef =
            CTFontDescriptorCreateWithAttributes(attributes.as_concrete_TypeRef());
        TCFType::wrap_under_create_rule(result)
    }
}

pub fn debug_descriptor(desc: &CTFontDescriptor) {
    println!("family: {}", desc.family_name());
    println!("name: {}", desc.font_name());
    println!("style: {}", desc.style_name());
    println!("display: {}", desc.display_name());
    println!("path: {:?}", desc.font_path());
    desc.show();
}

extern {
    /*
     * CTFontTraits.h
     */

    // font trait constants
    pub static kCTFontSymbolicTrait: CFStringRef;
    pub static kCTFontWeightTrait: CFStringRef;
    pub static kCTFontWidthTrait: CFStringRef;
    pub static kCTFontSlantTrait: CFStringRef;

    /*
     * CTFontDescriptor.h
     */

    // font attribute constants. Note that the name-related attributes
    // here are somewhat flaky. Servo creates CTFont instances and
    // then uses CTFontCopyName to get more fine-grained names.
    pub static kCTFontURLAttribute:                  CFStringRef; // value: CFURLRef
    pub static kCTFontNameAttribute:                 CFStringRef; // value: CFStringRef
    pub static kCTFontDisplayNameAttribute:          CFStringRef; // value: CFStringRef
    pub static kCTFontFamilyNameAttribute:           CFStringRef; // value: CFStringRef
    pub static kCTFontStyleNameAttribute:            CFStringRef; // value: CFStringRef
    pub static kCTFontTraitsAttribute:               CFStringRef;
    pub static kCTFontVariationAttribute:            CFStringRef;
    pub static kCTFontSizeAttribute:                 CFStringRef;
    pub static kCTFontMatrixAttribute:               CFStringRef;
    pub static kCTFontCascadeListAttribute:          CFStringRef;
    pub static kCTFontCharacterSetAttribute:         CFStringRef;
    pub static kCTFontLanguagesAttribute:            CFStringRef;
    pub static kCTFontBaselineAdjustAttribute:       CFStringRef;
    pub static kCTFontMacintoshEncodingsAttribute:   CFStringRef;
    pub static kCTFontFeaturesAttribute:             CFStringRef;
    pub static kCTFontFeatureSettingsAttribute:      CFStringRef;
    pub static kCTFontFixedAdvanceAttribute:         CFStringRef;
    pub static kCTFontOrientationAttribute:          CFStringRef;
    pub static kCTFontFormatAttribute:               CFStringRef;
    pub static kCTFontRegistrationScopeAttribute:    CFStringRef;
    pub static kCTFontPriorityAttribute:             CFStringRef;
    pub static kCTFontEnabledAttribute:              CFStringRef;

    pub fn CTFontDescriptorCopyAttribute(descriptor: CTFontDescriptorRef,
                                         attribute: CFStringRef) -> CFTypeRef;
    pub fn CTFontDescriptorCopyAttributes(descriptor: CTFontDescriptorRef) -> CFDictionaryRef;
    pub fn CTFontDescriptorCopyLocalizedAttribute(descriptor: CTFontDescriptorRef,
                                                  attribute: CFStringRef,
                                                  language: *mut CFStringRef) -> CFTypeRef;
    pub fn CTFontDescriptorCreateCopyWithAttributes(original: CTFontDescriptorRef,
                                                    attributes: CFDictionaryRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateCopyWithFeature(original: CTFontDescriptorRef,
                                                 featureTypeIdentifier: CFNumberRef,
                                                 featureSelectorIdentifier: CFNumberRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateCopyWithVariation(original: CTFontDescriptorRef,
                                                   variationIdentifier: CFNumberRef,
                                                   variationValue: CGFloat) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateMatchingFontDescriptor(descriptor: CTFontDescriptorRef,
                                                        mandatoryAttributes: CFSetRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateWithAttributes(attributes: CFDictionaryRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateWithNameAndSize(name: CFStringRef, size: CGFloat) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorGetTypeID() -> CFTypeID;
}

extern {
    pub fn CTFontDescriptorCreateMatchingFontDescriptors(descriptor: CTFontDescriptorRef,
                                                         mandatoryAttributes: CFSetRef) -> CFArrayRef;
}
<commit_msg>Auto merge of #83 - poiru:font-traits, r=jdm<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_upper_case_globals)]

use core_foundation::array::CFArrayRef;
use core_foundation::base::{CFType, CFTypeID, CFTypeRef, TCFType};
use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
use core_foundation::number::{CFNumber, CFNumberRef};
use core_foundation::set::CFSetRef;
use core_foundation::string::{CFString, CFStringRef};
use core_foundation::url::CFURL;
use core_graphics::base::CGFloat;

use libc::c_void;
use std::mem;

/*
* CTFontTraits.h
*/
// actually, these are extern enums
pub type CTFontFormat = u32;
pub const kCTFontFormatUnrecognized: CTFontFormat = 0;
pub const kCTFontFormatOpenTypePostScript: CTFontFormat = 1;
pub const kCTFontFormatOpenTypeTrueType: CTFontFormat = 2;
pub const kCTFontFormatTrueType: CTFontFormat = 3;
pub const kCTFontFormatPostScript: CTFontFormat = 4;
pub const kCTFontFormatBitmap: CTFontFormat = 5;

pub const kCTFontClassMaskShift: u32 = 28;

pub type CTFontSymbolicTraits = u32;
pub const kCTFontItalicTrait: CTFontSymbolicTraits = (1 << 0);
pub const kCTFontBoldTrait: CTFontSymbolicTraits = (1 << 1);
pub const kCTFontExpandedTrait: CTFontSymbolicTraits = (1 << 5);
pub const kCTFontCondensedTrait: CTFontSymbolicTraits = (1 << 6);
pub const kCTFontMonoSpaceTrait: CTFontSymbolicTraits = (1 << 10);
pub const kCTFontVerticalTrait: CTFontSymbolicTraits = (1 << 11);
pub const kCTFontUIOptimizedTrait: CTFontSymbolicTraits = (1 << 12);
pub const kCTFontColorGlyphsTrait: CTFontSymbolicTraits = (1 << 13);
pub const kCTFontClassMaskTrait: CTFontSymbolicTraits = (15 << kCTFontClassMaskShift );

pub trait SymbolicTraitAccessors {
    fn is_italic(&self) -> bool;
    fn is_bold(&self) -> bool;
    fn is_expanded(&self) -> bool;
    fn is_condensed(&self) -> bool;
    fn is_monospace(&self) -> bool;
}

impl SymbolicTraitAccessors for CTFontSymbolicTraits {
    fn is_italic(&self) -> bool { (*self & kCTFontItalicTrait) != 0 }
    fn is_bold(&self) -> bool { (*self & kCTFontBoldTrait) != 0 }
    fn is_expanded(&self) -> bool { (*self & kCTFontExpandedTrait) != 0 }
    fn is_condensed(&self) -> bool { (*self & kCTFontCondensedTrait) != 0 }
    fn is_monospace(&self) -> bool { (*self & kCTFontMonoSpaceTrait) != 0 }
}

pub type CTFontStylisticClass = u32;
pub const kCTFontUnknownClass: CTFontStylisticClass = (0 << kCTFontClassMaskShift );
pub const kCTFontOldStyleSerifsClass: CTFontStylisticClass = (1 << kCTFontClassMaskShift );
pub const kCTFontTransitionalSerifsClass: CTFontStylisticClass = (2 << kCTFontClassMaskShift );
pub const kCTFontModernSerifsClass: CTFontStylisticClass = (3 << kCTFontClassMaskShift );
pub const kCTFontClarendonSerifsClass: CTFontStylisticClass = (4 << kCTFontClassMaskShift );
pub const kCTFontSlabSerifsClass: CTFontStylisticClass = (5 << kCTFontClassMaskShift );
pub const kCTFontFreeformSerifsClass: CTFontStylisticClass = (7 << kCTFontClassMaskShift );
pub const kCTFontSansSerifClass: CTFontStylisticClass = (8 << kCTFontClassMaskShift );
pub const kCTFontOrnamentalsClass: CTFontStylisticClass = (9 << kCTFontClassMaskShift );
pub const kCTFontScriptsClass: CTFontStylisticClass = (10 << kCTFontClassMaskShift );
pub const kCTFontSymbolicClass: CTFontStylisticClass = (12 << kCTFontClassMaskShift );

pub trait StylisticClassAccessors {
    fn is_serif(&self) -> bool;
    fn is_sans_serif(&self) -> bool;
    fn is_script(&self) -> bool;
    fn is_fantasy(&self) -> bool;
    fn is_symbols(&self) -> bool;
}

impl StylisticClassAccessors for CTFontStylisticClass {
    fn is_serif(&self) -> bool {
        let any_serif_class = kCTFontOldStyleSerifsClass
            | kCTFontTransitionalSerifsClass
            | kCTFontModernSerifsClass
            | kCTFontClarendonSerifsClass
            | kCTFontSlabSerifsClass
            | kCTFontFreeformSerifsClass;

        return (*self & any_serif_class) != 0;
    }

    fn is_sans_serif(&self) -> bool {
        return (*self & kCTFontSansSerifClass) != 0;
    }

    fn is_script(&self) -> bool {
        return (*self & kCTFontScriptsClass) != 0;
    }

    fn is_fantasy(&self) -> bool {
        return (*self & kCTFontOrnamentalsClass) != 0;
    }

    fn is_symbols(&self) -> bool {
        return (*self & kCTFontSymbolicClass) != 0;
    }
}

pub type CTFontAttributes = CFDictionary;

pub type CTFontTraits = CFDictionary;

pub trait TraitAccessors {
    fn symbolic_traits(&self) -> CTFontSymbolicTraits;
    fn normalized_weight(&self) -> f64;
    fn normalized_width(&self) -> f64;
    fn normalized_slant(&self) -> f64;
}

trait TraitAccessorPrivate {
    unsafe fn extract_number_for_key(&self, key: CFStringRef) -> CFNumber;
}

impl TraitAccessorPrivate for CTFontTraits {
    unsafe fn extract_number_for_key(&self, key: CFStringRef) -> CFNumber {
        let cftype = self.get_CFType(mem::transmute(key));
        assert!(cftype.instance_of::<CFNumber>());
        TCFType::wrap_under_get_rule(mem::transmute(cftype.as_CFTypeRef()))
    }

}

impl TraitAccessors for CTFontTraits {
    fn symbolic_traits(&self) -> CTFontSymbolicTraits {
        unsafe {
            let number = self.extract_number_for_key(kCTFontSymbolicTrait);
            number.to_i64().unwrap() as u32
        }
    }

    fn normalized_weight(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontWeightTrait);
            number.to_f64().unwrap()
        }
    }

    fn normalized_width(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontWidthTrait);
            number.to_f64().unwrap()
        }
    }

    fn normalized_slant(&self) -> f64 {
        unsafe {
            let number = self.extract_number_for_key(kCTFontSlantTrait);
            number.to_f64().unwrap()
        }
    }
}

/*
* CTFontDescriptor.h
*/
pub type CTFontOrientation = u32;
pub const kCTFontDefaultOrientation: CTFontOrientation = 0;
pub const kCTFontHorizontalOrientation: CTFontOrientation = 1;
pub const kCTFontVerticalOrientation: CTFontOrientation = 2;

pub type CTFontPriority = u32;
pub const kCTFontPrioritySystem: CTFontPriority = 10000;
pub const kCTFontPriorityNetwork: CTFontPriority = 20000;
pub const kCTFontPriorityComputer: CTFontPriority = 30000;
pub const kCTFontPriorityUser: CTFontPriority = 40000;
pub const kCTFontPriorityDynamic: CTFontPriority = 50000;
pub const kCTFontPriorityProcess: CTFontPriority = 60000;

#[repr(C)]
pub struct __CTFontDescriptor(c_void);

pub type CTFontDescriptorRef = *const __CTFontDescriptor;

declare_TCFType! {
    CTFontDescriptor, CTFontDescriptorRef
}
impl_TCFType!(CTFontDescriptor, CTFontDescriptorRef, CTFontDescriptorGetTypeID);
impl_CFTypeDescription!(CTFontDescriptor);

impl CTFontDescriptor {
    fn get_string_attribute(&self, attribute: CFStringRef) -> Option<String> {
        unsafe {
            let value = CTFontDescriptorCopyAttribute(self.0, attribute);
            if value.is_null() {
                return None
            }

            let value: CFType = TCFType::wrap_under_create_rule(value);
            assert!(value.instance_of::<CFString>());
            let s: CFString = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            Some(s.to_string())
        }
    }

}

impl CTFontDescriptor {
    pub fn family_name(&self) -> String {
        unsafe {
            let value = self.get_string_attribute(kCTFontFamilyNameAttribute);
            value.expect("A font must have a non-null family name.")
        }
    }

    pub fn font_name(&self) -> String {
        unsafe {
            let value = self.get_string_attribute(kCTFontNameAttribute);
            value.expect("A font must have a non-null name.")
        }
    }

    pub fn style_name(&self) -> String {
        unsafe {
            let value = self.get_string_attribute(kCTFontStyleNameAttribute);
            value.expect("A font must have a non-null style name.")
        }
    }

    pub fn display_name(&self) -> String {
        unsafe {
            let value = self.get_string_attribute(kCTFontDisplayNameAttribute);
            value.expect("A font must have a non-null display name.")
        }
    }

    pub fn font_path(&self) -> Option<String> {
        unsafe {
            let value = CTFontDescriptorCopyAttribute(self.0, kCTFontURLAttribute);
            if value.is_null() {
                return None;
            }

            let value: CFType = TCFType::wrap_under_create_rule(value);
            assert!(value.instance_of::<CFURL>());
            let url: CFURL = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            Some(format!("{:?}", url))
        }
    }

    pub fn traits(&self) -> CTFontTraits {
        unsafe {
            let value = CTFontDescriptorCopyAttribute(self.0, kCTFontTraitsAttribute);
            assert!(!value.is_null());
            let value: CFType = TCFType::wrap_under_create_rule(value);
            assert!(value.instance_of::<CFDictionary>());
            let dictionary: CFDictionary = TCFType::wrap_under_get_rule(mem::transmute(value.as_CFTypeRef()));
            dictionary
        }
    }
}

pub fn new_from_attributes(attributes: &CFDictionary) -> CTFontDescriptor {
    unsafe {
        let result: CTFontDescriptorRef =
            CTFontDescriptorCreateWithAttributes(attributes.as_concrete_TypeRef());
        TCFType::wrap_under_create_rule(result)
    }
}

pub fn debug_descriptor(desc: &CTFontDescriptor) {
    println!("family: {}", desc.family_name());
    println!("name: {}", desc.font_name());
    println!("style: {}", desc.style_name());
    println!("display: {}", desc.display_name());
    println!("path: {:?}", desc.font_path());
    desc.show();
}

extern {
    /*
     * CTFontTraits.h
     */

    // font trait constants
    pub static kCTFontSymbolicTrait: CFStringRef;
    pub static kCTFontWeightTrait: CFStringRef;
    pub static kCTFontWidthTrait: CFStringRef;
    pub static kCTFontSlantTrait: CFStringRef;

    /*
     * CTFontDescriptor.h
     */

    // font attribute constants. Note that the name-related attributes
    // here are somewhat flaky. Servo creates CTFont instances and
    // then uses CTFontCopyName to get more fine-grained names.
    pub static kCTFontURLAttribute:                  CFStringRef; // value: CFURLRef
    pub static kCTFontNameAttribute:                 CFStringRef; // value: CFStringRef
    pub static kCTFontDisplayNameAttribute:          CFStringRef; // value: CFStringRef
    pub static kCTFontFamilyNameAttribute:           CFStringRef; // value: CFStringRef
    pub static kCTFontStyleNameAttribute:            CFStringRef; // value: CFStringRef
    pub static kCTFontTraitsAttribute:               CFStringRef;
    pub static kCTFontVariationAttribute:            CFStringRef;
    pub static kCTFontSizeAttribute:                 CFStringRef;
    pub static kCTFontMatrixAttribute:               CFStringRef;
    pub static kCTFontCascadeListAttribute:          CFStringRef;
    pub static kCTFontCharacterSetAttribute:         CFStringRef;
    pub static kCTFontLanguagesAttribute:            CFStringRef;
    pub static kCTFontBaselineAdjustAttribute:       CFStringRef;
    pub static kCTFontMacintoshEncodingsAttribute:   CFStringRef;
    pub static kCTFontFeaturesAttribute:             CFStringRef;
    pub static kCTFontFeatureSettingsAttribute:      CFStringRef;
    pub static kCTFontFixedAdvanceAttribute:         CFStringRef;
    pub static kCTFontOrientationAttribute:          CFStringRef;
    pub static kCTFontFormatAttribute:               CFStringRef;
    pub static kCTFontRegistrationScopeAttribute:    CFStringRef;
    pub static kCTFontPriorityAttribute:             CFStringRef;
    pub static kCTFontEnabledAttribute:              CFStringRef;

    pub fn CTFontDescriptorCopyAttribute(descriptor: CTFontDescriptorRef,
                                         attribute: CFStringRef) -> CFTypeRef;
    pub fn CTFontDescriptorCopyAttributes(descriptor: CTFontDescriptorRef) -> CFDictionaryRef;
    pub fn CTFontDescriptorCopyLocalizedAttribute(descriptor: CTFontDescriptorRef,
                                                  attribute: CFStringRef,
                                                  language: *mut CFStringRef) -> CFTypeRef;
    pub fn CTFontDescriptorCreateCopyWithAttributes(original: CTFontDescriptorRef,
                                                    attributes: CFDictionaryRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateCopyWithFeature(original: CTFontDescriptorRef,
                                                 featureTypeIdentifier: CFNumberRef,
                                                 featureSelectorIdentifier: CFNumberRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateCopyWithVariation(original: CTFontDescriptorRef,
                                                   variationIdentifier: CFNumberRef,
                                                   variationValue: CGFloat) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateMatchingFontDescriptor(descriptor: CTFontDescriptorRef,
                                                        mandatoryAttributes: CFSetRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateWithAttributes(attributes: CFDictionaryRef) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorCreateWithNameAndSize(name: CFStringRef, size: CGFloat) -> CTFontDescriptorRef;
    pub fn CTFontDescriptorGetTypeID() -> CFTypeID;
}

extern {
    pub fn CTFontDescriptorCreateMatchingFontDescriptors(descriptor: CTFontDescriptorRef,
                                                         mandatoryAttributes: CFSetRef) -> CFArrayRef;
}
<|endoftext|>