<commit_before>use bindings::*;
use compilable::Compilable;
use function::ABI;
use libc::c_uint;
use std::kinds::marker::ContravariantLifetime;
use std::str::raw::from_c_str;
use util::NativeRef;
/// The types that a value can be
bitflags!(
	flags TypeKind: i32 {
		static Invalid		= -1,
		static Void			= 0,
		static SByte		= 1,
		static UByte		= 2,
		static Short		= 3,
		static UShort		= 4,
		static Int			= 5,
		static UInt 		= 6,
		static NInt 		= 7,
		static NUInt 		= 8,
		static Long 		= 9,
		static ULong 		= 10,
		static Float32 		= 11,
		static Float64 		= 12,
		static NFloat 		= 13,
		static MaxPrimitive = 13,
		static Struct 		= 14,
		static Union 		= 15,
		static Signature 	= 16,
		static Pointer 		= 17,
		static FirstTagged	= 32,
		static SysBool 		= 10009,
		static SysChar 		= 10010
	}
)
/// A type field iterator
pub struct Fields<'a> {
	_type: jit_type_t,
	index: c_uint,
	marker: ContravariantLifetime<'a>
}
impl<'a> Fields<'a> {
	#[inline]
	fn new(ty:&'a Type) -> Fields<'a> {
		unsafe {
			Fields {
				_type: ty.as_ptr(),
				index: 0 as c_uint,
				marker: ContravariantLifetime::<'a>
			}
		}
	}
}
impl<'a> Iterator<(String, Type)> for Fields<'a> {
	fn next(&mut self) -> Option<(String, Type)> {
		unsafe {
			let index = self.index;
			self.index += 1;
			if index < jit_type_num_fields(self._type) {
				let name = from_c_str(jit_type_get_name(self._type, index));
				let native_field = jit_type_get_field(self._type, index);
				if name.len() == 0 || native_field.is_null() {
					None
				} else {
					let field:Type = NativeRef::from_ptr(native_field);
					Some((name, field))
				}
			} else {
				None
			}
		}
	}
}
/// A type of a value to JIT compile
native_ref!(Type, _type, jit_type_t)
impl Clone for Type {
	#[inline]
	fn clone(&self) -> Type {
		unsafe {
			NativeRef::from_ptr(jit_type_copy(self.as_ptr()))
		}
	}
}
impl Drop for Type {
	#[inline]
	fn drop(&mut self) {
		unsafe {
			jit_type_free(self.as_ptr());
		}
	}
}
impl Type {
	/// Create a function signature, with the given ABI, return type and parameters
	pub fn create_signature(abi: ABI, return_type: &Type, params: &mut [&Type]) -> Type {
		unsafe {
			let mut native_params:Vec<jit_type_t> = params.iter().map(|param| param.as_ptr()).collect();
			let signature = jit_type_create_signature(abi as jit_abi_t, return_type.as_ptr(), native_params.as_mut_ptr(), params.len() as c_uint, 1);
			NativeRef::from_ptr(signature)
		}
	}

	fn create_complex(fields: &mut [&Type], union: bool) -> Type {
		unsafe {
			let mut native_fields:Vec<jit_type_t> = fields.iter().map(|field| field.as_ptr()).collect();
			let f = if union { jit_type_create_union } else { jit_type_create_struct };
			let ty:jit_type_t = f(native_fields.as_mut_ptr(), fields.len() as c_uint, 1);
			NativeRef::from_ptr(ty)
		}
	}
	/// Create a struct type with the given field types
	pub fn create_struct(fields: &mut [&Type]) -> Type {
		Type::create_complex(fields, false)
	}
	/// Create a union type with the given field types
	pub fn create_union(fields: &mut [&Type]) -> Type {
		let inner = Type::create_complex(fields, true);
		Type::create_struct(&mut [&get::<int>(), &inner])
	}
	/// Create a pointer type with the given pointee type
	pub fn create_pointer(pointee: &Type) -> Type {
		unsafe {
			let ptr = jit_type_create_pointer(pointee.as_ptr(), 1);
			NativeRef::from_ptr(ptr)
		}
	}
	/// Work out the size of this type
	pub fn get_size(&self) -> jit_nuint {
		unsafe {
			jit_type_get_size(self.as_ptr())
		}
	}
	/// Get the kind of this type
	pub fn get_kind(&self) -> TypeKind {
		unsafe {
			TypeKind::from_bits(jit_type_get_kind(self.as_ptr())).unwrap()
		}
	}
	/// Get the reference this pointer points to
	pub fn get_ref(&self) -> Type {
		unsafe {
			NativeRef::from_ptr(jit_type_get_ref(self.as_ptr()))
		}
	}
	/// Set the field names of this type
	pub fn set_names(&self, names:&[String]) -> bool {
		unsafe {
			let native_names : Vec<*i8> = names.iter().map(|name| name.to_c_str().unwrap()).collect();
			jit_type_set_names(self.as_ptr(), native_names.as_ptr() as *mut *mut i8, names.len() as u32) != 0
		}
	}
	#[inline]
	/// Iterator over the type's fields
	pub fn iter_fields<'a>(&'a self) -> Fields<'a> {
		Fields::new(self)
	}
	#[inline]
	/// Get a field's index in the struct type
	pub fn find_name<'t>(&self, name:&'t str) -> uint {
		name.with_c_str(|c_name| unsafe {
			jit_type_find_name(self.as_ptr(), c_name) as uint
		})
	}
}
#[test]
fn test_struct() {
	::init();
	let float_t = get::<f64>();
	let double_float_t = Type::create_struct(&mut [&float_t, &float_t]);
	let first_name = "first".into_string();
	let second_name = "second".into_string();
	double_float_t.set_names(&[first_name.clone(), second_name.clone()]);
	assert_eq!(double_float_t.find_name("first"), 0);
	assert_eq!(double_float_t.find_name("second"), 1);
	let mut iter = double_float_t.iter_fields();
	assert!(iter.next() == Some((first_name, float_t.clone())));
	assert!(iter.next() == Some((second_name, float_t)));
}
#[inline]
/// Get the type specified as a JIT type
pub fn get<T:Compilable>() -> Type {
	Compilable::jit_type(None::<T>)
}<commit_msg>Use generics to allow Type::set_names to accept any ToCStr implementor<commit_after>use bindings::*;
use compilable::Compilable;
use function::ABI;
use libc::c_uint;
use std::kinds::marker::ContravariantLifetime;
use std::str::raw::from_c_str;
use std::c_str::ToCStr;
use util::NativeRef;
/// The types that a value can be
bitflags!(
	flags TypeKind: i32 {
		static Invalid		= -1,
		static Void			= 0,
		static SByte		= 1,
		static UByte		= 2,
		static Short		= 3,
		static UShort		= 4,
		static Int			= 5,
		static UInt 		= 6,
		static NInt 		= 7,
		static NUInt 		= 8,
		static Long 		= 9,
		static ULong 		= 10,
		static Float32 		= 11,
		static Float64 		= 12,
		static NFloat 		= 13,
		static MaxPrimitive = 13,
		static Struct 		= 14,
		static Union 		= 15,
		static Signature 	= 16,
		static Pointer 		= 17,
		static FirstTagged	= 32,
		static SysBool 		= 10009,
		static SysChar 		= 10010
	}
)
/// A type field iterator
pub struct Fields<'a> {
	_type: jit_type_t,
	index: c_uint,
	marker: ContravariantLifetime<'a>
}
impl<'a> Fields<'a> {
	#[inline]
	fn new(ty:&'a Type) -> Fields<'a> {
		unsafe {
			Fields {
				_type: ty.as_ptr(),
				index: 0 as c_uint,
				marker: ContravariantLifetime::<'a>
			}
		}
	}
}
impl<'a> Iterator<(String, Type)> for Fields<'a> {
	fn next(&mut self) -> Option<(String, Type)> {
		unsafe {
			let index = self.index;
			self.index += 1;
			if index < jit_type_num_fields(self._type) {
				let name = from_c_str(jit_type_get_name(self._type, index));
				let native_field = jit_type_get_field(self._type, index);
				if name.len() == 0 || native_field.is_null() {
					None
				} else {
					let field:Type = NativeRef::from_ptr(native_field);
					Some((name, field))
				}
			} else {
				None
			}
		}
	}
}
/// A type of a value to JIT compile
native_ref!(Type, _type, jit_type_t)
impl Clone for Type {
	#[inline]
	fn clone(&self) -> Type {
		unsafe {
			NativeRef::from_ptr(jit_type_copy(self.as_ptr()))
		}
	}
}
impl Drop for Type {
	#[inline]
	fn drop(&mut self) {
		unsafe {
			jit_type_free(self.as_ptr());
		}
	}
}
impl Type {
	/// Create a function signature, with the given ABI, return type and parameters
	pub fn create_signature(abi: ABI, return_type: &Type, params: &mut [&Type]) -> Type {
		unsafe {
			let mut native_params:Vec<jit_type_t> = params.iter().map(|param| param.as_ptr()).collect();
			let signature = jit_type_create_signature(abi as jit_abi_t, return_type.as_ptr(), native_params.as_mut_ptr(), params.len() as c_uint, 1);
			NativeRef::from_ptr(signature)
		}
	}

	fn create_complex(fields: &mut [&Type], union: bool) -> Type {
		unsafe {
			let mut native_fields:Vec<jit_type_t> = fields.iter().map(|field| field.as_ptr()).collect();
			let f = if union { jit_type_create_union } else { jit_type_create_struct };
			let ty:jit_type_t = f(native_fields.as_mut_ptr(), fields.len() as c_uint, 1);
			NativeRef::from_ptr(ty)
		}
	}
	/// Create a struct type with the given field types
	pub fn create_struct(fields: &mut [&Type]) -> Type {
		Type::create_complex(fields, false)
	}
	/// Create a union type with the given field types
	pub fn create_union(fields: &mut [&Type]) -> Type {
		let inner = Type::create_complex(fields, true);
		Type::create_struct(&mut [&get::<int>(), &inner])
	}
	/// Create a pointer type with the given pointee type
	pub fn create_pointer(pointee: &Type) -> Type {
		unsafe {
			let ptr = jit_type_create_pointer(pointee.as_ptr(), 1);
			NativeRef::from_ptr(ptr)
		}
	}
	/// Work out the size of this type
	pub fn get_size(&self) -> jit_nuint {
		unsafe {
			jit_type_get_size(self.as_ptr())
		}
	}
	/// Get the kind of this type
	pub fn get_kind(&self) -> TypeKind {
		unsafe {
			TypeKind::from_bits(jit_type_get_kind(self.as_ptr())).unwrap()
		}
	}
	/// Get the reference this pointer points to
	pub fn get_ref(&self) -> Type {
		unsafe {
			NativeRef::from_ptr(jit_type_get_ref(self.as_ptr()))
		}
	}
	/// Set the field names of this type
	pub fn set_names<T:ToCStr>(&self, names:&[T]) -> bool {
		unsafe {
			let native_names : Vec<*i8> = names.iter().map(|name| name.to_c_str().unwrap()).collect();
			jit_type_set_names(self.as_ptr(), native_names.as_ptr() as *mut *mut i8, names.len() as u32) != 0
		}
	}
	#[inline]
	/// Iterator over the type's fields
	pub fn iter_fields<'a>(&'a self) -> Fields<'a> {
		Fields::new(self)
	}
	#[inline]
	/// Get a field's index in the struct type
	pub fn find_name<'t>(&self, name:&'t str) -> uint {
		name.with_c_str(|c_name| unsafe {
			jit_type_find_name(self.as_ptr(), c_name) as uint
		})
	}
}
#[test]
fn test_struct() {
	::init();
	let float_t = get::<f64>();
	let double_float_t = Type::create_struct(&mut [&float_t, &float_t]);
	double_float_t.set_names(&["first", "second"]);
	assert_eq!(double_float_t.find_name("first"), 0);
	assert_eq!(double_float_t.find_name("second"), 1);
	let mut iter = double_float_t.iter_fields();
	assert!(iter.next() == Some(("first".into_string(), float_t.clone())));
	assert!(iter.next() == Some(("second".into_string(), float_t)));
}
#[inline]
/// Get the type specified as a JIT type
pub fn get<T:Compilable>() -> Type {
	Compilable::jit_type(None::<T>)
}<|endoftext|>


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

//! The fixed-size array type (`[T; n]`).
//!
//! Some usage examples:
//!
//! ```
//! let array: [i32; 3] = [0, 1, 2];
//!
//! assert_eq!(0, array[0]);
//! assert_eq!([0, 1], &array[..2]);
//!
//! for x in &array {
//!     println!("{}", x);
//! }
//! ```

#![doc(primitive = "array")]
<commit_msg>Auto merge of #26923 - bluss:doc-array, r=alexcrichton<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A fixed-size array is denoted `[T; N]` for the element type `T` and
//! the compile time constant size `N`. The size should be zero or positive.
//!
//! Arrays values are created either with an explicit expression that lists
//! each element: `[x, y, z]` or a repeat expression: `[x; N]`. The repeat
//! expression requires that the element type is `Copy`.
//!
//! The type `[T; N]` is `Copy` if `T: Copy`.
//!
//! Arrays of sizes from 0 to 32 (inclusive) implement the following traits
//! if the element type allows it:
//!
//! - `Clone`
//! - `Debug`
//! - `IntoIterator` (implemented for `&[T; N]` and `&mut [T; N]`)
//! - `PartialEq`, `PartialOrd`, `Ord`, `Eq`
//! - `Hash`
//! - `AsRef`, `AsMut`
//!
//! Arrays dereference to [slices (`[T]`)][slice], so their methods can be called
//! on arrays.
//!
//! [slice]: primitive.slice.html
//!
//! ## Examples
//!
//! ```
//! let mut array: [i32; 3] = [0; 3];
//!
//! array[1] = 1;
//! array[2] = 2;
//!
//! assert_eq!([1, 2], &array[1..]);
//!
//! // This loop prints: 0 1 2
//! for x in &array {
//!     print!("{} ", x);
//! }
//!
//! ```
//!
//! Rust does not currently support generics over the size of an array type.
//!

#![doc(primitive = "array")]
<|endoftext|>


<commit_before>use nix::sys::uio::*;
use nix::unistd::*;
use rand::{thread_rng, Rng};
use rand::distributions::Alphanumeric;
use std::{cmp, iter};
use std::fs::{OpenOptions};
use std::io::IoSlice;
use std::os::unix::io::AsRawFd;

#[cfg(not(target_os = "redox"))]
use std::io::IoSliceMut;

#[cfg(not(target_os = "redox"))]
use tempfile::tempfile;
use tempfile::tempdir;

#[test]
fn test_writev() {
    let mut to_write = Vec::with_capacity(16 * 128);
    for _ in 0..16 {
        let s: String = thread_rng()
            .sample_iter(&Alphanumeric)
            .map(char::from)
            .take(128)
            .collect();
        let b = s.as_bytes();
        to_write.extend(b.iter().cloned());
    }
    // Allocate and fill iovecs
    let mut iovecs = Vec::new();
    let mut consumed = 0;
    while consumed < to_write.len() {
        let left = to_write.len() - consumed;
        let slice_len = if left <= 64 { left } else { thread_rng().gen_range(64..cmp::min(256, left)) };
        let b = &to_write[consumed..consumed+slice_len];
        iovecs.push(IoSlice::new(b));
        consumed += slice_len;
    }
    let pipe_res = pipe();
    assert!(pipe_res.is_ok());
    let (reader, writer) = pipe_res.ok().unwrap();
    // FileDesc will close its filedesc (reader).
    let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect();
    // Blocking io, should write all data.
    let write_res = writev(writer, &iovecs);
    // Successful write
    assert!(write_res.is_ok());
    let written = write_res.ok().unwrap();
    // Check whether we written all data
    assert_eq!(to_write.len(), written);
    let read_res = read(reader, &mut read_buf[..]);
    // Successful read
    assert!(read_res.is_ok());
    let read = read_res.ok().unwrap() as usize;
    // Check we have read as much as we written
    assert_eq!(read, written);
    // Check equality of written and read data
    assert_eq!(&to_write, &read_buf);
    let close_res = close(writer);
    assert!(close_res.is_ok());
    let close_res = close(reader);
    assert!(close_res.is_ok());
}

#[test]
#[cfg(not(target_os = "redox"))]
fn test_readv() {
    let s:String = thread_rng()
        .sample_iter(&Alphanumeric)
        .map(char::from)
        .take(128)
        .collect();
    let to_write = s.as_bytes().to_vec();
    let mut storage = Vec::new();
    let mut allocated = 0;
    while allocated < to_write.len() {
        let left = to_write.len() - allocated;
        let vec_len = if left <= 64 { left } else { thread_rng().gen_range(64..cmp::min(256, left)) };
        let v: Vec<u8> = iter::repeat(0u8).take(vec_len).collect();
        storage.push(v);
        allocated += vec_len;
    }
    let mut iovecs = Vec::with_capacity(storage.len());
    for v in &mut storage {
        iovecs.push(IoSliceMut::new(&mut v[..]));
    }
    let pipe_res = pipe();
    assert!(pipe_res.is_ok());
    let (reader, writer) = pipe_res.ok().unwrap();
    // Blocking io, should write all data.
    let write_res = write(writer, &to_write);
    // Successful write
    assert!(write_res.is_ok());
    let read_res = readv(reader, &mut iovecs[..]);
    assert!(read_res.is_ok());
    let read = read_res.ok().unwrap();
    // Check whether we've read all data
    assert_eq!(to_write.len(), read);
    // Cccumulate data from iovecs
    let mut read_buf = Vec::with_capacity(to_write.len());
    for iovec in &iovecs {
        read_buf.extend(iovec.iter().cloned());
    }
    // Check whether iovecs contain all written data
    assert_eq!(read_buf.len(), to_write.len());
    // Check equality of written and read data
    assert_eq!(&read_buf, &to_write);
    let close_res = close(reader);
    assert!(close_res.is_ok());
    let close_res = close(writer);
    assert!(close_res.is_ok());
}

#[test]
#[cfg(not(target_os = "redox"))]
fn test_pwrite() {
    use std::io::Read;

    let mut file = tempfile().unwrap();
    let buf = [1u8;8];
    assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8));
    let mut file_content = Vec::new();
    file.read_to_end(&mut file_content).unwrap();
    let mut expected = vec![0u8;8];
    expected.extend(vec![1;8]);
    assert_eq!(file_content, expected);
}

#[test]
fn test_pread() {
    use std::io::Write;

    let tempdir = tempdir().unwrap();

    let path = tempdir.path().join("pread_test_file");
    let mut file = OpenOptions::new().write(true).read(true).create(true)
                                    .truncate(true).open(path).unwrap();
    let file_content: Vec<u8> = (0..64).collect();
    file.write_all(&file_content).unwrap();

    let mut buf = [0u8;16];
    assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16));
    let expected: Vec<_> = (16..32).collect();
    assert_eq!(&buf[..], &expected[..]);
}

#[test]
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
fn test_pwritev() {
    use std::io::Read;

    let to_write: Vec<u8> = (0..128).collect();
    let expected: Vec<u8> = [vec![0;100], to_write.clone()].concat();

    let iovecs = [
        IoSlice::new(&to_write[0..17]),
        IoSlice::new(&to_write[17..64]),
        IoSlice::new(&to_write[64..128]),
    ];

    let tempdir = tempdir().unwrap();

    // pwritev them into a temporary file
    let path = tempdir.path().join("pwritev_test_file");
    let mut file = OpenOptions::new().write(true).read(true).create(true)
                                    .truncate(true).open(path).unwrap();

    let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap();
    assert_eq!(written, to_write.len());

    // Read the data back and make sure it matches
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(contents, expected);
}

#[test]
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
fn test_preadv() {
    use std::io::Write;

    let to_write: Vec<u8> = (0..200).collect();
    let expected: Vec<u8> = (100..200).collect();

    let tempdir = tempdir().unwrap();

    let path = tempdir.path().join("preadv_test_file");

    let mut file = OpenOptions::new().read(true).write(true).create(true)
                                    .truncate(true).open(path).unwrap();
    file.write_all(&to_write).unwrap();

    let mut buffers: Vec<Vec<u8>> = vec![
        vec![0; 24],
        vec![0; 1],
        vec![0; 75],
    ];

    {
        // Borrow the buffers into IoVecs and preadv into them
        let mut iovecs: Vec<_> = buffers.iter_mut().map(
            |buf| IoSliceMut::new(&mut buf[..])).collect();
        assert_eq!(Ok(100), preadv(file.as_raw_fd(), &mut iovecs, 100));
    }

    let all = buffers.concat();
    assert_eq!(all, expected);
}

#[test]
#[cfg(all(target_os = "linux", not(target_env = "uclibc")))] // uclibc doesn't implement process_vm_readv
// qemu-user doesn't implement process_vm_readv/writev on most arches
#[cfg_attr(qemu, ignore)]
fn test_process_vm_readv() {
    use nix::unistd::ForkResult::*;
    use nix::sys::signal::*;
    use nix::sys::wait::*;
    use crate::*;

    require_capability!("test_process_vm_readv", CAP_SYS_PTRACE);
    let _m = crate::FORK_MTX.lock();

    // Pre-allocate memory in the child, since allocation isn't safe
    // post-fork (~= async-signal-safe)
    let mut vector = vec![1u8, 2, 3, 4, 5];

    let (r, w) = pipe().unwrap();
    match unsafe{fork()}.expect("Error: Fork Failed") {
        Parent { child } => {
            close(w).unwrap();
            // wait for child
            read(r, &mut [0u8]).unwrap();
            close(r).unwrap();

            let ptr = vector.as_ptr() as usize;
            let remote_iov = RemoteIoVec { base: ptr, len: 5 };
            let mut buf = vec![0u8; 5];

            let ret = process_vm_readv(child,
                                       &mut [IoSliceMut::new(&mut buf)],
                                       &[remote_iov]);

            kill(child, SIGTERM).unwrap();
            waitpid(child, None).unwrap();

            assert_eq!(Ok(5), ret);
            assert_eq!(20u8, buf.iter().sum());
        },
        Child => {
            let _ = close(r);
            for i in &mut vector {
                *i += 1;
            }
            let _ = write(w, b"\0");
            let _ = close(w);
            loop { let _ = pause(); }
        },
    }
}
<commit_msg>Fix nightly clippy in tests<commit_after>use nix::sys::uio::*;
use nix::unistd::*;
use rand::{thread_rng, Rng};
use rand::distributions::Alphanumeric;
use std::{cmp, iter};
use std::fs::{OpenOptions};
use std::io::IoSlice;
use std::os::unix::io::AsRawFd;

#[cfg(not(target_os = "redox"))]
use std::io::IoSliceMut;

#[cfg(not(target_os = "redox"))]
use tempfile::tempfile;
use tempfile::tempdir;

#[test]
fn test_writev() {
    let mut to_write = Vec::with_capacity(16 * 128);
    for _ in 0..16 {
        let s: String = thread_rng()
            .sample_iter(&Alphanumeric)
            .map(char::from)
            .take(128)
            .collect();
        let b = s.as_bytes();
        to_write.extend(b.iter().cloned());
    }
    // Allocate and fill iovecs
    let mut iovecs = Vec::new();
    let mut consumed = 0;
    while consumed < to_write.len() {
        let left = to_write.len() - consumed;
        let slice_len = if left <= 64 { left } else { thread_rng().gen_range(64..cmp::min(256, left)) };
        let b = &to_write[consumed..consumed+slice_len];
        iovecs.push(IoSlice::new(b));
        consumed += slice_len;
    }
    let pipe_res = pipe();
    assert!(pipe_res.is_ok());
    let (reader, writer) = pipe_res.ok().unwrap();
    // FileDesc will close its filedesc (reader).
    let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect();
    // Blocking io, should write all data.
    let write_res = writev(writer, &iovecs);
    // Successful write
    assert!(write_res.is_ok());
    let written = write_res.ok().unwrap();
    // Check whether we written all data
    assert_eq!(to_write.len(), written);
    let read_res = read(reader, &mut read_buf[..]);
    // Successful read
    assert!(read_res.is_ok());
    let read = read_res.ok().unwrap() as usize;
    // Check we have read as much as we written
    assert_eq!(read, written);
    // Check equality of written and read data
    assert_eq!(&to_write, &read_buf);
    let close_res = close(writer);
    assert!(close_res.is_ok());
    let close_res = close(reader);
    assert!(close_res.is_ok());
}

#[test]
#[cfg(not(target_os = "redox"))]
fn test_readv() {
    let s:String = thread_rng()
        .sample_iter(&Alphanumeric)
        .map(char::from)
        .take(128)
        .collect();
    let to_write = s.as_bytes().to_vec();
    let mut storage = Vec::new();
    let mut allocated = 0;
    while allocated < to_write.len() {
        let left = to_write.len() - allocated;
        let vec_len = if left <= 64 { left } else { thread_rng().gen_range(64..cmp::min(256, left)) };
        let v: Vec<u8> = iter::repeat(0u8).take(vec_len).collect();
        storage.push(v);
        allocated += vec_len;
    }
    let mut iovecs = Vec::with_capacity(storage.len());
    for v in &mut storage {
        iovecs.push(IoSliceMut::new(&mut v[..]));
    }
    let pipe_res = pipe();
    assert!(pipe_res.is_ok());
    let (reader, writer) = pipe_res.ok().unwrap();
    // Blocking io, should write all data.
    let write_res = write(writer, &to_write);
    // Successful write
    assert!(write_res.is_ok());
    let read_res = readv(reader, &mut iovecs[..]);
    assert!(read_res.is_ok());
    let read = read_res.ok().unwrap();
    // Check whether we've read all data
    assert_eq!(to_write.len(), read);
    // Cccumulate data from iovecs
    let mut read_buf = Vec::with_capacity(to_write.len());
    for iovec in &iovecs {
        read_buf.extend(iovec.iter().cloned());
    }
    // Check whether iovecs contain all written data
    assert_eq!(read_buf.len(), to_write.len());
    // Check equality of written and read data
    assert_eq!(&read_buf, &to_write);
    let close_res = close(reader);
    assert!(close_res.is_ok());
    let close_res = close(writer);
    assert!(close_res.is_ok());
}

#[test]
#[cfg(not(target_os = "redox"))]
fn test_pwrite() {
    use std::io::Read;

    let mut file = tempfile().unwrap();
    let buf = [1u8;8];
    assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8));
    let mut file_content = Vec::new();
    file.read_to_end(&mut file_content).unwrap();
    let mut expected = vec![0u8;8];
    expected.extend(vec![1;8]);
    assert_eq!(file_content, expected);
}

#[test]
fn test_pread() {
    use std::io::Write;

    let tempdir = tempdir().unwrap();

    let path = tempdir.path().join("pread_test_file");
    let mut file = OpenOptions::new().write(true).read(true).create(true)
                                    .truncate(true).open(path).unwrap();
    let file_content: Vec<u8> = (0..64).collect();
    file.write_all(&file_content).unwrap();

    let mut buf = [0u8;16];
    assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16));
    let expected: Vec<_> = (16..32).collect();
    assert_eq!(&buf[..], &expected[..]);
}

#[test]
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
fn test_pwritev() {
    use std::io::Read;

    let to_write: Vec<u8> = (0..128).collect();
    let expected: Vec<u8> = [vec![0;100], to_write.clone()].concat();

    let iovecs = [
        IoSlice::new(&to_write[0..17]),
        IoSlice::new(&to_write[17..64]),
        IoSlice::new(&to_write[64..128]),
    ];

    let tempdir = tempdir().unwrap();

    // pwritev them into a temporary file
    let path = tempdir.path().join("pwritev_test_file");
    let mut file = OpenOptions::new().write(true).read(true).create(true)
                                    .truncate(true).open(path).unwrap();

    let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap();
    assert_eq!(written, to_write.len());

    // Read the data back and make sure it matches
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(contents, expected);
}

#[test]
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
fn test_preadv() {
    use std::io::Write;

    let to_write: Vec<u8> = (0..200).collect();
    let expected: Vec<u8> = (100..200).collect();

    let tempdir = tempdir().unwrap();

    let path = tempdir.path().join("preadv_test_file");

    let mut file = OpenOptions::new().read(true).write(true).create(true)
                                    .truncate(true).open(path).unwrap();
    file.write_all(&to_write).unwrap();

    let mut buffers: Vec<Vec<u8>> = vec![
        vec![0; 24],
        vec![0; 1],
        vec![0; 75],
    ];

    {
        // Borrow the buffers into IoVecs and preadv into them
        let mut iovecs: Vec<_> = buffers.iter_mut().map(
            |buf| IoSliceMut::new(&mut buf[..])).collect();
        assert_eq!(Ok(100), preadv(file.as_raw_fd(), &mut iovecs, 100));
    }

    let all = buffers.concat();
    assert_eq!(all, expected);
}

#[test]
#[cfg(all(target_os = "linux", not(target_env = "uclibc")))] // uclibc doesn't implement process_vm_readv
// qemu-user doesn't implement process_vm_readv/writev on most arches
#[cfg_attr(qemu, ignore)]
fn test_process_vm_readv() {
    use nix::unistd::ForkResult::*;
    use nix::sys::signal::*;
    use nix::sys::wait::*;
    use crate::*;

    require_capability!("test_process_vm_readv", CAP_SYS_PTRACE);
    let _m = crate::FORK_MTX.lock();

    // Pre-allocate memory in the child, since allocation isn't safe
    // post-fork (~= async-signal-safe)
    let mut vector = vec![1u8, 2, 3, 4, 5];

    let (r, w) = pipe().unwrap();
    match unsafe{fork()}.expect("Error: Fork Failed") {
        Parent { child } => {
            close(w).unwrap();
            // wait for child
            read(r, &mut [0u8]).unwrap();
            close(r).unwrap();

            let ptr = vector.as_ptr() as usize;
            let remote_iov = RemoteIoVec { base: ptr, len: 5 };
            let mut buf = vec![0u8; 5];

            let ret = process_vm_readv(child,
                                       &mut [IoSliceMut::new(&mut buf)],
                                       &[remote_iov]);

            kill(child, SIGTERM).unwrap();
            waitpid(child, None).unwrap();

            assert_eq!(Ok(5), ret);
            assert_eq!(20u8, buf.iter().sum());
        },
        Child => {
            let _ = close(r);
            for i in &mut vector {
                *i += 1;
            }
            let _ = write(w, b"\0");
            let _ = close(w);
            loop { pause(); }
        },
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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 super::*;

use cocoa::foundation::NSUInteger;
use foreign_types::ForeignType;
use objc::runtime::{Object, NO, YES};
use std::ffi::CStr;

pub enum MTLVertexAttribute {}

foreign_obj_type! {
    type CType = MTLVertexAttribute;
    pub struct VertexAttribute;
    pub struct VertexAttributeRef;
}

impl VertexAttributeRef {
    pub fn name(&self) -> &str {
        unsafe {
            let name = msg_send![self, name];
            crate::nsstring_as_str(name)
        }
    }

    pub fn attribute_index(&self) -> u64 {
        unsafe { msg_send![self, attributeIndex] }
    }

    pub fn attribute_type(&self) -> MTLDataType {
        unsafe { msg_send![self, attributeType] }
    }

    pub fn is_active(&self) -> bool {
        unsafe {
            match msg_send![self, isActive] {
                YES => true,
                NO => false,
                _ => unreachable!(),
            }
        }
    }
}

#[repr(u64)]
#[derive(Debug)]
pub enum MTLFunctionType {
    Vertex = 1,
    Fragment = 2,
    Kernel = 3,
}

pub enum MTLFunction {}

foreign_obj_type! {
    type CType = MTLFunction;
    pub struct Function;
    pub struct FunctionRef;
}

impl FunctionRef {
    pub fn name(&self) -> &str {
        unsafe {
            let name = msg_send![self, name];
            crate::nsstring_as_str(name)
        }
    }

    pub fn function_type(&self) -> MTLFunctionType {
        unsafe { msg_send![self, functionType] }
    }

    pub fn vertex_attributes(&self) -> &Array<VertexAttribute> {
        unsafe { msg_send![self, vertexAttributes] }
    }

    pub fn new_argument_encoder(&self, buffer_index: NSUInteger) -> ArgumentEncoder {
        unsafe {
            let ptr = msg_send![self, newArgumentEncoderWithBufferIndex: buffer_index];
            ArgumentEncoder::from_ptr(ptr)
        }
    }

    pub fn function_constants_dictionary(&self) -> *mut Object {
        unsafe { msg_send![self, functionConstantsDictionary] }
    }
}

#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum MTLLanguageVersion {
    V1_0 = 0x10000,
    V1_1 = 0x10001,
    V1_2 = 0x10002,
    V2_0 = 0x20000,
    V2_1 = 0x20001,
}

pub enum MTLFunctionConstantValues {}

foreign_obj_type! {
    type CType = MTLFunctionConstantValues;
    pub struct FunctionConstantValues;
    pub struct FunctionConstantValuesRef;
}

impl FunctionConstantValues {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLFunctionConstantValues);
            msg_send![class, new]
        }
    }
}

impl FunctionConstantValuesRef {
    pub unsafe fn set_constant_value_at_index(
        &self,
        index: NSUInteger,
        ty: MTLDataType,
        value: *const std::os::raw::c_void,
    ) {
        msg_send![self, setConstantValue:value type:ty atIndex:index]
    }
}

pub enum MTLCompileOptions {}

foreign_obj_type! {
    type CType = MTLCompileOptions;
    pub struct CompileOptions;
    pub struct CompileOptionsRef;
}

impl CompileOptions {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLCompileOptions);
            msg_send![class, new]
        }
    }
}

impl CompileOptionsRef {
    pub unsafe fn preprocessor_defines(&self) -> *mut Object {
        msg_send![self, preprocessorMacros]
    }

    pub unsafe fn set_preprocessor_defines(&self, defines: *mut Object) {
        msg_send![self, setPreprocessorMacros: defines]
    }

    pub fn is_fast_math_enabled(&self) -> bool {
        unsafe {
            match msg_send![self, fastMathEnabled] {
                YES => true,
                NO => false,
                _ => unreachable!(),
            }
        }
    }

    pub fn set_fast_math_enabled(&self, enabled: bool) {
        unsafe { msg_send![self, setFastMathEnabled: enabled] }
    }

    pub fn language_version(&self) -> MTLLanguageVersion {
        unsafe { msg_send![self, languageVersion] }
    }

    pub fn set_language_version(&self, version: MTLLanguageVersion) {
        unsafe { msg_send![self, setLanguageVersion: version] }
    }
}

#[repr(u64)]
#[allow(non_camel_case_types)]
pub enum MTLLibraryError {
    Unsupported = 1,
    Internal = 2,
    CompileFailure = 3,
    CompileWarning = 4,
}

pub enum MTLLibrary {}

foreign_obj_type! {
    type CType = MTLLibrary;
    pub struct Library;
    pub struct LibraryRef;
}

impl LibraryRef {
    pub fn label(&self) -> &str {
        unsafe {
            let label = msg_send![self, label];
            crate::nsstring_as_str(label)
        }
    }

    pub fn set_label(&self, label: &str) {
        unsafe {
            let nslabel = crate::nsstring_from_str(label);
            let () = msg_send![self, setLabel: nslabel];
        }
    }

    pub fn get_function(
        &self,
        name: &str,
        constants: Option<FunctionConstantValues>,
    ) -> Result<Function, String> {
        unsafe {
            let nsname = crate::nsstring_from_str(name);

            let function: *mut MTLFunction = match constants {
                Some(c) => try_objc! { err => msg_send![self,
                    newFunctionWithName: nsname.as_ref()
                    constantValues: c.as_ref()
                    error: &mut err
                ]},
                None => msg_send![self, newFunctionWithName: nsname.as_ref()],
            };

            if !function.is_null() {
                Ok(Function::from_ptr(function))
            } else {
                Err(format!("Function '{}' does not exist", name))
            }
        }
    }

    pub fn function_names(&self) -> *const objc::runtime::Object {
        unsafe { msg_send![self, functionNames] }
    }
}
<commit_msg>Change `Library::function_names` to return `Vec<String>`<commit_after>// Copyright 2017 GFX developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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 super::*;

use cocoa::foundation::NSUInteger;
use foreign_types::ForeignType;
use objc::runtime::{Object, NO, YES};
use std::ffi::CStr;

pub enum MTLVertexAttribute {}

foreign_obj_type! {
    type CType = MTLVertexAttribute;
    pub struct VertexAttribute;
    pub struct VertexAttributeRef;
}

impl VertexAttributeRef {
    pub fn name(&self) -> &str {
        unsafe {
            let name = msg_send![self, name];
            crate::nsstring_as_str(name)
        }
    }

    pub fn attribute_index(&self) -> u64 {
        unsafe { msg_send![self, attributeIndex] }
    }

    pub fn attribute_type(&self) -> MTLDataType {
        unsafe { msg_send![self, attributeType] }
    }

    pub fn is_active(&self) -> bool {
        unsafe {
            match msg_send![self, isActive] {
                YES => true,
                NO => false,
                _ => unreachable!(),
            }
        }
    }
}

#[repr(u64)]
#[derive(Debug)]
pub enum MTLFunctionType {
    Vertex = 1,
    Fragment = 2,
    Kernel = 3,
}

pub enum MTLFunction {}

foreign_obj_type! {
    type CType = MTLFunction;
    pub struct Function;
    pub struct FunctionRef;
}

impl FunctionRef {
    pub fn name(&self) -> &str {
        unsafe {
            let name = msg_send![self, name];
            crate::nsstring_as_str(name)
        }
    }

    pub fn function_type(&self) -> MTLFunctionType {
        unsafe { msg_send![self, functionType] }
    }

    pub fn vertex_attributes(&self) -> &Array<VertexAttribute> {
        unsafe { msg_send![self, vertexAttributes] }
    }

    pub fn new_argument_encoder(&self, buffer_index: NSUInteger) -> ArgumentEncoder {
        unsafe {
            let ptr = msg_send![self, newArgumentEncoderWithBufferIndex: buffer_index];
            ArgumentEncoder::from_ptr(ptr)
        }
    }

    pub fn function_constants_dictionary(&self) -> *mut Object {
        unsafe { msg_send![self, functionConstantsDictionary] }
    }
}

#[repr(u64)]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum MTLLanguageVersion {
    V1_0 = 0x10000,
    V1_1 = 0x10001,
    V1_2 = 0x10002,
    V2_0 = 0x20000,
    V2_1 = 0x20001,
}

pub enum MTLFunctionConstantValues {}

foreign_obj_type! {
    type CType = MTLFunctionConstantValues;
    pub struct FunctionConstantValues;
    pub struct FunctionConstantValuesRef;
}

impl FunctionConstantValues {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLFunctionConstantValues);
            msg_send![class, new]
        }
    }
}

impl FunctionConstantValuesRef {
    pub unsafe fn set_constant_value_at_index(
        &self,
        index: NSUInteger,
        ty: MTLDataType,
        value: *const std::os::raw::c_void,
    ) {
        msg_send![self, setConstantValue:value type:ty atIndex:index]
    }
}

pub enum MTLCompileOptions {}

foreign_obj_type! {
    type CType = MTLCompileOptions;
    pub struct CompileOptions;
    pub struct CompileOptionsRef;
}

impl CompileOptions {
    pub fn new() -> Self {
        unsafe {
            let class = class!(MTLCompileOptions);
            msg_send![class, new]
        }
    }
}

impl CompileOptionsRef {
    pub unsafe fn preprocessor_defines(&self) -> *mut Object {
        msg_send![self, preprocessorMacros]
    }

    pub unsafe fn set_preprocessor_defines(&self, defines: *mut Object) {
        msg_send![self, setPreprocessorMacros: defines]
    }

    pub fn is_fast_math_enabled(&self) -> bool {
        unsafe {
            match msg_send![self, fastMathEnabled] {
                YES => true,
                NO => false,
                _ => unreachable!(),
            }
        }
    }

    pub fn set_fast_math_enabled(&self, enabled: bool) {
        unsafe { msg_send![self, setFastMathEnabled: enabled] }
    }

    pub fn language_version(&self) -> MTLLanguageVersion {
        unsafe { msg_send![self, languageVersion] }
    }

    pub fn set_language_version(&self, version: MTLLanguageVersion) {
        unsafe { msg_send![self, setLanguageVersion: version] }
    }
}

#[repr(u64)]
#[allow(non_camel_case_types)]
pub enum MTLLibraryError {
    Unsupported = 1,
    Internal = 2,
    CompileFailure = 3,
    CompileWarning = 4,
}

pub enum MTLLibrary {}

foreign_obj_type! {
    type CType = MTLLibrary;
    pub struct Library;
    pub struct LibraryRef;
}

impl LibraryRef {
    pub fn label(&self) -> &str {
        unsafe {
            let label = msg_send![self, label];
            crate::nsstring_as_str(label)
        }
    }

    pub fn set_label(&self, label: &str) {
        unsafe {
            let nslabel = crate::nsstring_from_str(label);
            let () = msg_send![self, setLabel: nslabel];
        }
    }

    pub fn get_function(
        &self,
        name: &str,
        constants: Option<FunctionConstantValues>,
    ) -> Result<Function, String> {
        unsafe {
            let nsname = crate::nsstring_from_str(name);

            let function: *mut MTLFunction = match constants {
                Some(c) => try_objc! { err => msg_send![self,
                    newFunctionWithName: nsname.as_ref()
                    constantValues: c.as_ref()
                    error: &mut err
                ]},
                None => msg_send![self, newFunctionWithName: nsname.as_ref()],
            };

            if !function.is_null() {
                Ok(Function::from_ptr(function))
            } else {
                Err(format!("Function '{}' does not exist", name))
            }
        }
    }

    pub fn function_names(&self) -> Vec<String> {
        unsafe {
            let names: *mut Object = msg_send![self, functionNames];
            let count: NSUInteger = msg_send![names, count];
            let ret = (0..count)
                .map(|i| {
                    let name = msg_send![names, objectAtIndex: i];
                    nsstring_as_str(name).to_string()
                })
                .collect();
            let () = msg_send![names, release];
            ret
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::Write;
use std::os::raw::c_uchar;
use std::process;
use mustache;
use mustache::MapBuilder;

use client::ClientW;
use config::Config;
use util;
use workspace::Workspace;

pub struct LoggerConfig {
    client_template: mustache::Template,
    client_selected_template: mustache::Template,
    client_title_length: usize,
    separator: &'static str,
    tag_template: mustache::Template,
    tag_selected_template: mustache::Template,
}

impl LoggerConfig {
    pub fn client_template(mut self, template: &str) -> Self {
        self.client_template = mustache::compile_str(template).unwrap();
        self
    }

    pub fn client_selected_template(mut self, template: &str) -> Self {
        self.client_selected_template = mustache::compile_str(template).unwrap();
        self
    }

    pub fn client_title_length(mut self, len: usize) -> Self {
        self.client_title_length = len;
        self
    }

    pub fn separator(mut self, s: &'static str) -> Self {
        self.separator = s;
        self
    }

    pub fn tag_template(mut self, template: &str) -> Self {
        self.tag_template = mustache::compile_str(template).unwrap();
        self
    }

    pub fn tag_selected_template(mut self, template: &str) -> Self {
        self.tag_selected_template = mustache::compile_str(template).unwrap();
        self
    }
}

impl Default for LoggerConfig {
    fn default() -> Self {
        LoggerConfig {
            client_template: mustache::compile_str("[{{& content }}] ").unwrap(),
            client_selected_template: mustache::compile_str("[<fc=#FFFF00>{{& content }}</fc>] ")
                .unwrap(),
            client_title_length: 8,
            separator: " :: ",
            tag_template: mustache::compile_str("{{& content }}").unwrap(),
            tag_selected_template: mustache::compile_str("<fc=#00FF00>{{& content }}</fc> |")
                .unwrap(),
        }
    }
}

pub trait Logger {
    fn dump(&mut self,
            global_config: &Config,
            workspaces: &HashMap<c_uchar, Workspace>,
            clients: &Vec<ClientW>,
            current_tag: c_uchar,
            current_clients: &Vec<ClientW>,
            focused: Option<ClientW>);
}

pub struct DummyLogger;

impl DummyLogger {
    #[allow(unused_variables)]
    pub fn new(config: LoggerConfig) -> Self {
        DummyLogger
    }
}

impl Logger for DummyLogger {
    #[allow(unused_variables)]
    fn dump(&mut self,
            global_config: &Config,
            workspaces: &HashMap<c_uchar, Workspace>,
            clients: &Vec<ClientW>,
            current_tag: c_uchar,
            current_clients: &Vec<ClientW>,
            focused: Option<ClientW>) {
        // Do nothing.
    }
}

pub struct XMobarLogger {
    config: LoggerConfig,
    child_stdin: process::ChildStdin,
}

impl XMobarLogger {
    pub fn new(config: LoggerConfig, xmobar_args: &[&str]) -> Self {
        let process::Child { stdin: child_stdin, .. } = process::Command::new("xmobar")
            .stdin(process::Stdio::piped())
            .args(xmobar_args)
            .spawn()
            .expect("cannot spawn xmobar");
        XMobarLogger {
            config: config,
            child_stdin: child_stdin.unwrap(),
        }
    }
}

impl Logger for XMobarLogger {
    fn dump(&mut self,
            global_config: &Config,
            workspaces: &HashMap<c_uchar, Workspace>,
            clients: &Vec<ClientW>,
            current_tag: c_uchar,
            current_clients: &Vec<ClientW>,
            focused: Option<ClientW>) {
        fn render<W: Write, T1: Into<String>, T2: Into<String>>(w: &mut W,
                                                                template: &mustache::Template,
                                                                to_render: T1,
                                                                tag: T2) {
            let content = mustache::MapBuilder::new()
                .insert_str("content", to_render.into())
                .insert_str("tag", tag.into())
                .build();
            template.render_data(w, &content).unwrap();
        }

        let mut tags: Vec<char> = clients.iter().map(|c| c.tag() as char).collect();
        tags.push(current_tag as char);
        tags.sort();
        tags.dedup();
        for t in &tags {
            let selected_template = if *t == current_tag as char {
                &self.config.tag_selected_template
            } else {
                &self.config.tag_template
            };
            if current_tag == 0 {
                render(&mut self.child_stdin,
                       selected_template,
                       "Overview",
                       t.to_string());
            } else {
                let string = if let Some(description) =
                    workspaces.get(&(*t as c_uchar)).unwrap().get_description() {
                    format!("{} - {}", t, description)
                } else {
                    (*t).to_string()
                };
                render(&mut self.child_stdin,
                       selected_template,
                       string,
                       t.to_string());
            }
        }
        write!(self.child_stdin, "{}", self.config.separator);
        for i in 0..current_clients.len() {
            let c = &current_clients[i];
            let selected_template = match focused.as_ref() {
                Some(c_focused) if c_focused.window() == c.window() => {
                    &self.config.client_selected_template
                }
                _ => &self.config.client_template,
            };
            let msg = if current_tag == 0 {
                format!("{}@", c.tag() as char)
            } else {
                "".to_string()
            };
            render(&mut self.child_stdin,
                   selected_template,
                   format!("{}{} ",
                           msg,
                           util::truncate(&c.get_title(), self.config.client_title_length)),
                   (i + 1).to_string());
        }
        write!(self.child_stdin, "\n");
    }
}
<commit_msg>implement drop for XmobarLogger.<commit_after>use std::collections::HashMap;
use std::io::Write;
use std::os::raw::c_uchar;
use std::process;
use mustache;
use mustache::MapBuilder;

use client::ClientW;
use config::Config;
use util;
use workspace::Workspace;

pub struct LoggerConfig {
    client_template: mustache::Template,
    client_selected_template: mustache::Template,
    client_title_length: usize,
    separator: &'static str,
    tag_template: mustache::Template,
    tag_selected_template: mustache::Template,
}

impl LoggerConfig {
    pub fn client_template(mut self, template: &str) -> Self {
        self.client_template = mustache::compile_str(template).unwrap();
        self
    }

    pub fn client_selected_template(mut self, template: &str) -> Self {
        self.client_selected_template = mustache::compile_str(template).unwrap();
        self
    }

    pub fn client_title_length(mut self, len: usize) -> Self {
        self.client_title_length = len;
        self
    }

    pub fn separator(mut self, s: &'static str) -> Self {
        self.separator = s;
        self
    }

    pub fn tag_template(mut self, template: &str) -> Self {
        self.tag_template = mustache::compile_str(template).unwrap();
        self
    }

    pub fn tag_selected_template(mut self, template: &str) -> Self {
        self.tag_selected_template = mustache::compile_str(template).unwrap();
        self
    }
}

impl Default for LoggerConfig {
    fn default() -> Self {
        LoggerConfig {
            client_template: mustache::compile_str("[{{& content }}] ").unwrap(),
            client_selected_template: mustache::compile_str("[<fc=#FFFF00>{{& content }}</fc>] ")
                .unwrap(),
            client_title_length: 8,
            separator: " :: ",
            tag_template: mustache::compile_str("{{& content }}").unwrap(),
            tag_selected_template: mustache::compile_str("<fc=#00FF00>{{& content }}</fc> |")
                .unwrap(),
        }
    }
}

pub trait Logger {
    fn dump(&mut self,
            global_config: &Config,
            workspaces: &HashMap<c_uchar, Workspace>,
            clients: &Vec<ClientW>,
            current_tag: c_uchar,
            current_clients: &Vec<ClientW>,
            focused: Option<ClientW>);
}

pub struct DummyLogger;

impl DummyLogger {
    #[allow(unused_variables)]
    pub fn new(config: LoggerConfig) -> Self {
        DummyLogger
    }
}

impl Logger for DummyLogger {
    #[allow(unused_variables)]
    fn dump(&mut self,
            global_config: &Config,
            workspaces: &HashMap<c_uchar, Workspace>,
            clients: &Vec<ClientW>,
            current_tag: c_uchar,
            current_clients: &Vec<ClientW>,
            focused: Option<ClientW>) {
        // Do nothing.
    }
}

pub struct XMobarLogger {
    config: LoggerConfig,
    child: process::Child,
}

impl Drop for XMobarLogger {
    fn drop(&mut self) {
        self.child.kill().unwrap_or_else(|_| ());
    }
}

impl XMobarLogger {
    pub fn new(config: LoggerConfig, xmobar_args: &[&str]) -> Self {
        let child = process::Command::new("xmobar")
            .stdin(process::Stdio::piped())
            .args(xmobar_args)
            .spawn()
            .expect("cannot spawn xmobar");
        XMobarLogger {
            config: config,
            child: child,
        }
    }
}

impl Logger for XMobarLogger {
    fn dump(&mut self,
            global_config: &Config,
            workspaces: &HashMap<c_uchar, Workspace>,
            clients: &Vec<ClientW>,
            current_tag: c_uchar,
            current_clients: &Vec<ClientW>,
            focused: Option<ClientW>) {
        fn render<W: Write, T1: Into<String>, T2: Into<String>>(w: &mut W,
                                                                template: &mustache::Template,
                                                                to_render: T1,
                                                                tag: T2) {
            let content = mustache::MapBuilder::new()
                .insert_str("content", to_render.into())
                .insert_str("tag", tag.into())
                .build();
            template.render_data(w, &content).unwrap();
        }

        let mut tags: Vec<char> = clients.iter().map(|c| c.tag() as char).collect();
        tags.push(current_tag as char);
        tags.sort();
        tags.dedup();
        for t in &tags {
            let selected_template = if *t == current_tag as char {
                &self.config.tag_selected_template
            } else {
                &self.config.tag_template
            };
            if current_tag == 0 {
                render(self.child.stdin.as_mut().unwrap(),
                       selected_template,
                       "Overview",
                       t.to_string());
            } else {
                let string = if let Some(description) =
                    workspaces.get(&(*t as c_uchar)).unwrap().get_description() {
                    format!("{} - {}", t, description)
                } else {
                    (*t).to_string()
                };
                render(self.child.stdin.as_mut().unwrap(),
                       selected_template,
                       string,
                       t.to_string());
            }
        }
        write!(self.child.stdin.as_mut().unwrap(),
               "{}",
               self.config.separator);
        for i in 0..current_clients.len() {
            let c = &current_clients[i];
            let selected_template = match focused.as_ref() {
                Some(c_focused) if c_focused.window() == c.window() => {
                    &self.config.client_selected_template
                }
                _ => &self.config.client_template,
            };
            let msg = if current_tag == 0 {
                format!("{}@", c.tag() as char)
            } else {
                "".to_string()
            };
            render(self.child.stdin.as_mut().unwrap(),
                   selected_template,
                   format!("{}{} ",
                           msg,
                           util::truncate(&c.get_title(), self.config.client_title_length)),
                   (i + 1).to_string());
        }
        write!(self.child.stdin.as_mut().unwrap(), "\n");
    }
}
<|endoftext|>


<commit_before>//! Abstractions for default-sized and huge virtual memory pages.

use crate::structures::paging::page_table::PageTableLevel;
use crate::structures::paging::PageTableIndex;
use crate::VirtAddr;
use core::fmt;
use core::marker::PhantomData;
use core::ops::{Add, AddAssign, Sub, SubAssign};

/// Trait for abstracting over the three possible page sizes on x86_64, 4KiB, 2MiB, 1GiB.
pub trait PageSize: Copy + Eq + PartialOrd + Ord {
    /// The page size in bytes.
    const SIZE: u64;

    /// A string representation of the page size for debug output.
    const SIZE_AS_DEBUG_STR: &'static str;
}

/// This trait is implemented for 4KiB and 2MiB pages, but not for 1GiB pages.
pub trait NotGiantPageSize: PageSize {}

/// A standard 4KiB page.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Size4KiB {}

/// A “huge” 2MiB page.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Size2MiB {}

/// A “giant” 1GiB page.
///
/// (Only available on newer x86_64 CPUs.)
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Size1GiB {}

impl PageSize for Size4KiB {
    const SIZE: u64 = 4096;
    const SIZE_AS_DEBUG_STR: &'static str = "4KiB";
}

impl NotGiantPageSize for Size4KiB {}

impl PageSize for Size2MiB {
    const SIZE: u64 = Size4KiB::SIZE * 512;
    const SIZE_AS_DEBUG_STR: &'static str = "2MiB";
}

impl NotGiantPageSize for Size2MiB {}

impl PageSize for Size1GiB {
    const SIZE: u64 = Size2MiB::SIZE * 512;
    const SIZE_AS_DEBUG_STR: &'static str = "1GiB";
}

/// A virtual memory page.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(C)]
pub struct Page<S: PageSize = Size4KiB> {
    start_address: VirtAddr,
    size: PhantomData<S>,
}

impl<S: PageSize> Page<S> {
    /// The page size in bytes.
    pub const SIZE: u64 = S::SIZE;

    /// Returns the page that starts at the given virtual address.
    ///
    /// Returns an error if the address is not correctly aligned (i.e. is not a valid page start).
    #[inline]
    pub fn from_start_address(address: VirtAddr) -> Result<Self, AddressNotAligned> {
        if !address.is_aligned(S::SIZE) {
            return Err(AddressNotAligned);
        }
        Ok(Page::containing_address(address))
    }

    const_fn! {
        /// Returns the page that starts at the given virtual address.
        ///
        /// ## Safety
        ///
        /// The address must be correctly aligned.
        #[inline]
        pub unsafe fn from_start_address_unchecked(start_address: VirtAddr) -> Self {
            Page {
                start_address,
                size: PhantomData,
            }
        }
    }

    /// Returns the page that contains the given virtual address.
    #[inline]
    pub fn containing_address(address: VirtAddr) -> Self {
        Page {
            start_address: address.align_down(S::SIZE),
            size: PhantomData,
        }
    }

    const_fn! {
        /// Returns the start address of the page.
        #[inline]
        pub fn start_address(self) -> VirtAddr {
            self.start_address
        }
    }

    const_fn! {
        /// Returns the size the page (4KB, 2MB or 1GB).
        #[inline]
        pub fn size(self) -> u64 {
            S::SIZE
        }
    }

    const_fn! {
        /// Returns the level 4 page table index of this page.
        #[inline]
        pub fn p4_index(self) -> PageTableIndex {
            self.start_address().p4_index()
        }
    }

    const_fn! {
        /// Returns the level 3 page table index of this page.
        #[inline]
        pub fn p3_index(self) -> PageTableIndex {
            self.start_address().p3_index()
        }
    }

    const_fn! {
        /// Returns the level 3 page table index of this page.
        ///
        /// ## Panics
        ///
        /// Panics if level is not between 1 and 4
        #[inline]
        pub fn page_table_index(self, level: PageTableLevel) -> PageTableIndex {
            self.start_address().page_table_index(level)
        }
    }

    const_fn! {
        /// Returns a range of pages, exclusive `end`.
        #[inline]
        pub fn range(start: Self, end: Self) -> PageRange<S> {
            PageRange { start, end }
        }
    }

    const_fn! {
        /// Returns a range of pages, inclusive `end`.
        #[inline]
        pub fn range_inclusive(start: Self, end: Self) -> PageRangeInclusive<S> {
            PageRangeInclusive { start, end }
        }
    }
}

impl<S: NotGiantPageSize> Page<S> {
    const_fn! {
        /// Returns the level 2 page table index of this page.
        #[inline]
        pub fn p2_index(self) -> PageTableIndex {
            self.start_address().p2_index()
        }
    }
}

impl Page<Size1GiB> {
    /// Returns the 1GiB memory page with the specified page table indices.
    #[inline]
    pub fn from_page_table_indices_1gib(
        p4_index: PageTableIndex,
        p3_index: PageTableIndex,
    ) -> Self {
        use bit_field::BitField;

        let mut addr = 0;
        addr.set_bits(39..48, u64::from(p4_index));
        addr.set_bits(30..39, u64::from(p3_index));
        Page::containing_address(VirtAddr::new(addr))
    }
}

impl Page<Size2MiB> {
    /// Returns the 2MiB memory page with the specified page table indices.
    #[inline]
    pub fn from_page_table_indices_2mib(
        p4_index: PageTableIndex,
        p3_index: PageTableIndex,
        p2_index: PageTableIndex,
    ) -> Self {
        use bit_field::BitField;

        let mut addr = 0;
        addr.set_bits(39..48, u64::from(p4_index));
        addr.set_bits(30..39, u64::from(p3_index));
        addr.set_bits(21..30, u64::from(p2_index));
        Page::containing_address(VirtAddr::new(addr))
    }
}

impl Page<Size4KiB> {
    /// Returns the 4KiB memory page with the specified page table indices.
    #[inline]
    pub fn from_page_table_indices(
        p4_index: PageTableIndex,
        p3_index: PageTableIndex,
        p2_index: PageTableIndex,
        p1_index: PageTableIndex,
    ) -> Self {
        use bit_field::BitField;

        let mut addr = 0;
        addr.set_bits(39..48, u64::from(p4_index));
        addr.set_bits(30..39, u64::from(p3_index));
        addr.set_bits(21..30, u64::from(p2_index));
        addr.set_bits(12..21, u64::from(p1_index));
        Page::containing_address(VirtAddr::new(addr))
    }

    /// Returns the level 1 page table index of this page.
    #[inline]
    pub const fn p1_index(self) -> PageTableIndex {
        self.start_address.p1_index()
    }
}

impl<S: PageSize> fmt::Debug for Page<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_fmt(format_args!(
            "Page[{}]({:#x})",
            S::SIZE_AS_DEBUG_STR,
            self.start_address().as_u64()
        ))
    }
}

impl<S: PageSize> Add<u64> for Page<S> {
    type Output = Self;
    #[inline]
    fn add(self, rhs: u64) -> Self::Output {
        Page::containing_address(self.start_address() + rhs * S::SIZE)
    }
}

impl<S: PageSize> AddAssign<u64> for Page<S> {
    #[inline]
    fn add_assign(&mut self, rhs: u64) {
        *self = *self + rhs;
    }
}

impl<S: PageSize> Sub<u64> for Page<S> {
    type Output = Self;
    #[inline]
    fn sub(self, rhs: u64) -> Self::Output {
        Page::containing_address(self.start_address() - rhs * S::SIZE)
    }
}

impl<S: PageSize> SubAssign<u64> for Page<S> {
    #[inline]
    fn sub_assign(&mut self, rhs: u64) {
        *self = *self - rhs;
    }
}

impl<S: PageSize> Sub<Self> for Page<S> {
    type Output = u64;
    #[inline]
    fn sub(self, rhs: Self) -> Self::Output {
        (self.start_address - rhs.start_address) / S::SIZE
    }
}

/// A range of pages with exclusive upper bound.
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct PageRange<S: PageSize = Size4KiB> {
    /// The start of the range, inclusive.
    pub start: Page<S>,
    /// The end of the range, exclusive.
    pub end: Page<S>,
}

impl<S: PageSize> PageRange<S> {
    /// Returns wether this range contains no pages.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.start >= self.end
    }
}

impl<S: PageSize> Iterator for PageRange<S> {
    type Item = Page<S>;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.start < self.end {
            let page = self.start;
            self.start += 1;
            Some(page)
        } else {
            None
        }
    }
}

impl PageRange<Size2MiB> {
    /// Converts the range of 2MiB pages to a range of 4KiB pages.
    #[inline]
    pub fn as_4kib_page_range(self) -> PageRange<Size4KiB> {
        PageRange {
            start: Page::containing_address(self.start.start_address()),
            end: Page::containing_address(self.end.start_address()),
        }
    }
}

impl<S: PageSize> fmt::Debug for PageRange<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("PageRange")
            .field("start", &self.start)
            .field("end", &self.end)
            .finish()
    }
}

/// A range of pages with inclusive upper bound.
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct PageRangeInclusive<S: PageSize = Size4KiB> {
    /// The start of the range, inclusive.
    pub start: Page<S>,
    /// The end of the range, inclusive.
    pub end: Page<S>,
}

impl<S: PageSize> PageRangeInclusive<S> {
    /// Returns wether this range contains no pages.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.start > self.end
    }
}

impl<S: PageSize> Iterator for PageRangeInclusive<S> {
    type Item = Page<S>;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.start <= self.end {
            let page = self.start;
            self.start += 1;
            Some(page)
        } else {
            None
        }
    }
}

impl<S: PageSize> fmt::Debug for PageRangeInclusive<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("PageRangeInclusive")
            .field("start", &self.start)
            .field("end", &self.end)
            .finish()
    }
}

/// The given address was not sufficiently aligned.
#[derive(Debug)]
pub struct AddressNotAligned;

impl fmt::Display for AddressNotAligned {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "the given address was not sufficiently aligned")
    }
}

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

    #[test]
    pub fn test_page_ranges() {
        let page_size = Size4KiB::SIZE;
        let number = 1000;

        let start_addr = VirtAddr::new(0xdead_beaf);
        let start: Page = Page::containing_address(start_addr);
        let end = start + number;

        let mut range = Page::range(start, end);
        for i in 0..number {
            assert_eq!(
                range.next(),
                Some(Page::containing_address(start_addr + page_size * i))
            );
        }
        assert_eq!(range.next(), None);

        let mut range_inclusive = Page::range_inclusive(start, end);
        for i in 0..=number {
            assert_eq!(
                range_inclusive.next(),
                Some(Page::containing_address(start_addr + page_size * i))
            );
        }
        assert_eq!(range_inclusive.next(), None);
    }
}
<commit_msg>fix docs for `page_table_index`<commit_after>//! Abstractions for default-sized and huge virtual memory pages.

use crate::structures::paging::page_table::PageTableLevel;
use crate::structures::paging::PageTableIndex;
use crate::VirtAddr;
use core::fmt;
use core::marker::PhantomData;
use core::ops::{Add, AddAssign, Sub, SubAssign};

/// Trait for abstracting over the three possible page sizes on x86_64, 4KiB, 2MiB, 1GiB.
pub trait PageSize: Copy + Eq + PartialOrd + Ord {
    /// The page size in bytes.
    const SIZE: u64;

    /// A string representation of the page size for debug output.
    const SIZE_AS_DEBUG_STR: &'static str;
}

/// This trait is implemented for 4KiB and 2MiB pages, but not for 1GiB pages.
pub trait NotGiantPageSize: PageSize {}

/// A standard 4KiB page.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Size4KiB {}

/// A “huge” 2MiB page.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Size2MiB {}

/// A “giant” 1GiB page.
///
/// (Only available on newer x86_64 CPUs.)
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Size1GiB {}

impl PageSize for Size4KiB {
    const SIZE: u64 = 4096;
    const SIZE_AS_DEBUG_STR: &'static str = "4KiB";
}

impl NotGiantPageSize for Size4KiB {}

impl PageSize for Size2MiB {
    const SIZE: u64 = Size4KiB::SIZE * 512;
    const SIZE_AS_DEBUG_STR: &'static str = "2MiB";
}

impl NotGiantPageSize for Size2MiB {}

impl PageSize for Size1GiB {
    const SIZE: u64 = Size2MiB::SIZE * 512;
    const SIZE_AS_DEBUG_STR: &'static str = "1GiB";
}

/// A virtual memory page.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(C)]
pub struct Page<S: PageSize = Size4KiB> {
    start_address: VirtAddr,
    size: PhantomData<S>,
}

impl<S: PageSize> Page<S> {
    /// The page size in bytes.
    pub const SIZE: u64 = S::SIZE;

    /// Returns the page that starts at the given virtual address.
    ///
    /// Returns an error if the address is not correctly aligned (i.e. is not a valid page start).
    #[inline]
    pub fn from_start_address(address: VirtAddr) -> Result<Self, AddressNotAligned> {
        if !address.is_aligned(S::SIZE) {
            return Err(AddressNotAligned);
        }
        Ok(Page::containing_address(address))
    }

    const_fn! {
        /// Returns the page that starts at the given virtual address.
        ///
        /// ## Safety
        ///
        /// The address must be correctly aligned.
        #[inline]
        pub unsafe fn from_start_address_unchecked(start_address: VirtAddr) -> Self {
            Page {
                start_address,
                size: PhantomData,
            }
        }
    }

    /// Returns the page that contains the given virtual address.
    #[inline]
    pub fn containing_address(address: VirtAddr) -> Self {
        Page {
            start_address: address.align_down(S::SIZE),
            size: PhantomData,
        }
    }

    const_fn! {
        /// Returns the start address of the page.
        #[inline]
        pub fn start_address(self) -> VirtAddr {
            self.start_address
        }
    }

    const_fn! {
        /// Returns the size the page (4KB, 2MB or 1GB).
        #[inline]
        pub fn size(self) -> u64 {
            S::SIZE
        }
    }

    const_fn! {
        /// Returns the level 4 page table index of this page.
        #[inline]
        pub fn p4_index(self) -> PageTableIndex {
            self.start_address().p4_index()
        }
    }

    const_fn! {
        /// Returns the level 3 page table index of this page.
        #[inline]
        pub fn p3_index(self) -> PageTableIndex {
            self.start_address().p3_index()
        }
    }

    const_fn! {
        /// Returns the table index of this page at the specified level.
        #[inline]
        pub fn page_table_index(self, level: PageTableLevel) -> PageTableIndex {
            self.start_address().page_table_index(level)
        }
    }

    const_fn! {
        /// Returns a range of pages, exclusive `end`.
        #[inline]
        pub fn range(start: Self, end: Self) -> PageRange<S> {
            PageRange { start, end }
        }
    }

    const_fn! {
        /// Returns a range of pages, inclusive `end`.
        #[inline]
        pub fn range_inclusive(start: Self, end: Self) -> PageRangeInclusive<S> {
            PageRangeInclusive { start, end }
        }
    }
}

impl<S: NotGiantPageSize> Page<S> {
    const_fn! {
        /// Returns the level 2 page table index of this page.
        #[inline]
        pub fn p2_index(self) -> PageTableIndex {
            self.start_address().p2_index()
        }
    }
}

impl Page<Size1GiB> {
    /// Returns the 1GiB memory page with the specified page table indices.
    #[inline]
    pub fn from_page_table_indices_1gib(
        p4_index: PageTableIndex,
        p3_index: PageTableIndex,
    ) -> Self {
        use bit_field::BitField;

        let mut addr = 0;
        addr.set_bits(39..48, u64::from(p4_index));
        addr.set_bits(30..39, u64::from(p3_index));
        Page::containing_address(VirtAddr::new(addr))
    }
}

impl Page<Size2MiB> {
    /// Returns the 2MiB memory page with the specified page table indices.
    #[inline]
    pub fn from_page_table_indices_2mib(
        p4_index: PageTableIndex,
        p3_index: PageTableIndex,
        p2_index: PageTableIndex,
    ) -> Self {
        use bit_field::BitField;

        let mut addr = 0;
        addr.set_bits(39..48, u64::from(p4_index));
        addr.set_bits(30..39, u64::from(p3_index));
        addr.set_bits(21..30, u64::from(p2_index));
        Page::containing_address(VirtAddr::new(addr))
    }
}

impl Page<Size4KiB> {
    /// Returns the 4KiB memory page with the specified page table indices.
    #[inline]
    pub fn from_page_table_indices(
        p4_index: PageTableIndex,
        p3_index: PageTableIndex,
        p2_index: PageTableIndex,
        p1_index: PageTableIndex,
    ) -> Self {
        use bit_field::BitField;

        let mut addr = 0;
        addr.set_bits(39..48, u64::from(p4_index));
        addr.set_bits(30..39, u64::from(p3_index));
        addr.set_bits(21..30, u64::from(p2_index));
        addr.set_bits(12..21, u64::from(p1_index));
        Page::containing_address(VirtAddr::new(addr))
    }

    /// Returns the level 1 page table index of this page.
    #[inline]
    pub const fn p1_index(self) -> PageTableIndex {
        self.start_address.p1_index()
    }
}

impl<S: PageSize> fmt::Debug for Page<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_fmt(format_args!(
            "Page[{}]({:#x})",
            S::SIZE_AS_DEBUG_STR,
            self.start_address().as_u64()
        ))
    }
}

impl<S: PageSize> Add<u64> for Page<S> {
    type Output = Self;
    #[inline]
    fn add(self, rhs: u64) -> Self::Output {
        Page::containing_address(self.start_address() + rhs * S::SIZE)
    }
}

impl<S: PageSize> AddAssign<u64> for Page<S> {
    #[inline]
    fn add_assign(&mut self, rhs: u64) {
        *self = *self + rhs;
    }
}

impl<S: PageSize> Sub<u64> for Page<S> {
    type Output = Self;
    #[inline]
    fn sub(self, rhs: u64) -> Self::Output {
        Page::containing_address(self.start_address() - rhs * S::SIZE)
    }
}

impl<S: PageSize> SubAssign<u64> for Page<S> {
    #[inline]
    fn sub_assign(&mut self, rhs: u64) {
        *self = *self - rhs;
    }
}

impl<S: PageSize> Sub<Self> for Page<S> {
    type Output = u64;
    #[inline]
    fn sub(self, rhs: Self) -> Self::Output {
        (self.start_address - rhs.start_address) / S::SIZE
    }
}

/// A range of pages with exclusive upper bound.
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct PageRange<S: PageSize = Size4KiB> {
    /// The start of the range, inclusive.
    pub start: Page<S>,
    /// The end of the range, exclusive.
    pub end: Page<S>,
}

impl<S: PageSize> PageRange<S> {
    /// Returns wether this range contains no pages.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.start >= self.end
    }
}

impl<S: PageSize> Iterator for PageRange<S> {
    type Item = Page<S>;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.start < self.end {
            let page = self.start;
            self.start += 1;
            Some(page)
        } else {
            None
        }
    }
}

impl PageRange<Size2MiB> {
    /// Converts the range of 2MiB pages to a range of 4KiB pages.
    #[inline]
    pub fn as_4kib_page_range(self) -> PageRange<Size4KiB> {
        PageRange {
            start: Page::containing_address(self.start.start_address()),
            end: Page::containing_address(self.end.start_address()),
        }
    }
}

impl<S: PageSize> fmt::Debug for PageRange<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("PageRange")
            .field("start", &self.start)
            .field("end", &self.end)
            .finish()
    }
}

/// A range of pages with inclusive upper bound.
#[derive(Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct PageRangeInclusive<S: PageSize = Size4KiB> {
    /// The start of the range, inclusive.
    pub start: Page<S>,
    /// The end of the range, inclusive.
    pub end: Page<S>,
}

impl<S: PageSize> PageRangeInclusive<S> {
    /// Returns wether this range contains no pages.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.start > self.end
    }
}

impl<S: PageSize> Iterator for PageRangeInclusive<S> {
    type Item = Page<S>;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.start <= self.end {
            let page = self.start;
            self.start += 1;
            Some(page)
        } else {
            None
        }
    }
}

impl<S: PageSize> fmt::Debug for PageRangeInclusive<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("PageRangeInclusive")
            .field("start", &self.start)
            .field("end", &self.end)
            .finish()
    }
}

/// The given address was not sufficiently aligned.
#[derive(Debug)]
pub struct AddressNotAligned;

impl fmt::Display for AddressNotAligned {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "the given address was not sufficiently aligned")
    }
}

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

    #[test]
    pub fn test_page_ranges() {
        let page_size = Size4KiB::SIZE;
        let number = 1000;

        let start_addr = VirtAddr::new(0xdead_beaf);
        let start: Page = Page::containing_address(start_addr);
        let end = start + number;

        let mut range = Page::range(start, end);
        for i in 0..number {
            assert_eq!(
                range.next(),
                Some(Page::containing_address(start_addr + page_size * i))
            );
        }
        assert_eq!(range.next(), None);

        let mut range_inclusive = Page::range_inclusive(start, end);
        for i in 0..=number {
            assert_eq!(
                range_inclusive.next(),
                Some(Page::containing_address(start_addr + page_size * i))
            );
        }
        assert_eq!(range_inclusive.next(), None);
    }
}
<|endoftext|>