<commit_before>use std::{
    fmt,
    hash::{Hash, Hasher},
    ops::Deref,
    result::Result as StdResult,
    sync::Arc,
};

use serde::{
    Deserialize, Serialize,
    {de::Deserializer, ser::Serializer},
};

const CUTOFF: usize = std::mem::size_of::<&[u8]>() - 1;

type Inner = [u8; CUTOFF];

/// A buffer that may either be inline or remote and protected
/// by an Arc
#[derive(Clone)]
pub struct IVec(IVecInner);

#[derive(Clone)]
enum IVecInner {
    Inline(u8, Inner),
    Remote(Arc<[u8]>),
}

impl Hash for IVec {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.deref().hash(state);
    }
}

impl Serialize for IVec {
    fn serialize<S: Serializer>(
        &self,
        serializer: S,
    ) -> StdResult<S::Ok, S::Error> {
        serde_bytes::serialize(self.as_ref(), serializer)
    }
}

impl<'de> Deserialize<'de> for IVec {
    fn deserialize<D: Deserializer<'de>>(
        deserializer: D,
    ) -> StdResult<Self, D::Error> {
        let bytes: StdResult<Box<[u8]>, D::Error> =
            serde_bytes::deserialize(deserializer);
        bytes.map(IVec::from)
    }
}

const fn is_inline_candidate(length: usize) -> bool {
    length <= CUTOFF
}

impl IVec {
    fn inline(slice: &[u8]) -> IVec {
        assert!(is_inline_candidate(slice.len()));

        let mut data = Inner::default();

        unsafe {
            std::ptr::copy_nonoverlapping(
                slice.as_ptr(),
                data.as_mut_ptr(),
                slice.len(),
            );
        }

        IVec(IVecInner::Inline(slice.len() as u8, data))
    }

    fn remote(arc: Arc<[u8]>) -> IVec {
        IVec(IVecInner::Remote(arc))
    }

    #[inline]
    pub(crate) fn size_in_bytes(&self) -> u64 {
        if let IVecInner::Inline(..) = self.0 {
            std::mem::size_of::<IVec>() as u64
        } else {
            let sz = std::mem::size_of::<IVec>() as u64;
            sz.saturating_add(self.len() as u64)
        }
    }
}

impl From<Box<[u8]>> for IVec {
    fn from(b: Box<[u8]>) -> IVec {
        if is_inline_candidate(b.len()) {
            IVec::inline(&b)
        } else {
            // rely on the Arc From specialization
            // for Box<T>, which may improve
            // over time
            IVec::remote(Arc::from(b))
        }
    }
}

impl From<&[u8]> for IVec {
    fn from(slice: &[u8]) -> IVec {
        if is_inline_candidate(slice.len()) {
            IVec::inline(slice)
        } else {
            IVec::remote(Arc::from(slice))
        }
    }
}

impl From<Arc<[u8]>> for IVec {
    fn from(arc: Arc<[u8]>) -> IVec {
        IVec::remote(arc)
    }
}

impl From<&str> for IVec {
    fn from(s: &str) -> IVec {
        IVec::from(s.as_bytes())
    }
}

impl From<&IVec> for IVec {
    fn from(v: &IVec) -> IVec {
        v.clone()
    }
}

impl From<Vec<u8>> for IVec {
    fn from(v: Vec<u8>) -> IVec {
        if is_inline_candidate(v.len()) {
            IVec::inline(&v)
        } else {
            // rely on the Arc From specialization
            // for Vec<T>, which may improve
            // over time
            IVec::remote(Arc::from(v))
        }
    }
}

impl std::borrow::Borrow<[u8]> for IVec {
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

impl std::borrow::Borrow<[u8]> for &IVec {
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

macro_rules! from_array {
    ($($s:expr),*) => {
        $(
            impl From<&[u8; $s]> for IVec {
                fn from(v: &[u8; $s]) -> IVec {
                    IVec::from(&v[..])
                }
            }
        )*
    }
}

from_array!(
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
);

impl Into<Arc<[u8]>> for IVec {
    fn into(self) -> Arc<[u8]> {
        match self.0 {
            IVecInner::Inline(..) => Arc::from(self.as_ref()),
            IVecInner::Remote(arc) => arc,
        }
    }
}

impl Deref for IVec {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        self.as_ref()
    }
}

impl AsRef<[u8]> for IVec {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        match &self.0 {
            IVecInner::Inline(sz, buf) => unsafe {
                buf.get_unchecked(..*sz as usize)
            },
            IVecInner::Remote(buf) => buf,
        }
    }
}

impl Ord for IVec {
    fn cmp(&self, other: &IVec) -> std::cmp::Ordering {
        self.as_ref().cmp(other.as_ref())
    }
}

impl PartialOrd for IVec {
    fn partial_cmp(&self, other: &IVec) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: AsRef<[u8]>> PartialEq<T> for IVec {
    fn eq(&self, other: &T) -> bool {
        self.as_ref() == other.as_ref()
    }
}

impl PartialEq<[u8]> for IVec {
    fn eq(&self, other: &[u8]) -> bool {
        self.as_ref() == other
    }
}

impl Eq for IVec {}

impl fmt::Debug for IVec {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.as_ref().fmt(f)
    }
}

#[test]
fn ivec_usage() {
    let iv1 = IVec::from(vec![1, 2, 3]);
    assert_eq!(iv1, vec![1, 2, 3]);
    let iv2 = IVec::from(&[4; 128][..]);
    assert_eq!(iv2, vec![4; 128]);
}
<commit_msg>Implement Default for IVec<commit_after>use std::{
    fmt,
    hash::{Hash, Hasher},
    ops::Deref,
    result::Result as StdResult,
    sync::Arc,
};

use serde::{
    Deserialize, Serialize,
    {de::Deserializer, ser::Serializer},
};

const CUTOFF: usize = std::mem::size_of::<&[u8]>() - 1;

type Inner = [u8; CUTOFF];

/// A buffer that may either be inline or remote and protected
/// by an Arc
#[derive(Clone)]
pub struct IVec(IVecInner);

impl Default for IVec {
    fn default() -> IVec {
        IVec::from(&[])
    }
}

#[derive(Clone)]
enum IVecInner {
    Inline(u8, Inner),
    Remote(Arc<[u8]>),
}

impl Hash for IVec {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.deref().hash(state);
    }
}

impl Serialize for IVec {
    fn serialize<S: Serializer>(
        &self,
        serializer: S,
    ) -> StdResult<S::Ok, S::Error> {
        serde_bytes::serialize(self.as_ref(), serializer)
    }
}

impl<'de> Deserialize<'de> for IVec {
    fn deserialize<D: Deserializer<'de>>(
        deserializer: D,
    ) -> StdResult<Self, D::Error> {
        let bytes: StdResult<Box<[u8]>, D::Error> =
            serde_bytes::deserialize(deserializer);
        bytes.map(IVec::from)
    }
}

const fn is_inline_candidate(length: usize) -> bool {
    length <= CUTOFF
}

impl IVec {
    fn inline(slice: &[u8]) -> IVec {
        assert!(is_inline_candidate(slice.len()));

        let mut data = Inner::default();

        unsafe {
            std::ptr::copy_nonoverlapping(
                slice.as_ptr(),
                data.as_mut_ptr(),
                slice.len(),
            );
        }

        IVec(IVecInner::Inline(slice.len() as u8, data))
    }

    fn remote(arc: Arc<[u8]>) -> IVec {
        IVec(IVecInner::Remote(arc))
    }

    #[inline]
    pub(crate) fn size_in_bytes(&self) -> u64 {
        if let IVecInner::Inline(..) = self.0 {
            std::mem::size_of::<IVec>() as u64
        } else {
            let sz = std::mem::size_of::<IVec>() as u64;
            sz.saturating_add(self.len() as u64)
        }
    }
}

impl From<Box<[u8]>> for IVec {
    fn from(b: Box<[u8]>) -> IVec {
        if is_inline_candidate(b.len()) {
            IVec::inline(&b)
        } else {
            // rely on the Arc From specialization
            // for Box<T>, which may improve
            // over time
            IVec::remote(Arc::from(b))
        }
    }
}

impl From<&[u8]> for IVec {
    fn from(slice: &[u8]) -> IVec {
        if is_inline_candidate(slice.len()) {
            IVec::inline(slice)
        } else {
            IVec::remote(Arc::from(slice))
        }
    }
}

impl From<Arc<[u8]>> for IVec {
    fn from(arc: Arc<[u8]>) -> IVec {
        IVec::remote(arc)
    }
}

impl From<&str> for IVec {
    fn from(s: &str) -> IVec {
        IVec::from(s.as_bytes())
    }
}

impl From<&IVec> for IVec {
    fn from(v: &IVec) -> IVec {
        v.clone()
    }
}

impl From<Vec<u8>> for IVec {
    fn from(v: Vec<u8>) -> IVec {
        if is_inline_candidate(v.len()) {
            IVec::inline(&v)
        } else {
            // rely on the Arc From specialization
            // for Vec<T>, which may improve
            // over time
            IVec::remote(Arc::from(v))
        }
    }
}

impl std::borrow::Borrow<[u8]> for IVec {
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

impl std::borrow::Borrow<[u8]> for &IVec {
    fn borrow(&self) -> &[u8] {
        self.as_ref()
    }
}

macro_rules! from_array {
    ($($s:expr),*) => {
        $(
            impl From<&[u8; $s]> for IVec {
                fn from(v: &[u8; $s]) -> IVec {
                    IVec::from(&v[..])
                }
            }
        )*
    }
}

from_array!(
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
    21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
);

impl Into<Arc<[u8]>> for IVec {
    fn into(self) -> Arc<[u8]> {
        match self.0 {
            IVecInner::Inline(..) => Arc::from(self.as_ref()),
            IVecInner::Remote(arc) => arc,
        }
    }
}

impl Deref for IVec {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        self.as_ref()
    }
}

impl AsRef<[u8]> for IVec {
    #[inline]
    fn as_ref(&self) -> &[u8] {
        match &self.0 {
            IVecInner::Inline(sz, buf) => unsafe {
                buf.get_unchecked(..*sz as usize)
            },
            IVecInner::Remote(buf) => buf,
        }
    }
}

impl Ord for IVec {
    fn cmp(&self, other: &IVec) -> std::cmp::Ordering {
        self.as_ref().cmp(other.as_ref())
    }
}

impl PartialOrd for IVec {
    fn partial_cmp(&self, other: &IVec) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl<T: AsRef<[u8]>> PartialEq<T> for IVec {
    fn eq(&self, other: &T) -> bool {
        self.as_ref() == other.as_ref()
    }
}

impl PartialEq<[u8]> for IVec {
    fn eq(&self, other: &[u8]) -> bool {
        self.as_ref() == other
    }
}

impl Eq for IVec {}

impl fmt::Debug for IVec {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.as_ref().fmt(f)
    }
}

#[test]
fn ivec_usage() {
    let iv1 = IVec::from(vec![1, 2, 3]);
    assert_eq!(iv1, vec![1, 2, 3]);
    let iv2 = IVec::from(&[4; 128][..]);
    assert_eq!(iv2, vec![4; 128]);
}
<|endoftext|>


<commit_before>//! Context management

use alloc::boxed::Box;
use collections::{BTreeMap, Vec};
use core::mem;
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};

use arch;
use arch::context::Context as ArchContext;
use syscall::{Error, Result};

/// File operations
pub mod file;

/// Limit on number of contexts
pub const CONTEXT_MAX_CONTEXTS: usize = 65536;

/// Maximum context files
pub const CONTEXT_MAX_FILES: usize = 65536;

/// Context list type
pub struct ContextList {
    map: BTreeMap<usize, RwLock<Context>>,
    next_id: usize
}

impl ContextList {
    /// Create a new context list.
    pub fn new() -> Self {
        ContextList {
            map: BTreeMap::new(),
            next_id: 1
        }
    }

    /// Get the nth context.
    pub fn get(&self, id: usize) -> Option<&RwLock<Context>> {
        self.map.get(&id)
    }

    /// Get the current context.
    pub fn current(&self) -> Option<&RwLock<Context>> {
        self.map.get(&CONTEXT_ID.load(Ordering::SeqCst))
    }

    /// Create a new context.
    pub fn new_context(&mut self) -> Result<&RwLock<Context>> {
        if self.next_id >= CONTEXT_MAX_CONTEXTS {
            self.next_id = 1;
        }

        while self.map.contains_key(&self.next_id) {
            self.next_id += 1;
        }

        if self.next_id >= CONTEXT_MAX_CONTEXTS {
            return Err(Error::TryAgain);
        }

        let id = self.next_id;
        self.next_id += 1;

        assert!(self.map.insert(id, RwLock::new(Context::new(id))).is_none());

        Ok(self.map.get(&id).expect("Failed to insert new context. ID is out of bounds."))
    }

    /// Spawn a context from a function.
    pub fn spawn(&mut self, func: extern fn()) -> Result<&RwLock<Context>> {
        let context_lock = self.new_context()?;
        {
            let mut context = context_lock.write();
            let mut stack = Box::new([0; 4096]);
            let offset = stack.len() - mem::size_of::<usize>();
            unsafe {
                let offset = stack.len() - mem::size_of::<usize>();
                let func_ptr = stack.as_mut_ptr().offset(offset as isize);
                *(func_ptr as *mut usize) = func as usize;
            }
            context.arch.set_stack(stack.as_ptr() as usize + offset);
            context.kstack = Some(stack);
            print!("{}", format!("{}: {:X}\n", context.id, func as usize));
        }
        Ok(context_lock)
    }
}

/// Contexts list
static CONTEXTS: Once<RwLock<ContextList>> = Once::new();

#[thread_local]
static CONTEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;

pub fn init() {
    let mut contexts = contexts_mut();
    let context_lock = contexts.new_context().expect("could not initialize first context");
    let mut context = context_lock.write();
    context.running = true;
    CONTEXT_ID.store(context.id, Ordering::SeqCst);
}

/// Initialize contexts, called if needed
fn init_contexts() -> RwLock<ContextList> {
    RwLock::new(ContextList::new())
}

/// Get the global schemes list, const
pub fn contexts() -> RwLockReadGuard<'static, ContextList> {
    CONTEXTS.call_once(init_contexts).read()
}

/// Get the global schemes list, mutable
pub fn contexts_mut() -> RwLockWriteGuard<'static, ContextList> {
    CONTEXTS.call_once(init_contexts).write()
}

/// Switch to the next context
///
/// # Safety
///
/// Do not call this while holding locks!
pub unsafe fn switch() {
    use core::ops::DerefMut;

    // Set the global lock to avoid the unsafe operations below from causing issues
    while arch::context::CONTEXT_SWITCH_LOCK.compare_and_swap(false, true, Ordering::SeqCst) {
        arch::interrupt::pause();
    }

    let from_ptr = if let Some(context_lock) = contexts().current() {
        let mut context = context_lock.write();
        context.deref_mut() as *mut Context
    } else {
        print!("NO FROM_PTR\n");
        return;
    };

    let mut to_ptr = 0 as *mut Context;

    for (_pid, context_lock) in contexts().map.iter() {
        let mut context = context_lock.write();
        if ! context.running {
            to_ptr = context.deref_mut() as *mut Context;
            break;
        }
    }

    if to_ptr as usize == 0 {
        print!("NO TO_PTR\n");
        return;
    }

    unsafe {
        (&mut *from_ptr).running = false;
        (&mut *to_ptr).running = true;
        CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst);

        (&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch);
    }
}

/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
    /// The ID of this context
    pub id: usize,
    /// Running or not
    pub running: bool,
    /// The architecture specific context
    pub arch: ArchContext,
    /// Kernel stack
    pub kstack: Option<Box<[u8]>>,
    /// The open files in the scheme
    pub files: Vec<Option<file::File>>
}

impl Context {
    /// Create a new context
    pub fn new(id: usize) -> Context {
        Context {
            id: id,
            running: false,
            arch: ArchContext::new(),
            kstack: None,
            files: Vec::new()
        }
    }

    /// Add a file to the lowest available slot.
    /// Return the file descriptor number or None if no slot was found
    pub fn add_file(&mut self, file: file::File) -> Option<usize> {
        for (i, mut file_option) in self.files.iter_mut().enumerate() {
            if file_option.is_none() {
                *file_option = Some(file);
                return Some(i);
            }
        }
        let len = self.files.len();
        if len < CONTEXT_MAX_FILES {
            self.files.push(Some(file));
            Some(len)
        } else {
            None
        }
    }
}
<commit_msg>Fill in all exception and IRQ entries. Handle PIT, keyboard IRQs<commit_after>//! Context management

use alloc::boxed::Box;
use collections::{BTreeMap, Vec};
use core::mem;
use core::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};

use arch;
use arch::context::Context as ArchContext;
use syscall::{Error, Result};

/// File operations
pub mod file;

/// Limit on number of contexts
pub const CONTEXT_MAX_CONTEXTS: usize = 65536;

/// Maximum context files
pub const CONTEXT_MAX_FILES: usize = 65536;

/// Context list type
pub struct ContextList {
    map: BTreeMap<usize, RwLock<Context>>,
    next_id: usize
}

impl ContextList {
    /// Create a new context list.
    pub fn new() -> Self {
        ContextList {
            map: BTreeMap::new(),
            next_id: 1
        }
    }

    /// Get the nth context.
    pub fn get(&self, id: usize) -> Option<&RwLock<Context>> {
        self.map.get(&id)
    }

    /// Get the current context.
    pub fn current(&self) -> Option<&RwLock<Context>> {
        self.map.get(&CONTEXT_ID.load(Ordering::SeqCst))
    }

    /// Create a new context.
    pub fn new_context(&mut self) -> Result<&RwLock<Context>> {
        if self.next_id >= CONTEXT_MAX_CONTEXTS {
            self.next_id = 1;
        }

        while self.map.contains_key(&self.next_id) {
            self.next_id += 1;
        }

        if self.next_id >= CONTEXT_MAX_CONTEXTS {
            return Err(Error::TryAgain);
        }

        let id = self.next_id;
        self.next_id += 1;

        assert!(self.map.insert(id, RwLock::new(Context::new(id))).is_none());

        Ok(self.map.get(&id).expect("Failed to insert new context. ID is out of bounds."))
    }

    /// Spawn a context from a function.
    pub fn spawn(&mut self, func: extern fn()) -> Result<&RwLock<Context>> {
        let context_lock = self.new_context()?;
        {
            let mut context = context_lock.write();
            let mut stack = Box::new([0; 4096]);
            let offset = stack.len() - mem::size_of::<usize>();
            unsafe {
                let offset = stack.len() - mem::size_of::<usize>();
                let func_ptr = stack.as_mut_ptr().offset(offset as isize);
                *(func_ptr as *mut usize) = func as usize;
            }
            context.arch.set_stack(stack.as_ptr() as usize + offset);
            context.kstack = Some(stack);
            print!("{}", format!("{}: {:X}\n", context.id, func as usize));
        }
        Ok(context_lock)
    }
}

/// Contexts list
static CONTEXTS: Once<RwLock<ContextList>> = Once::new();

#[thread_local]
static CONTEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;

pub fn init() {
    let mut contexts = contexts_mut();
    let context_lock = contexts.new_context().expect("could not initialize first context");
    let mut context = context_lock.write();
    context.running = true;
    CONTEXT_ID.store(context.id, Ordering::SeqCst);
}

/// Initialize contexts, called if needed
fn init_contexts() -> RwLock<ContextList> {
    RwLock::new(ContextList::new())
}

/// Get the global schemes list, const
pub fn contexts() -> RwLockReadGuard<'static, ContextList> {
    CONTEXTS.call_once(init_contexts).read()
}

/// Get the global schemes list, mutable
pub fn contexts_mut() -> RwLockWriteGuard<'static, ContextList> {
    CONTEXTS.call_once(init_contexts).write()
}

/// Switch to the next context
///
/// # Safety
///
/// Do not call this while holding locks!
pub unsafe fn switch() {
    use core::ops::DerefMut;

    // Set the global lock to avoid the unsafe operations below from causing issues
    while arch::context::CONTEXT_SWITCH_LOCK.compare_and_swap(false, true, Ordering::SeqCst) {
        arch::interrupt::pause();
    }

    let from_ptr = if let Some(context_lock) = contexts().current() {
        let mut context = context_lock.write();
        context.deref_mut() as *mut Context
    } else {
        print!("NO FROM_PTR\n");
        return;
    };

    let mut to_ptr = 0 as *mut Context;

    for (_pid, context_lock) in contexts().map.iter() {
        let mut context = context_lock.write();
        if ! context.running {
            to_ptr = context.deref_mut() as *mut Context;
            break;
        }
    }

    if to_ptr as usize == 0 {
        print!("NO TO_PTR\n");
        return;
    }

    (&mut *from_ptr).running = false;
    (&mut *to_ptr).running = true;
    CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst);

    (&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch);
}

/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
    /// The ID of this context
    pub id: usize,
    /// Running or not
    pub running: bool,
    /// The architecture specific context
    pub arch: ArchContext,
    /// Kernel stack
    pub kstack: Option<Box<[u8]>>,
    /// The open files in the scheme
    pub files: Vec<Option<file::File>>
}

impl Context {
    /// Create a new context
    pub fn new(id: usize) -> Context {
        Context {
            id: id,
            running: false,
            arch: ArchContext::new(),
            kstack: None,
            files: Vec::new()
        }
    }

    /// Add a file to the lowest available slot.
    /// Return the file descriptor number or None if no slot was found
    pub fn add_file(&mut self, file: file::File) -> Option<usize> {
        for (i, mut file_option) in self.files.iter_mut().enumerate() {
            if file_option.is_none() {
                *file_option = Some(file);
                return Some(i);
            }
        }
        let len = self.files.len();
        if len < CONTEXT_MAX_FILES {
            self.files.push(Some(file));
            Some(len)
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>use std::default::Default;
use std::path::Path;

use collada;
use gfx;
use gfx::Typed;
use gfx::traits::*;
use gfx_texture;

use math::*;
use skeleton::Skeleton;
use transform::Transform;

const MAX_JOINTS: usize = 64;

pub struct SkinnedRenderBatch<R: gfx::Resources, T: Transform> {
    skinning_transforms_buffer: gfx::handle::Buffer<R, T>,
    slice: gfx::Slice<R>,
    vertex_buffer: gfx::handle::Buffer<R, SkinnedVertex>,
    texture: (gfx::handle::ShaderResourceView<R, [f32; 4]>, gfx::handle::Sampler<R>),
}

pub struct SkinnedRenderer<R: gfx::Resources, T: Transform> {
    pso: gfx::PipelineState<R, pipe::Meta>,
    skeleton: Skeleton, // TODO Should this be a ref? Should this just be the joints?
    render_batches: Vec<SkinnedRenderBatch<R, T>>,
}

pub trait HasShaderSources<'a> {
    fn vertex_shader_source() -> &'a [u8];
    fn fragment_shader_source() -> &'a [u8];
}

impl<'a> HasShaderSources<'a> for Matrix4<f32> {
    fn vertex_shader_source() -> &'a [u8] {
        include_bytes!("lbs_skinning_150.glslv")
    }
    fn fragment_shader_source() -> &'a [u8] {
        include_bytes!("skinning_150.glslf")
    }
}

impl<'a> HasShaderSources<'a> for DualQuaternion<f32> {
    fn vertex_shader_source() -> &'a [u8] {
        include_bytes!("dlb_skinning_150.glslv")
    }
    fn fragment_shader_source() -> &'a [u8] {
        include_bytes!("skinning_150.glslf")
    }
}

impl<'a, R: gfx::Resources, T: Transform + HasShaderSources<'a>> SkinnedRenderer<R, T> {

    pub fn from_collada<F: gfx::Factory<R>>(
        factory: &mut F,
        collada_document: collada::document::ColladaDocument,
        texture_paths: Vec<&str>, // TODO - read from the COLLADA document (if available)
    ) -> Result<SkinnedRenderer<R, T>, gfx::shade::ProgramError> {
        use gfx::format::Formatted;

        let program = {
            let vs = T::vertex_shader_source();
            let fs = T::fragment_shader_source();
            match factory.link_program(vs, fs) {
                Ok(program_handle) => program_handle,
                Err(e) => return Err(e),
            }
        };

        // TODO: Pass in format as parameter.
        let format = gfx::format::Srgba8::get_format();
        let init = pipe::Init {
            vertex: (),
            u_model_view_proj: "u_model_view_proj",
            u_model_view: "u_model_view",
            u_skinning_transforms: "u_skinning_transforms",
            u_texture: "u_texture",
            out_color: ("out_color", format, gfx::state::MASK_ALL, Some(gfx::preset::blend::ALPHA)),
            out_depth: gfx::preset::depth::LESS_EQUAL_WRITE,
        };
        let pso = factory.create_pipeline_from_program(
            &program,
            gfx::Primitive::LineList,
            gfx::state::Rasterizer::new_fill(),
            init
        ).unwrap();

        let sampler = factory.create_sampler(
            gfx::tex::SamplerInfo::new(
                gfx::tex::FilterMethod::Trilinear,
                gfx::tex::WrapMode::Clamp
            )
        );

        let obj_set = collada_document.get_obj_set().unwrap();

        let skeleton_set = collada_document.get_skeletons().unwrap();
        let skeleton = Skeleton::from_collada(&skeleton_set[0]);

        let mut render_batches = Vec::new();

        for (i, object) in obj_set.objects.iter().enumerate().take(6) {

            let mut vertex_data: Vec<SkinnedVertex> = Vec::new();
            let mut index_data: Vec<u32> = Vec::new();

            get_vertex_index_data(&object, &mut vertex_data, &mut index_data);

            let (vbuf, slice) = factory.create_vertex_buffer_with_slice
                (&vertex_data, &index_data[..]);

            let skinning_transforms_buffer = factory.create_buffer_dynamic::<T>(
                MAX_JOINTS, gfx::BufferRole::Uniform, gfx::Bind::empty()).unwrap();

            let texture = gfx_texture::Texture::from_path(
                factory,
                &Path::new(&texture_paths[i]),
                gfx_texture::Flip::None,
                &gfx_texture::TextureSettings::new()
            ).unwrap();

            render_batches.push(SkinnedRenderBatch {
                slice: slice,
                vertex_buffer: vbuf,
                skinning_transforms_buffer: skinning_transforms_buffer,
                texture: (texture.view.clone(), sampler.clone()),
            });
        }

        Ok(SkinnedRenderer {
            pso: pso,
            render_batches: render_batches,
            skeleton: skeleton.clone(),
        })
    }

    pub fn render<C: gfx::CommandBuffer<R>, Rf: gfx::format::RenderFormat> (
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        out_color: &gfx::handle::RenderTargetView<R, Rf>,
        out_depth: &gfx::handle::DepthStencilView<R, gfx::format::DepthStencil>,
        view: [[f32; 4]; 4],
        projection: [[f32; 4]; 4],
        joint_poses: &[T]
    ) {

        let skinning_transforms = self.calculate_skinning_transforms(&joint_poses);

        for material in self.render_batches.iter_mut() {
            // FIXME -- should all be able to share the same buffer
            encoder.update_buffer(&material.skinning_transforms_buffer, &skinning_transforms[..], 0).unwrap();

            let data = pipe::Data {
                vertex: material.vertex_buffer.clone(),
                u_model_view_proj: projection,
                u_model_view: view,
                u_skinning_transforms: material.skinning_transforms_buffer.raw().clone(),
                u_texture: material.texture.clone(),
                out_color: out_color.raw().clone(),
                out_depth: out_depth.clone(),
            };

            encoder.draw(&material.slice, &self.pso, &data);
        }
    }

    ///
    /// TODO - don't allocate a new vector
    ///
    pub fn calculate_skinning_transforms(&self, global_poses: &[T]) -> Vec<T> {
        self.skeleton.joints.iter().enumerate().map(|(i, joint)| {
            // TODO avoid conversion...
            global_poses[i].concat(T::from_matrix(joint.inverse_bind_pose))
        }).collect()
    }
}

gfx_pipeline_base!( pipe {
    vertex: gfx::VertexBuffer<SkinnedVertex>,
    u_model_view_proj: gfx::Global<[[f32; 4]; 4]>,
    u_model_view: gfx::Global<[[f32; 4]; 4]>,
    u_skinning_transforms: gfx::RawConstantBuffer,
    u_texture: gfx::TextureSampler<[f32; 4]>,
    out_color: gfx::RawRenderTarget,
    out_depth: gfx::DepthTarget<gfx::format::DepthStencil>,
});

/*
gfx_pipeline!( pipe {
    u_model_view_proj: gfx::Global<[[f32; 4]; 4]> = "u_model_view_proj",
    u_model_view: gfx::Global<[[f32; 4]; 4]> = "u_model_view",
    u_skinning_transforms: gfx::RawVertexBuffer = &[],
    u_texture: gfx::TextureSampler<[f32; 4]> = "u_texture",
    // out_color: gfx::RenderTarget<gfx::format::Srgba8> = "o_Color",
    out_color: gfx::RawRenderTarget = "o_Color",
    out_depth: gfx::DepthTarget<gfx::format::DepthStencil> =
        gfx::preset::depth::LESS_EQUAL_WRITE,
});
*/

gfx_vertex_struct!(SkinnedVertex {
    pos: [f32; 3] = "pos",
    normal: [f32; 3] = "normal",
    uv: [f32; 2] = "uv",
    joint_indices: [i32; 4] = "joint_indices",
    joint_weights: [f32; 4] = "joint_weights", // TODO last weight is redundant
});

impl Default for SkinnedVertex {
    fn default() -> SkinnedVertex {
        SkinnedVertex {
            pos: [0.0; 3],
            normal: [0.0; 3],
            uv: [0.0; 2],
            joint_indices: [0; 4],
            joint_weights: [0.0; 4],
        }
    }
}

fn vtn_to_vertex(a: collada::VTNIndex, obj: &collada::Object) -> SkinnedVertex
{
    let mut vertex: SkinnedVertex = Default::default();
    let position = obj.vertices[a.0];

    vertex.pos = [position.x as f32, position.y as f32, position.z as f32];

    if obj.joint_weights.len() == obj.vertices.len() {
        let weights = obj.joint_weights[a.0];
        vertex.joint_weights = weights.weights;
        vertex.joint_indices = [
            weights.joints[0] as i32,
            weights.joints[1] as i32,
            weights.joints[2] as i32,
            weights.joints[3] as i32,
        ];
    }

    if let Some(uv) = a.1 {
        let uv = obj.tex_vertices[uv];
        vertex.uv = [uv.x as f32, uv.y as f32];
    }

    if let Some(normal) = a.2 {
        let normal = obj.normals[normal];
        vertex.normal = [normal.x as f32, normal.y as f32, normal.z as f32];
    }

    vertex
}

fn get_vertex_index_data(obj: &collada::Object, vertex_data: &mut Vec<SkinnedVertex>, index_data: &mut Vec<u32>) {
    for geom in obj.geometry.iter() {
        let mut i = vertex_data.len() as u32;
        let mut uvs: u32 = 0;
        let mut normals: u32 = 0;
        {
            let mut add = |a: collada::VTNIndex| {
                if let Some(_) = a.1 { uvs += 1; }
                if let Some(_) = a.2 { normals += 1; }
                vertex_data.push(vtn_to_vertex(a, obj));
                index_data.push(i);
                i += 1;
            };
            for shape in geom.shapes.iter() {
                match shape {
                    &collada::Shape::Triangle(a, b, c) => {
                        add(a);
                        add(b);
                        add(c);
                    }
                    _ => {}
                }
            }
        }
    }
}
<commit_msg>Fixed PSO output and primitive types<commit_after>use std::default::Default;
use std::path::Path;

use collada;
use gfx;
use gfx::Typed;
use gfx::traits::*;
use gfx_texture;

use math::*;
use skeleton::Skeleton;
use transform::Transform;

const MAX_JOINTS: usize = 64;

pub struct SkinnedRenderBatch<R: gfx::Resources, T: Transform> {
    skinning_transforms_buffer: gfx::handle::Buffer<R, T>,
    slice: gfx::Slice<R>,
    vertex_buffer: gfx::handle::Buffer<R, SkinnedVertex>,
    texture: (gfx::handle::ShaderResourceView<R, [f32; 4]>, gfx::handle::Sampler<R>),
}

pub struct SkinnedRenderer<R: gfx::Resources, T: Transform> {
    pso: gfx::PipelineState<R, pipe::Meta>,
    skeleton: Skeleton, // TODO Should this be a ref? Should this just be the joints?
    render_batches: Vec<SkinnedRenderBatch<R, T>>,
}

pub trait HasShaderSources<'a> {
    fn vertex_shader_source() -> &'a [u8];
    fn fragment_shader_source() -> &'a [u8];
}

impl<'a> HasShaderSources<'a> for Matrix4<f32> {
    fn vertex_shader_source() -> &'a [u8] {
        include_bytes!("lbs_skinning_150.glslv")
    }
    fn fragment_shader_source() -> &'a [u8] {
        include_bytes!("skinning_150.glslf")
    }
}

impl<'a> HasShaderSources<'a> for DualQuaternion<f32> {
    fn vertex_shader_source() -> &'a [u8] {
        include_bytes!("dlb_skinning_150.glslv")
    }
    fn fragment_shader_source() -> &'a [u8] {
        include_bytes!("skinning_150.glslf")
    }
}

impl<'a, R: gfx::Resources, T: Transform + HasShaderSources<'a>> SkinnedRenderer<R, T> {

    pub fn from_collada<F: gfx::Factory<R>>(
        factory: &mut F,
        collada_document: collada::document::ColladaDocument,
        texture_paths: Vec<&str>, // TODO - read from the COLLADA document (if available)
    ) -> Result<SkinnedRenderer<R, T>, gfx::shade::ProgramError> {
        use gfx::format::Formatted;

        let program = {
            let vs = T::vertex_shader_source();
            let fs = T::fragment_shader_source();
            match factory.link_program(vs, fs) {
                Ok(program_handle) => program_handle,
                Err(e) => return Err(e),
            }
        };

        // TODO: Pass in format as parameter.
        let format = gfx::format::Srgba8::get_format();
        let init = pipe::Init {
            vertex: (),
            u_model_view_proj: "u_model_view_proj",
            u_model_view: "u_model_view",
            u_skinning_transforms: "u_skinning_transforms",
            u_texture: "u_texture",
            out_color: ("out_color", format, gfx::state::MASK_ALL, None),
            out_depth: gfx::preset::depth::LESS_EQUAL_WRITE,
        };
        let pso = factory.create_pipeline_from_program(
            &program,
            gfx::Primitive::TriangleList,
            gfx::state::Rasterizer::new_fill(),
            init
        ).unwrap();

        let sampler = factory.create_sampler(
            gfx::tex::SamplerInfo::new(
                gfx::tex::FilterMethod::Trilinear,
                gfx::tex::WrapMode::Clamp
            )
        );

        let obj_set = collada_document.get_obj_set().unwrap();

        let skeleton_set = collada_document.get_skeletons().unwrap();
        let skeleton = Skeleton::from_collada(&skeleton_set[0]);

        let mut render_batches = Vec::new();

        for (i, object) in obj_set.objects.iter().enumerate().take(6) {

            let mut vertex_data: Vec<SkinnedVertex> = Vec::new();
            let mut index_data: Vec<u32> = Vec::new();

            get_vertex_index_data(&object, &mut vertex_data, &mut index_data);

            let (vbuf, slice) = factory.create_vertex_buffer_with_slice
                (&vertex_data, &index_data[..]);

            let skinning_transforms_buffer = factory.create_buffer_dynamic::<T>(
                MAX_JOINTS, gfx::BufferRole::Uniform, gfx::Bind::empty()).unwrap();

            let texture = gfx_texture::Texture::from_path(
                factory,
                &Path::new(&texture_paths[i]),
                gfx_texture::Flip::None,
                &gfx_texture::TextureSettings::new()
            ).unwrap();

            render_batches.push(SkinnedRenderBatch {
                slice: slice,
                vertex_buffer: vbuf,
                skinning_transforms_buffer: skinning_transforms_buffer,
                texture: (texture.view.clone(), sampler.clone()),
            });
        }

        Ok(SkinnedRenderer {
            pso: pso,
            render_batches: render_batches,
            skeleton: skeleton.clone(),
        })
    }

    pub fn render<C: gfx::CommandBuffer<R>, Rf: gfx::format::RenderFormat> (
        &mut self,
        encoder: &mut gfx::Encoder<R, C>,
        out_color: &gfx::handle::RenderTargetView<R, Rf>,
        out_depth: &gfx::handle::DepthStencilView<R, gfx::format::DepthStencil>,
        view: [[f32; 4]; 4],
        projection: [[f32; 4]; 4],
        joint_poses: &[T]
    ) {

        let skinning_transforms = self.calculate_skinning_transforms(&joint_poses);

        for material in self.render_batches.iter_mut() {
            // FIXME -- should all be able to share the same buffer
            encoder.update_buffer(&material.skinning_transforms_buffer, &skinning_transforms[..], 0).unwrap();

            let data = pipe::Data {
                vertex: material.vertex_buffer.clone(),
                u_model_view_proj: projection,
                u_model_view: view,
                u_skinning_transforms: material.skinning_transforms_buffer.raw().clone(),
                u_texture: material.texture.clone(),
                out_color: out_color.raw().clone(),
                out_depth: out_depth.clone(),
            };

            encoder.draw(&material.slice, &self.pso, &data);
        }
    }

    ///
    /// TODO - don't allocate a new vector
    ///
    pub fn calculate_skinning_transforms(&self, global_poses: &[T]) -> Vec<T> {
        self.skeleton.joints.iter().enumerate().map(|(i, joint)| {
            // TODO avoid conversion...
            global_poses[i].concat(T::from_matrix(joint.inverse_bind_pose))
        }).collect()
    }
}

gfx_pipeline_base!( pipe {
    vertex: gfx::VertexBuffer<SkinnedVertex>,
    u_model_view_proj: gfx::Global<[[f32; 4]; 4]>,
    u_model_view: gfx::Global<[[f32; 4]; 4]>,
    u_skinning_transforms: gfx::RawConstantBuffer,
    u_texture: gfx::TextureSampler<[f32; 4]>,
    out_color: gfx::RawRenderTarget,
    out_depth: gfx::DepthTarget<gfx::format::DepthStencil>,
});

/*
gfx_pipeline!( pipe {
    u_model_view_proj: gfx::Global<[[f32; 4]; 4]> = "u_model_view_proj",
    u_model_view: gfx::Global<[[f32; 4]; 4]> = "u_model_view",
    u_skinning_transforms: gfx::RawVertexBuffer = &[],
    u_texture: gfx::TextureSampler<[f32; 4]> = "u_texture",
    // out_color: gfx::RenderTarget<gfx::format::Srgba8> = "o_Color",
    out_color: gfx::RawRenderTarget = "o_Color",
    out_depth: gfx::DepthTarget<gfx::format::DepthStencil> =
        gfx::preset::depth::LESS_EQUAL_WRITE,
});
*/

gfx_vertex_struct!(SkinnedVertex {
    pos: [f32; 3] = "pos",
    normal: [f32; 3] = "normal",
    uv: [f32; 2] = "uv",
    joint_indices: [i32; 4] = "joint_indices",
    joint_weights: [f32; 4] = "joint_weights", // TODO last weight is redundant
});

impl Default for SkinnedVertex {
    fn default() -> SkinnedVertex {
        SkinnedVertex {
            pos: [0.0; 3],
            normal: [0.0; 3],
            uv: [0.0; 2],
            joint_indices: [0; 4],
            joint_weights: [0.0; 4],
        }
    }
}

fn vtn_to_vertex(a: collada::VTNIndex, obj: &collada::Object) -> SkinnedVertex
{
    let mut vertex: SkinnedVertex = Default::default();
    let position = obj.vertices[a.0];

    vertex.pos = [position.x as f32, position.y as f32, position.z as f32];

    if obj.joint_weights.len() == obj.vertices.len() {
        let weights = obj.joint_weights[a.0];
        vertex.joint_weights = weights.weights;
        vertex.joint_indices = [
            weights.joints[0] as i32,
            weights.joints[1] as i32,
            weights.joints[2] as i32,
            weights.joints[3] as i32,
        ];
    }

    if let Some(uv) = a.1 {
        let uv = obj.tex_vertices[uv];
        vertex.uv = [uv.x as f32, uv.y as f32];
    }

    if let Some(normal) = a.2 {
        let normal = obj.normals[normal];
        vertex.normal = [normal.x as f32, normal.y as f32, normal.z as f32];
    }

    vertex
}

fn get_vertex_index_data(obj: &collada::Object, vertex_data: &mut Vec<SkinnedVertex>, index_data: &mut Vec<u32>) {
    for geom in obj.geometry.iter() {
        let mut i = vertex_data.len() as u32;
        let mut uvs: u32 = 0;
        let mut normals: u32 = 0;
        {
            let mut add = |a: collada::VTNIndex| {
                if let Some(_) = a.1 { uvs += 1; }
                if let Some(_) = a.2 { normals += 1; }
                vertex_data.push(vtn_to_vertex(a, obj));
                index_data.push(i);
                i += 1;
            };
            for shape in geom.shapes.iter() {
                match shape {
                    &collada::Shape::Triangle(a, b, c) => {
                        add(a);
                        add(b);
                        add(c);
                    }
                    _ => {}
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::Deref;
use std::rc::Rc;

use wayland_server::protocol::wl_touch::WlTouch;
use wayland_server::{Filter, Main};

use crate::backend::input::TouchSlot;
use crate::utils::{Logical, Point};
use crate::wayland::seat::wl_surface::WlSurface;

/// An handle to a touch handler.
///
/// It can be cloned and all clones manipulate the same internal state.
///
/// This handle gives you access to an interface to send touch events to your
/// clients.
#[derive(Debug, Clone)]
pub struct TouchHandle {
    inner: Rc<RefCell<TouchInternal>>,
}

impl TouchHandle {
    pub(crate) fn new() -> Self {
        Self {
            inner: Default::default(),
        }
    }

    /// Register a new touch handle to this handler
    ///
    /// This should be done first, before anything else is done with this touch handle.
    pub(crate) fn new_touch(&self, touch: WlTouch) {
        self.inner.borrow_mut().known_handles.push(touch);
    }

    /// Notify clients about new touch points.
    pub fn down(
        &mut self,
        serial: u32,
        time: u32,
        surface: &WlSurface,
        surface_offset: Point<i32, Logical>,
        slot: TouchSlot,
        location: Point<f64, Logical>,
    ) {
        self.inner
            .borrow_mut()
            .down(serial, time, surface, surface_offset, slot, location);
    }

    /// Notify clients about touch point removal.
    pub fn up(&self, serial: u32, time: u32, slot: TouchSlot) {
        self.inner.borrow_mut().up(serial, time, slot);
    }

    /// Notify clients about touch motion.
    pub fn motion(&self, time: u32, slot: TouchSlot, location: Point<f64, Logical>) {
        self.inner.borrow_mut().motion(time, slot, location);
    }

    /// Notify clients about touch shape changes.
    pub fn shape(&self, slot: TouchSlot, major: f64, minor: f64) {
        self.inner.borrow_mut().shape(slot, major, minor);
    }

    /// Notify clients about touch shape orientation.
    pub fn orientation(&self, slot: TouchSlot, orientation: f64) {
        self.inner.borrow_mut().orientation(slot, orientation);
    }

    /// Notify clients about touch cancellation.
    ///
    /// This should be sent by the compositor when the currently active touch
    /// slot was recognized as a gesture.
    pub fn cancel(&self) {
        self.inner.borrow_mut().cancel();
    }
}

/// Touch-slot focused Wayland client state.
#[derive(Default, Debug)]
struct TouchFocus {
    surface_offset: Point<f64, Logical>,
    handles: Vec<WlTouch>,
}

#[derive(Default, Debug)]
struct TouchInternal {
    known_handles: Vec<WlTouch>,
    focus: HashMap<TouchSlot, TouchFocus>,
}

impl TouchInternal {
    fn down(
        &mut self,
        serial: u32,
        time: u32,
        surface: &WlSurface,
        surface_offset: Point<i32, Logical>,
        slot: TouchSlot,
        location: Point<f64, Logical>,
    ) {
        // Update focused client state.
        let focus = self.focus.entry(slot).or_default();
        focus.surface_offset = surface_offset.to_f64();
        focus.handles.clear();

        // Select all WlTouch instances associated to the active WlSurface.
        for handle in &self.known_handles {
            if handle.as_ref().same_client_as(surface.as_ref()) {
                focus.handles.push(handle.clone());
            }
        }

        let (x, y) = (location - focus.surface_offset).into();
        self.with_focused_handles(slot, |handle| {
            handle.down(serial, time, surface, slot.into(), x, y)
        });
    }

    fn up(&self, serial: u32, time: u32, slot: TouchSlot) {
        self.with_focused_handles(slot, |handle| handle.up(serial, time, slot.into()));
    }

    fn motion(&self, time: u32, slot: TouchSlot, location: Point<f64, Logical>) {
        let focus = match self.focus.get(&slot) {
            Some(slot) => slot,
            None => return,
        };

        let (x, y) = (location - focus.surface_offset).into();
        self.with_focused_handles(slot, |handle| handle.motion(time, slot.into(), x, y));
    }

    fn shape(&self, slot: TouchSlot, major: f64, minor: f64) {
        self.with_focused_handles(slot, |handle| {
            if handle.as_ref().version() >= 6 {
                handle.shape(slot.into(), major, minor);
            }
        });
    }

    fn orientation(&self, slot: TouchSlot, orientation: f64) {
        self.with_focused_handles(slot, |handle| {
            if handle.as_ref().version() >= 6 {
                handle.orientation(slot.into(), orientation);
            }
        });
    }

    // TODO: In theory doesn't need to be sent for WlTouch that isn't in the focus hashmap?
    fn cancel(&self) {
        for handle in &self.known_handles {
            handle.cancel();
        }
    }

    // TODO: Document this also sends frame every time.
    #[inline]
    fn with_focused_handles<F>(&self, slot: TouchSlot, mut f: F)
    where
        F: FnMut(&WlTouch),
    {
        if let Some(focus) = self.focus.get(&slot) {
            for handle in &focus.handles {
                f(handle);
                handle.frame();
            }
        }
    }
}

pub(crate) fn implement_touch(touch: Main<WlTouch>, handle: Option<&TouchHandle>) -> WlTouch {
    // The sole `Release` request is already handled by our destructor.
    touch.quick_assign(|_touch, _request, _data| {});

    // Remove from touch handles on destroy.
    if let Some(handle) = handle {
        let inner = handle.inner.clone();
        touch.assign_destructor(Filter::new(move |touch: WlTouch, _, _| {
            inner
                .borrow_mut()
                .known_handles
                .retain(|t| !t.as_ref().equals(touch.as_ref()))
        }));
    }

    touch.deref().clone()
}
<commit_msg>Use `Serial` type for touch events instead of u32<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::Deref;
use std::rc::Rc;

use wayland_server::protocol::wl_touch::WlTouch;
use wayland_server::{Filter, Main};

use crate::backend::input::TouchSlot;
use crate::utils::{Logical, Point};
use crate::wayland::seat::wl_surface::WlSurface;
use crate::wayland::Serial;

/// An handle to a touch handler.
///
/// It can be cloned and all clones manipulate the same internal state.
///
/// This handle gives you access to an interface to send touch events to your
/// clients.
#[derive(Debug, Clone)]
pub struct TouchHandle {
    inner: Rc<RefCell<TouchInternal>>,
}

impl TouchHandle {
    pub(crate) fn new() -> Self {
        Self {
            inner: Default::default(),
        }
    }

    /// Register a new touch handle to this handler
    ///
    /// This should be done first, before anything else is done with this touch handle.
    pub(crate) fn new_touch(&self, touch: WlTouch) {
        self.inner.borrow_mut().known_handles.push(touch);
    }

    /// Notify clients about new touch points.
    pub fn down(
        &mut self,
        serial: Serial,
        time: u32,
        surface: &WlSurface,
        surface_offset: Point<i32, Logical>,
        slot: TouchSlot,
        location: Point<f64, Logical>,
    ) {
        self.inner
            .borrow_mut()
            .down(serial, time, surface, surface_offset, slot, location);
    }

    /// Notify clients about touch point removal.
    pub fn up(&self, serial: Serial, time: u32, slot: TouchSlot) {
        self.inner.borrow_mut().up(serial, time, slot);
    }

    /// Notify clients about touch motion.
    pub fn motion(&self, time: u32, slot: TouchSlot, location: Point<f64, Logical>) {
        self.inner.borrow_mut().motion(time, slot, location);
    }

    /// Notify clients about touch shape changes.
    pub fn shape(&self, slot: TouchSlot, major: f64, minor: f64) {
        self.inner.borrow_mut().shape(slot, major, minor);
    }

    /// Notify clients about touch shape orientation.
    pub fn orientation(&self, slot: TouchSlot, orientation: f64) {
        self.inner.borrow_mut().orientation(slot, orientation);
    }

    /// Notify clients about touch cancellation.
    ///
    /// This should be sent by the compositor when the currently active touch
    /// slot was recognized as a gesture.
    pub fn cancel(&self) {
        self.inner.borrow_mut().cancel();
    }
}

/// Touch-slot focused Wayland client state.
#[derive(Default, Debug)]
struct TouchFocus {
    surface_offset: Point<f64, Logical>,
    handles: Vec<WlTouch>,
}

#[derive(Default, Debug)]
struct TouchInternal {
    known_handles: Vec<WlTouch>,
    focus: HashMap<TouchSlot, TouchFocus>,
}

impl TouchInternal {
    fn down(
        &mut self,
        serial: Serial,
        time: u32,
        surface: &WlSurface,
        surface_offset: Point<i32, Logical>,
        slot: TouchSlot,
        location: Point<f64, Logical>,
    ) {
        // Update focused client state.
        let focus = self.focus.entry(slot).or_default();
        focus.surface_offset = surface_offset.to_f64();
        focus.handles.clear();

        // Select all WlTouch instances associated to the active WlSurface.
        for handle in &self.known_handles {
            if handle.as_ref().same_client_as(surface.as_ref()) {
                focus.handles.push(handle.clone());
            }
        }

        let (x, y) = (location - focus.surface_offset).into();
        self.with_focused_handles(slot, |handle| {
            handle.down(serial.into(), time, surface, slot.into(), x, y)
        });
    }

    fn up(&self, serial: Serial, time: u32, slot: TouchSlot) {
        self.with_focused_handles(slot, |handle| handle.up(serial.into(), time, slot.into()));
    }

    fn motion(&self, time: u32, slot: TouchSlot, location: Point<f64, Logical>) {
        let focus = match self.focus.get(&slot) {
            Some(slot) => slot,
            None => return,
        };

        let (x, y) = (location - focus.surface_offset).into();
        self.with_focused_handles(slot, |handle| handle.motion(time, slot.into(), x, y));
    }

    fn shape(&self, slot: TouchSlot, major: f64, minor: f64) {
        self.with_focused_handles(slot, |handle| {
            if handle.as_ref().version() >= 6 {
                handle.shape(slot.into(), major, minor);
            }
        });
    }

    fn orientation(&self, slot: TouchSlot, orientation: f64) {
        self.with_focused_handles(slot, |handle| {
            if handle.as_ref().version() >= 6 {
                handle.orientation(slot.into(), orientation);
            }
        });
    }

    // TODO: In theory doesn't need to be sent for WlTouch that isn't in the focus hashmap?
    fn cancel(&self) {
        for handle in &self.known_handles {
            handle.cancel();
        }
    }

    // TODO: Document this also sends frame every time.
    #[inline]
    fn with_focused_handles<F>(&self, slot: TouchSlot, mut f: F)
    where
        F: FnMut(&WlTouch),
    {
        if let Some(focus) = self.focus.get(&slot) {
            for handle in &focus.handles {
                f(handle);
                handle.frame();
            }
        }
    }
}

pub(crate) fn implement_touch(touch: Main<WlTouch>, handle: Option<&TouchHandle>) -> WlTouch {
    // The sole `Release` request is already handled by our destructor.
    touch.quick_assign(|_touch, _request, _data| {});

    // Remove from touch handles on destroy.
    if let Some(handle) = handle {
        let inner = handle.inner.clone();
        touch.assign_destructor(Filter::new(move |touch: WlTouch, _, _| {
            inner
                .borrow_mut()
                .known_handles
                .retain(|t| !t.as_ref().equals(touch.as_ref()))
        }));
    }

    touch.deref().clone()
}
<|endoftext|>


<commit_before>use std::default::Default;
use ToGlEnum;
use gl;

/// Function to use for out-of-bounds samples.
///
/// This is how GL must handle samples that are outside the texture.
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum SamplerWrapFunction {
    /// Samples at coord `x + 1` map to coord `x`.
    Repeat,

    /// Samples at coord `x + 1` map to coord `1 - x`.
    Mirror,

    /// Samples at coord `x + 1` map to coord `1`.
    Clamp
}

impl ToGlEnum for SamplerWrapFunction {
    fn to_glenum(&self) -> gl::types::GLenum {
        match *self {
            SamplerWrapFunction::Repeat => gl::REPEAT,
            SamplerWrapFunction::Mirror => gl::MIRRORED_REPEAT,
            SamplerWrapFunction::Clamp => gl::CLAMP_TO_EDGE,
        }
    }
}

/// The function that the GPU will use when loading the value of a texel.
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum MagnifySamplerFilter {
    /// The nearest texel will be loaded.
    Nearest,

    /// All nearby texels will be loaded and their values will be merged.
    Linear,
}

impl ToGlEnum for MagnifySamplerFilter {
    fn to_glenum(&self) -> gl::types::GLenum {
        match *self {
            MagnifySamplerFilter::Nearest => gl::NEAREST,
            MagnifySamplerFilter::Linear => gl::LINEAR,
        }
    }
}

/// The function that the GPU will use when loading the value of a texel.
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum MinifySamplerFilter {
    /// The nearest texel will be loaded.
    ///
    /// Only uses the main texture, mipmaps are totally ignored.
    Nearest,

    /// All nearby texels will be loaded and their values will be merged.
    ///
    /// Only uses the main texture, mipmaps are totally ignored.
    Linear,

    /// The nearest texel of the nearest mipmap will be loaded.
    NearestMipmapNearest,

    /// Takes the nearest texel from the two nearest mipmaps, and merges them.
    LinearMipmapNearest,

    /// Same as `Linear`, but from the nearest mipmap.
    NearestMipmapLinear,

    /// Same as `Linear`, but from the two nearest mipmaps.
    LinearMipmapLinear,
}

impl ToGlEnum for MinifySamplerFilter {
    fn to_glenum(&self) -> gl::types::GLenum {
        match *self {
            MinifySamplerFilter::Nearest => gl::NEAREST,
            MinifySamplerFilter::Linear => gl::LINEAR,
            MinifySamplerFilter::NearestMipmapNearest => gl::NEAREST_MIPMAP_NEAREST,
            MinifySamplerFilter::LinearMipmapNearest => gl::LINEAR_MIPMAP_NEAREST,
            MinifySamplerFilter::NearestMipmapLinear => gl::NEAREST_MIPMAP_LINEAR,
            MinifySamplerFilter::LinearMipmapLinear => gl::LINEAR_MIPMAP_LINEAR,
        }
    }
}

/// A sampler.
pub struct Sampler<'t, T: 't>(pub &'t T, pub SamplerBehavior);

impl<'t, T: 't> Sampler<'t, T> {
    /// Builds a new `Sampler` with default parameters.
    pub fn new(texture: &'t T) -> Sampler<'t, T> {
        Sampler(texture, Default::default())
    }

    /// Changes the wrap functions of all three coordinates.
    pub fn wrap_function(mut self, function: SamplerWrapFunction) -> Sampler<'t, T> {
        self.1.wrap_function = (function, function, function);
        self
    }

    /// Changes the minifying filter of the sampler.
    pub fn minify_filter(mut self, filter: MinifySamplerFilter) -> Sampler<'t, T> {
        self.1.minify_filter = filter;
        self
    }

    /// Changes the magnifying filter of the sampler.
    pub fn magnify_filter(mut self, filter: MagnifySamplerFilter) -> Sampler<'t, T> {
        self.1.magnify_filter = filter;
        self
    }

    /// Changes the magnifying filter of the sampler.
    pub fn anisotropy(mut self, level: u16) -> Sampler<'t, T> {
        self.1.max_anisotropy = level;
        self
    }
}

/// Behavior of a sampler.
// TODO: GL_TEXTURE_BORDER_COLOR, GL_TEXTURE_MIN_LOD, GL_TEXTURE_MAX_LOD, GL_TEXTURE_LOD_BIAS,
//       GL_TEXTURE_COMPARE_MODE, GL_TEXTURE_COMPARE_FUNC
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct SamplerBehavior {
    /// Functions to use for the X, Y, and Z coordinates.
    pub wrap_function: (SamplerWrapFunction, SamplerWrapFunction, SamplerWrapFunction),

    /// Filter to use when minifying the texture.
    pub minify_filter: MinifySamplerFilter,

    /// Filter to use when magnifying the texture.
    pub magnify_filter: MagnifySamplerFilter,

    /// `1` means no anisotropic filtering, any value above `1` sets the max anisotropy.
    ///
    /// ## Compatibility
    ///
    /// This parameter is always available. However it is ignored on hardware that does
    /// not support anisotropic filtering.
    ///
    /// If you set the value to a value higher than what the hardware supports, it will
    /// be clamped.
    pub max_anisotropy: u16,
}

impl Default for SamplerBehavior {
    fn default() -> SamplerBehavior {
        SamplerBehavior {
            wrap_function: (
                SamplerWrapFunction::Mirror,
                SamplerWrapFunction::Mirror,
                SamplerWrapFunction::Mirror
            ),
            minify_filter: MinifySamplerFilter::Linear,
            magnify_filter: MagnifySamplerFilter::Linear,
            max_anisotropy: 1,
        }
    }
}
<commit_msg>Set the default minify filter to LinearMipmapLinear<commit_after>use std::default::Default;
use ToGlEnum;
use gl;

/// Function to use for out-of-bounds samples.
///
/// This is how GL must handle samples that are outside the texture.
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum SamplerWrapFunction {
    /// Samples at coord `x + 1` map to coord `x`.
    Repeat,

    /// Samples at coord `x + 1` map to coord `1 - x`.
    Mirror,

    /// Samples at coord `x + 1` map to coord `1`.
    Clamp
}

impl ToGlEnum for SamplerWrapFunction {
    fn to_glenum(&self) -> gl::types::GLenum {
        match *self {
            SamplerWrapFunction::Repeat => gl::REPEAT,
            SamplerWrapFunction::Mirror => gl::MIRRORED_REPEAT,
            SamplerWrapFunction::Clamp => gl::CLAMP_TO_EDGE,
        }
    }
}

/// The function that the GPU will use when loading the value of a texel.
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum MagnifySamplerFilter {
    /// The nearest texel will be loaded.
    Nearest,

    /// All nearby texels will be loaded and their values will be merged.
    Linear,
}

impl ToGlEnum for MagnifySamplerFilter {
    fn to_glenum(&self) -> gl::types::GLenum {
        match *self {
            MagnifySamplerFilter::Nearest => gl::NEAREST,
            MagnifySamplerFilter::Linear => gl::LINEAR,
        }
    }
}

/// The function that the GPU will use when loading the value of a texel.
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum MinifySamplerFilter {
    /// The nearest texel will be loaded.
    ///
    /// Only uses the main texture, mipmaps are totally ignored.
    Nearest,

    /// All nearby texels will be loaded and their values will be merged.
    ///
    /// Only uses the main texture, mipmaps are totally ignored.
    Linear,

    /// The nearest texel of the nearest mipmap will be loaded.
    NearestMipmapNearest,

    /// Takes the nearest texel from the two nearest mipmaps, and merges them.
    LinearMipmapNearest,

    /// Same as `Linear`, but from the nearest mipmap.
    NearestMipmapLinear,

    /// Same as `Linear`, but from the two nearest mipmaps.
    LinearMipmapLinear,
}

impl ToGlEnum for MinifySamplerFilter {
    fn to_glenum(&self) -> gl::types::GLenum {
        match *self {
            MinifySamplerFilter::Nearest => gl::NEAREST,
            MinifySamplerFilter::Linear => gl::LINEAR,
            MinifySamplerFilter::NearestMipmapNearest => gl::NEAREST_MIPMAP_NEAREST,
            MinifySamplerFilter::LinearMipmapNearest => gl::LINEAR_MIPMAP_NEAREST,
            MinifySamplerFilter::NearestMipmapLinear => gl::NEAREST_MIPMAP_LINEAR,
            MinifySamplerFilter::LinearMipmapLinear => gl::LINEAR_MIPMAP_LINEAR,
        }
    }
}

/// A sampler.
pub struct Sampler<'t, T: 't>(pub &'t T, pub SamplerBehavior);

impl<'t, T: 't> Sampler<'t, T> {
    /// Builds a new `Sampler` with default parameters.
    pub fn new(texture: &'t T) -> Sampler<'t, T> {
        Sampler(texture, Default::default())
    }

    /// Changes the wrap functions of all three coordinates.
    pub fn wrap_function(mut self, function: SamplerWrapFunction) -> Sampler<'t, T> {
        self.1.wrap_function = (function, function, function);
        self
    }

    /// Changes the minifying filter of the sampler.
    pub fn minify_filter(mut self, filter: MinifySamplerFilter) -> Sampler<'t, T> {
        self.1.minify_filter = filter;
        self
    }

    /// Changes the magnifying filter of the sampler.
    pub fn magnify_filter(mut self, filter: MagnifySamplerFilter) -> Sampler<'t, T> {
        self.1.magnify_filter = filter;
        self
    }

    /// Changes the magnifying filter of the sampler.
    pub fn anisotropy(mut self, level: u16) -> Sampler<'t, T> {
        self.1.max_anisotropy = level;
        self
    }
}

/// Behavior of a sampler.
// TODO: GL_TEXTURE_BORDER_COLOR, GL_TEXTURE_MIN_LOD, GL_TEXTURE_MAX_LOD, GL_TEXTURE_LOD_BIAS,
//       GL_TEXTURE_COMPARE_MODE, GL_TEXTURE_COMPARE_FUNC
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub struct SamplerBehavior {
    /// Functions to use for the X, Y, and Z coordinates.
    pub wrap_function: (SamplerWrapFunction, SamplerWrapFunction, SamplerWrapFunction),

    /// Filter to use when minifying the texture.
    pub minify_filter: MinifySamplerFilter,

    /// Filter to use when magnifying the texture.
    pub magnify_filter: MagnifySamplerFilter,

    /// `1` means no anisotropic filtering, any value above `1` sets the max anisotropy.
    ///
    /// ## Compatibility
    ///
    /// This parameter is always available. However it is ignored on hardware that does
    /// not support anisotropic filtering.
    ///
    /// If you set the value to a value higher than what the hardware supports, it will
    /// be clamped.
    pub max_anisotropy: u16,
}

impl Default for SamplerBehavior {
    fn default() -> SamplerBehavior {
        SamplerBehavior {
            wrap_function: (
                SamplerWrapFunction::Mirror,
                SamplerWrapFunction::Mirror,
                SamplerWrapFunction::Mirror
            ),
            minify_filter: MinifySamplerFilter::LinearMipmapLinear,
            magnify_filter: MagnifySamplerFilter::Linear,
            max_anisotropy: 1,
        }
    }
}
<|endoftext|>


<commit_before>// NOTE: This is a copy and adaptation of the original mod "size" from
// the crate "termion".
//
// The original "termion::terminal_size()" function only checks the size
// against the STDOUT, but to interact with the user we use a custom
// tty (/dev/tty to be precise), so we need to use a different file
// descriptor. I don't know if this "feature" will be available in
// "termion" any time soon, so fo the moment I adapt the original code
// to my needs.
use std::io;
use libc::{c_ushort, c_int};

#[cfg(target_os = "linux")]
pub const TIOCGWINSZ: usize = 0x00005413;

#[cfg(not(target_os = "linux"))]
pub const TIOCGWINSZ: usize = 0x40087468;

#[repr(C)]
struct TermSize {
    row: c_ushort,
    col: c_ushort,
    _x: c_ushort,
    _y: c_ushort,
}

#[cfg(all(target_env = "musl", target_pointer_width = "64"))]
fn tiocgwinsz() -> i64 {
    TIOCGWINSZ as i64
}

#[cfg(all(target_env = "musl", target_pointer_width = "32"))]
fn tiocgwinsz() -> i32 {
    TIOCGWINSZ as i32
}

#[cfg(all(not(target_env = "musl"), target_pointer_width = "64"))]
fn tiocgwinsz() -> u64 {
    TIOCGWINSZ as u64
}

#[cfg(all(not(target_env = "musl"), target_pointer_width = "32"))]
fn tiocgwinsz() -> u32 {
    TIOCGWINSZ as u32
}

// Get the size of the terminal.
pub fn terminal_size(fileno: c_int) -> io::Result<(u16, u16)> {
    use libc::ioctl;
    use std::mem;

    unsafe {
        let mut size: TermSize = mem::zeroed();

        if ioctl(fileno, tiocgwinsz(), &mut size as *mut _) == 0 {
            Ok((size.col as u16, size.row as u16))
        } else {
            Err(io::Error::new(
                io::ErrorKind::Other,
                "Unable to get the terminal size.",
            ))
        }
    }
}

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

    #[test]
    fn test_size() {
        use libc::STDOUT_FILENO;

        assert!(terminal_size(STDOUT_FILENO).is_ok());
    }
}
<commit_msg>Always use TIOCGWINSZ as i32 on musl env<commit_after>// NOTE: This is a copy and adaptation of the original mod "size" from
// the crate "termion".
//
// The original "termion::terminal_size()" function only checks the size
// against the STDOUT, but to interact with the user we use a custom
// tty (/dev/tty to be precise), so we need to use a different file
// descriptor. I don't know if this "feature" will be available in
// "termion" any time soon, so fo the moment I adapt the original code
// to my needs.
use std::io;
use libc::{c_ushort, c_int};

#[cfg(target_os = "linux")]
pub const TIOCGWINSZ: usize = 0x00005413;

#[cfg(not(target_os = "linux"))]
pub const TIOCGWINSZ: usize = 0x40087468;

#[repr(C)]
struct TermSize {
    row: c_ushort,
    col: c_ushort,
    _x: c_ushort,
    _y: c_ushort,
}

#[cfg(target_env = "musl")]
fn tiocgwinsz() -> i32 {
    TIOCGWINSZ as i32
}

#[cfg(all(not(target_env = "musl"), target_pointer_width = "64"))]
fn tiocgwinsz() -> u64 {
    TIOCGWINSZ as u64
}

#[cfg(all(not(target_env = "musl"), target_pointer_width = "32"))]
fn tiocgwinsz() -> u32 {
    TIOCGWINSZ as u32
}

// Get the size of the terminal.
pub fn terminal_size(fileno: c_int) -> io::Result<(u16, u16)> {
    use libc::ioctl;
    use std::mem;

    unsafe {
        let mut size: TermSize = mem::zeroed();

        if ioctl(fileno, tiocgwinsz(), &mut size as *mut _) == 0 {
            Ok((size.col as u16, size.row as u16))
        } else {
            Err(io::Error::new(
                io::ErrorKind::Other,
                "Unable to get the terminal size.",
            ))
        }
    }
}

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

    #[test]
    fn test_size() {
        use libc::STDOUT_FILENO;

        assert!(terminal_size(STDOUT_FILENO).is_ok());
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::collections::BTreeMap;
use std::io::BufRead;
use std::result::Result as RResult;

use toml::Value;
use uuid::Uuid;

use task_hookrs::task::Task as TTask;
use task_hookrs::import::{import_task, import_tasks};

use libimagstore::store::{FileLockEntry, Store};
use libimagstore::storeid::{IntoStoreId, StoreIdIterator};
use module_path::ModuleEntryPath;

use error::TodoErrorKind as TEK;
use error::TodoError as TE;
use error::Result;
use error::ResultExt;

/// Task struct containing a `FileLockEntry`
pub trait TaskStore<'a> {
    fn import_task_from_reader<R: BufRead>(&'a self, r: R) -> Result<(FileLockEntry<'a>, String, Uuid)>;
    fn get_task_from_import<R: BufRead>(&'a self, r: R) -> Result<RResult<FileLockEntry<'a>, String>>;
    fn get_task_from_string(&'a self, s: String) -> Result<RResult<FileLockEntry<'a>, String>>;
    fn get_task_from_uuid(&'a self, uuid: Uuid) -> Result<Option<FileLockEntry<'a>>>;
    fn retrieve_task_from_import<R: BufRead>(&'a self, r: R) -> Result<FileLockEntry<'a>>;
    fn retrieve_task_from_string(&'a self, s: String) -> Result<FileLockEntry<'a>>;
    fn delete_tasks_by_imports<R: BufRead>(&self, r: R) -> Result<()>;
    fn delete_task_by_uuid(&self, uuid: Uuid) -> Result<()>;
    fn all_tasks(&self) -> Result<StoreIdIterator>;
    fn new_from_twtask(&'a self, task: TTask) -> Result<FileLockEntry<'a>>;
}

impl<'a> TaskStore<'a> for Store {

    fn import_task_from_reader<R: BufRead>(&'a self, mut r: R) -> Result<(FileLockEntry<'a>, String, Uuid)> {
        let mut line = String::new();
        try!(r.read_line(&mut line).map_err(|_| TE::from_kind(TEK::UTF8Error)));
        import_task(&line.as_str())
            .map_err(|_| TE::from_kind(TEK::ImportError))
            .and_then(|t| {
                let uuid = t.uuid().clone();
                self.new_from_twtask(t).map(|t| (t, line, uuid))
            })
    }

    /// Get a task from an import string. That is: read the imported string, get the UUID from it
    /// and try to load this UUID from store.
    ///
    /// Possible return values are:
    ///
    /// * Ok(Ok(Task))
    /// * Ok(Err(String)) - where the String is the String read from the `r` parameter
    /// * Err(_)          - where the error is an error that happened during evaluation
    ///
    fn get_task_from_import<R: BufRead>(&'a self, mut r: R) -> Result<RResult<FileLockEntry<'a>, String>> {
        let mut line = String::new();
        try!(r.read_line(&mut line).chain_err(|| TEK::UTF8Error));
        self.get_task_from_string(line)
    }

    /// Get a task from a String. The String is expected to contain the JSON-representation of the
    /// Task to get from the store (only the UUID really matters in this case)
    ///
    /// For an explanation on the return values see `Task::get_from_import()`.
    fn get_task_from_string(&'a self, s: String) -> Result<RResult<FileLockEntry<'a>, String>> {
        import_task(s.as_str())
            .map_err(|_| TE::from_kind(TEK::ImportError))
            .map(|t| t.uuid().clone())
            .and_then(|uuid| self.get_task_from_uuid(uuid))
            .and_then(|o| match o {
                None    => Ok(Err(s)),
                Some(t) => Ok(Ok(t)),
            })
    }

    /// Get a task from an UUID.
    ///
    /// If there is no task with this UUID, this returns `Ok(None)`.
    fn get_task_from_uuid(&'a self, uuid: Uuid) -> Result<Option<FileLockEntry<'a>>> {
        ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
            .into_storeid()
            .and_then(|store_id| self.get(store_id))
            .chain_err(|| TEK::StoreError)
    }

    /// Same as Task::get_from_import() but uses Store::retrieve() rather than Store::get(), to
    /// implicitely create the task if it does not exist.
    fn retrieve_task_from_import<R: BufRead>(&'a self, mut r: R) -> Result<FileLockEntry<'a>> {
        let mut line = String::new();
        try!(r.read_line(&mut line).chain_err(|| TEK::UTF8Error));
        self.retrieve_task_from_string(line)
    }

    /// Retrieve a task from a String. The String is expected to contain the JSON-representation of
    /// the Task to retrieve from the store (only the UUID really matters in this case)
    fn retrieve_task_from_string(&'a self, s: String) -> Result<FileLockEntry<'a>> {
        self.get_task_from_string(s)
            .and_then(|opt| match opt {
                Ok(task)    => Ok(task),
                Err(string) => import_task(string.as_str())
                    .map_err(|_| TE::from_kind(TEK::ImportError))
                    .and_then(|t| self.new_from_twtask(t)),
            })
    }

    fn delete_tasks_by_imports<R: BufRead>(&self, r: R) -> Result<()> {
        use serde_json::ser::to_string as serde_to_string;
        use task_hookrs::status::TaskStatus;

        for (counter, res_ttask) in import_tasks(r).into_iter().enumerate() {
            match res_ttask {
                Ok(ttask) => {
                    if counter % 2 == 1 {
                        // Only every second task is needed, the first one is the
                        // task before the change, and the second one after
                        // the change. The (maybe modified) second one is
                        // expected by taskwarrior.
                        match serde_to_string(&ttask).chain_err(|| TEK::ImportError) {
                            // use println!() here, as we talk with TW
                            Ok(val) => println!("{}", val),
                            Err(e)  => return Err(e),
                        }

                        // Taskwarrior does not have the concept of deleted tasks, but only modified
                        // ones.
                        //
                        // Here we check if the status of a task is deleted and if yes, we delete it
                        // from the store.
                        if *ttask.status() == TaskStatus::Deleted {
                            match self.delete_task_by_uuid(*ttask.uuid()) {
                                Ok(_)  => info!("Deleted task {}", *ttask.uuid()),
                                Err(e) => return Err(e),
                            }
                        }
                    } // end if c % 2
                },
                Err(e) => return Err(TE::from_kind(TEK::ImportError)),
            }
        }
        Ok(())
    }

    fn delete_task_by_uuid(&self, uuid: Uuid) -> Result<()> {
        ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
            .into_storeid()
            .and_then(|id| self.delete(id))
            .chain_err(|| TEK::StoreError)
    }

    fn all_tasks(&self) -> Result<StoreIdIterator> {
        self.retrieve_for_module("todo/taskwarrior")
            .chain_err(|| TEK::StoreError)
    }

    fn new_from_twtask(&'a self, task: TTask) -> Result<FileLockEntry<'a>> {
        use toml_query::read::TomlValueReadExt;
        use toml_query::set::TomlValueSetExt;

        let uuid     = task.uuid();
        ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
            .into_storeid()
            .chain_err(|| TEK::StoreIdError)
            .and_then(|id| {
                self.retrieve(id)
                    .chain_err(|| TEK::StoreError)
                    .and_then(|mut fle| {
                        {
                            let hdr = fle.get_header_mut();
                            if try!(hdr.read("todo").chain_err(|| TEK::StoreError)).is_none() {
                                try!(hdr
                                    .set("todo", Value::Table(BTreeMap::new()))
                                    .chain_err(|| TEK::StoreError));
                            }

                            try!(hdr.set("todo.uuid", Value::String(format!("{}",uuid)))
                                 .chain_err(|| TEK::StoreError));
                        }

                        // If none of the errors above have returned the function, everything is fine
                        Ok(fle)
                    })
            })

    }

}

<commit_msg>Remove unused variable<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::collections::BTreeMap;
use std::io::BufRead;
use std::result::Result as RResult;

use toml::Value;
use uuid::Uuid;

use task_hookrs::task::Task as TTask;
use task_hookrs::import::{import_task, import_tasks};

use libimagstore::store::{FileLockEntry, Store};
use libimagstore::storeid::{IntoStoreId, StoreIdIterator};
use module_path::ModuleEntryPath;

use error::TodoErrorKind as TEK;
use error::TodoError as TE;
use error::Result;
use error::ResultExt;

/// Task struct containing a `FileLockEntry`
pub trait TaskStore<'a> {
    fn import_task_from_reader<R: BufRead>(&'a self, r: R) -> Result<(FileLockEntry<'a>, String, Uuid)>;
    fn get_task_from_import<R: BufRead>(&'a self, r: R) -> Result<RResult<FileLockEntry<'a>, String>>;
    fn get_task_from_string(&'a self, s: String) -> Result<RResult<FileLockEntry<'a>, String>>;
    fn get_task_from_uuid(&'a self, uuid: Uuid) -> Result<Option<FileLockEntry<'a>>>;
    fn retrieve_task_from_import<R: BufRead>(&'a self, r: R) -> Result<FileLockEntry<'a>>;
    fn retrieve_task_from_string(&'a self, s: String) -> Result<FileLockEntry<'a>>;
    fn delete_tasks_by_imports<R: BufRead>(&self, r: R) -> Result<()>;
    fn delete_task_by_uuid(&self, uuid: Uuid) -> Result<()>;
    fn all_tasks(&self) -> Result<StoreIdIterator>;
    fn new_from_twtask(&'a self, task: TTask) -> Result<FileLockEntry<'a>>;
}

impl<'a> TaskStore<'a> for Store {

    fn import_task_from_reader<R: BufRead>(&'a self, mut r: R) -> Result<(FileLockEntry<'a>, String, Uuid)> {
        let mut line = String::new();
        try!(r.read_line(&mut line).map_err(|_| TE::from_kind(TEK::UTF8Error)));
        import_task(&line.as_str())
            .map_err(|_| TE::from_kind(TEK::ImportError))
            .and_then(|t| {
                let uuid = t.uuid().clone();
                self.new_from_twtask(t).map(|t| (t, line, uuid))
            })
    }

    /// Get a task from an import string. That is: read the imported string, get the UUID from it
    /// and try to load this UUID from store.
    ///
    /// Possible return values are:
    ///
    /// * Ok(Ok(Task))
    /// * Ok(Err(String)) - where the String is the String read from the `r` parameter
    /// * Err(_)          - where the error is an error that happened during evaluation
    ///
    fn get_task_from_import<R: BufRead>(&'a self, mut r: R) -> Result<RResult<FileLockEntry<'a>, String>> {
        let mut line = String::new();
        try!(r.read_line(&mut line).chain_err(|| TEK::UTF8Error));
        self.get_task_from_string(line)
    }

    /// Get a task from a String. The String is expected to contain the JSON-representation of the
    /// Task to get from the store (only the UUID really matters in this case)
    ///
    /// For an explanation on the return values see `Task::get_from_import()`.
    fn get_task_from_string(&'a self, s: String) -> Result<RResult<FileLockEntry<'a>, String>> {
        import_task(s.as_str())
            .map_err(|_| TE::from_kind(TEK::ImportError))
            .map(|t| t.uuid().clone())
            .and_then(|uuid| self.get_task_from_uuid(uuid))
            .and_then(|o| match o {
                None    => Ok(Err(s)),
                Some(t) => Ok(Ok(t)),
            })
    }

    /// Get a task from an UUID.
    ///
    /// If there is no task with this UUID, this returns `Ok(None)`.
    fn get_task_from_uuid(&'a self, uuid: Uuid) -> Result<Option<FileLockEntry<'a>>> {
        ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
            .into_storeid()
            .and_then(|store_id| self.get(store_id))
            .chain_err(|| TEK::StoreError)
    }

    /// Same as Task::get_from_import() but uses Store::retrieve() rather than Store::get(), to
    /// implicitely create the task if it does not exist.
    fn retrieve_task_from_import<R: BufRead>(&'a self, mut r: R) -> Result<FileLockEntry<'a>> {
        let mut line = String::new();
        try!(r.read_line(&mut line).chain_err(|| TEK::UTF8Error));
        self.retrieve_task_from_string(line)
    }

    /// Retrieve a task from a String. The String is expected to contain the JSON-representation of
    /// the Task to retrieve from the store (only the UUID really matters in this case)
    fn retrieve_task_from_string(&'a self, s: String) -> Result<FileLockEntry<'a>> {
        self.get_task_from_string(s)
            .and_then(|opt| match opt {
                Ok(task)    => Ok(task),
                Err(string) => import_task(string.as_str())
                    .map_err(|_| TE::from_kind(TEK::ImportError))
                    .and_then(|t| self.new_from_twtask(t)),
            })
    }

    fn delete_tasks_by_imports<R: BufRead>(&self, r: R) -> Result<()> {
        use serde_json::ser::to_string as serde_to_string;
        use task_hookrs::status::TaskStatus;

        for (counter, res_ttask) in import_tasks(r).into_iter().enumerate() {
            match res_ttask {
                Ok(ttask) => {
                    if counter % 2 == 1 {
                        // Only every second task is needed, the first one is the
                        // task before the change, and the second one after
                        // the change. The (maybe modified) second one is
                        // expected by taskwarrior.
                        match serde_to_string(&ttask).chain_err(|| TEK::ImportError) {
                            // use println!() here, as we talk with TW
                            Ok(val) => println!("{}", val),
                            Err(e)  => return Err(e),
                        }

                        // Taskwarrior does not have the concept of deleted tasks, but only modified
                        // ones.
                        //
                        // Here we check if the status of a task is deleted and if yes, we delete it
                        // from the store.
                        if *ttask.status() == TaskStatus::Deleted {
                            match self.delete_task_by_uuid(*ttask.uuid()) {
                                Ok(_)  => info!("Deleted task {}", *ttask.uuid()),
                                Err(e) => return Err(e),
                            }
                        }
                    } // end if c % 2
                },
                Err(_) => return Err(TE::from_kind(TEK::ImportError)),
            }
        }
        Ok(())
    }

    fn delete_task_by_uuid(&self, uuid: Uuid) -> Result<()> {
        ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
            .into_storeid()
            .and_then(|id| self.delete(id))
            .chain_err(|| TEK::StoreError)
    }

    fn all_tasks(&self) -> Result<StoreIdIterator> {
        self.retrieve_for_module("todo/taskwarrior")
            .chain_err(|| TEK::StoreError)
    }

    fn new_from_twtask(&'a self, task: TTask) -> Result<FileLockEntry<'a>> {
        use toml_query::read::TomlValueReadExt;
        use toml_query::set::TomlValueSetExt;

        let uuid     = task.uuid();
        ModuleEntryPath::new(format!("taskwarrior/{}", uuid))
            .into_storeid()
            .chain_err(|| TEK::StoreIdError)
            .and_then(|id| {
                self.retrieve(id)
                    .chain_err(|| TEK::StoreError)
                    .and_then(|mut fle| {
                        {
                            let hdr = fle.get_header_mut();
                            if try!(hdr.read("todo").chain_err(|| TEK::StoreError)).is_none() {
                                try!(hdr
                                    .set("todo", Value::Table(BTreeMap::new()))
                                    .chain_err(|| TEK::StoreError));
                            }

                            try!(hdr.set("todo.uuid", Value::String(format!("{}",uuid)))
                                 .chain_err(|| TEK::StoreError));
                        }

                        // If none of the errors above have returned the function, everything is fine
                        Ok(fle)
                    })
            })

    }

}

<|endoftext|>


<commit_before>use std;
use std::error;
use std::io;
use zip;

error_chain! {
    links {
        Ext4(::ext4::Error, ::ext4::ErrorKind);
    }

    foreign_links {
        Io(io::Error);
        Zip(zip::result::ZipError);
    }

    errors {
        Rewind {
            description("bailin' out")
            display("rewind")
        }
        UnsupportedFeature(msg: String) {
            description("format is (probably) legal, but we refuse to support its feature")
            display("unsupported feature: {}", msg)
        }
        Tar(msg: String) {
            description("tar-rs returned Other")
            display("tar failure message: {}", msg)
        }
    }
}

pub enum FormatErrorType {
    Rewind,
    Other,
}

pub fn is_format_error_result<T>(res: &Result<T>) -> Option<FormatErrorType> {
    if res.is_ok() {
        return None;
    }

    let error = res.as_ref().err().unwrap();

    // UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE
    // UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE
    // UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE
    // UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE
    // UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE

    // TODO: working around https://github.com/rust-lang/rust/issues/35943
    // TODO: i.e. error.cause() is totally useless

    let broken_ref = error.iter().last().unwrap();

    let oh_look_fixed = unsafe_staticify(broken_ref);

    if let Some(e) = oh_look_fixed.downcast_ref::<Error>() {
        is_format_error(e)
    } else if oh_look_fixed.is::<zip::result::ZipError>() {
        // Most zip errors should be wrapped in an errors::Error,
        // but https://github.com/brson/error-chain/issues/159

        // This is just a copy-paste of is_format_error's Zip(_) => Other
        Some(FormatErrorType::Other)
    } else {
//            self.log(1, || format!("unexpectedly failed to match an error type: {:?}", broken_ref))?;
        None
    }
}

fn is_format_error(e: &Error) -> Option<FormatErrorType> {
    match *e.kind() {
        ErrorKind::Rewind => {
            return Some(FormatErrorType::Rewind);
        }
        ErrorKind::Tar(_) | ErrorKind::UnsupportedFeature(_) => {
            return Some(FormatErrorType::Other);
        }
        ErrorKind::Io(ref e) => {
            // if there's an actual error code (regardless of what it is),
            // it's probably not from a library
            if e.raw_os_error().is_some() {
                return None;
            }

            match e.kind() {
                io::ErrorKind::InvalidData
                | io::ErrorKind::InvalidInput
                | io::ErrorKind::Other
                | io::ErrorKind::UnexpectedEof
                => return Some(FormatErrorType::Other),
                io::ErrorKind::BrokenPipe
                | io::ErrorKind::NotFound
                | io::ErrorKind::PermissionDenied
                => return None,
                _ => {}
            }
        }

        ErrorKind::Ext4(_) => {
            return Some(FormatErrorType::Other);
        }

        ErrorKind::Zip(_) => {
            return Some(FormatErrorType::Other);
        }

        ErrorKind::Msg(_) => {
            return None;
        }
    }

    None
}

fn unsafe_staticify(err: &error::Error) -> &'static error::Error {
    unsafe {
        std::mem::transmute(err)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io;
    use std::error::Error as Foo;
    use zip;

    fn simulate_failure(input: bool) -> zip::result::ZipResult<bool> {
        if !input {
            Ok(input)
        } else {
            Err(zip::result::ZipError::FileNotFound)
        }
    }

    #[test]
    fn chain_syntax_irrelevant() {
        let literate = simulate_failure(true).chain_err(|| "whoopsie").unwrap_err();
        let explicit = Error::with_chain(simulate_failure(true).unwrap_err(), "whoopsie");

        match literate.kind() {
            &ErrorKind::Msg(_) => {},
            _ => panic!(),
        };
        match explicit.kind() {
            &ErrorKind::Msg(_) => {},
            _ => panic!(),
        }

        let lit_cause = explicit.cause().unwrap();
        assert!(unsafe_staticify(lit_cause).is::<zip::result::ZipError>());

        let exp_cause = explicit.cause().unwrap();
        assert!(unsafe_staticify(exp_cause).is::<zip::result::ZipError>());
    }
}
<commit_msg>move comments / inline<commit_after>use std;
use std::error;
use std::io;
use zip;

error_chain! {
    links {
        Ext4(::ext4::Error, ::ext4::ErrorKind);
    }

    foreign_links {
        Io(io::Error);
        Zip(zip::result::ZipError);
    }

    errors {
        Rewind {
            description("bailin' out")
            display("rewind")
        }
        UnsupportedFeature(msg: String) {
            description("format is (probably) legal, but we refuse to support its feature")
            display("unsupported feature: {}", msg)
        }
        Tar(msg: String) {
            description("tar-rs returned Other")
            display("tar failure message: {}", msg)
        }
    }
}

pub enum FormatErrorType {
    Rewind,
    Other,
}

pub fn is_format_error_result<T>(res: &Result<T>) -> Option<FormatErrorType> {
    if res.is_ok() {
        return None;
    }

    let error = res.as_ref().err().unwrap();

    let broken_ref = error.iter().last().unwrap();

    if let Some(e) = unsafe_staticify(broken_ref).downcast_ref::<Error>() {
        is_format_error(e)
    } else if unsafe_staticify(broken_ref).is::<zip::result::ZipError>() {
        // Most zip errors should be wrapped in an errors::Error,
        // but https://github.com/brson/error-chain/issues/159

        // This is just a copy-paste of is_format_error's Zip(_) => Other
        Some(FormatErrorType::Other)
    } else {
//            self.log(1, || format!("unexpectedly failed to match an error type: {:?}", broken_ref))?;
        None
    }
}

fn is_format_error(e: &Error) -> Option<FormatErrorType> {
    match *e.kind() {
        ErrorKind::Rewind => {
            return Some(FormatErrorType::Rewind);
        }
        ErrorKind::Tar(_) | ErrorKind::UnsupportedFeature(_) => {
            return Some(FormatErrorType::Other);
        }
        ErrorKind::Io(ref e) => {
            // if there's an actual error code (regardless of what it is),
            // it's probably not from a library
            if e.raw_os_error().is_some() {
                return None;
            }

            match e.kind() {
                io::ErrorKind::InvalidData
                | io::ErrorKind::InvalidInput
                | io::ErrorKind::Other
                | io::ErrorKind::UnexpectedEof
                => return Some(FormatErrorType::Other),
                io::ErrorKind::BrokenPipe
                | io::ErrorKind::NotFound
                | io::ErrorKind::PermissionDenied
                => return None,
                _ => {}
            }
        }

        ErrorKind::Ext4(_) => {
            return Some(FormatErrorType::Other);
        }

        ErrorKind::Zip(_) => {
            return Some(FormatErrorType::Other);
        }

        ErrorKind::Msg(_) => {
            return None;
        }
    }

    None
}

/// UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE
/// UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE
/// UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE
/// UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE
/// UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE UNSAFE
///
/// TODO: working around https://github.com/rust-lang/rust/issues/35943
/// TODO: i.e. error.cause() is totally useless
///
/// This allows methods from the `Any` trait to be executed, e.g.
/// is::<> and downcast_ref::<>. I recommend you run them immediately;
/// i.e. don't even put the result of the method into a local.
fn unsafe_staticify(err: &error::Error) -> &'static error::Error {
    unsafe {
        std::mem::transmute(err)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io;
    use std::error::Error as Foo;
    use zip;

    fn simulate_failure(input: bool) -> zip::result::ZipResult<bool> {
        if !input {
            Ok(input)
        } else {
            Err(zip::result::ZipError::FileNotFound)
        }
    }

    #[test]
    fn chain_syntax_irrelevant() {
        let literate = simulate_failure(true).chain_err(|| "whoopsie").unwrap_err();
        let explicit = Error::with_chain(simulate_failure(true).unwrap_err(), "whoopsie");

        match literate.kind() {
            &ErrorKind::Msg(_) => {},
            _ => panic!(),
        };
        match explicit.kind() {
            &ErrorKind::Msg(_) => {},
            _ => panic!(),
        }

        let lit_cause = explicit.cause().unwrap();
        assert!(unsafe_staticify(lit_cause).is::<zip::result::ZipError>());

        let exp_cause = explicit.cause().unwrap();
        assert!(unsafe_staticify(exp_cause).is::<zip::result::ZipError>());
    }
}
<|endoftext|>


<commit_before>use std::cell::Cell;
use std::mem::MaybeUninit;
use std::ptr::NonNull;

#[test]
fn unitialized_zero_size_box() {
    assert_eq!(
        &*Box::<()>::new_uninit() as *const _,
        NonNull::<MaybeUninit<()>>::dangling().as_ptr(),
    );
    assert_eq!(
        Box::<[()]>::new_uninit_slice(4).as_ptr(),
        NonNull::<MaybeUninit<()>>::dangling().as_ptr(),
    );
    assert_eq!(
        Box::<[String]>::new_uninit_slice(0).as_ptr(),
        NonNull::<MaybeUninit<String>>::dangling().as_ptr(),
    );
}

#[derive(Clone, PartialEq, Eq, Debug)]
struct Dummy {
    _data: u8,
}

#[test]
fn box_clone_and_clone_from_equivalence() {
    for size in (0..8).map(|i| 2usize.pow(i)) {
        let control = vec![Dummy { _data: 42 }; size].into_boxed_slice();
        let clone = control.clone();
        let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice();
        copy.clone_from(&control);
        assert_eq!(control, clone);
        assert_eq!(control, copy);
    }
}

/// This test might give a false positive in case the box realocates, but the alocator keeps the
/// original pointer.
///
/// On the other hand it won't give a false negative, if it fails than the memory was definitely not
/// reused
#[test]
fn box_clone_from_ptr_stability() {
    for size in (0..8).map(|i| 2usize.pow(i)) {
        let control = vec![Dummy { _data: 42 }; size].into_boxed_slice();
        let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice();
        let copy_raw = copy.as_ptr() as usize;
        copy.clone_from(&control);
        assert_eq!(copy.as_ptr() as usize, copy_raw);
    }
}

#[test]
fn box_deref_lval() {
    let x = Box::new(Cell::new(5));
    x.set(1000);
    assert_eq!(x.get(), 1000);
}
<commit_msg>Fix grammar<commit_after>use std::cell::Cell;
use std::mem::MaybeUninit;
use std::ptr::NonNull;

#[test]
fn unitialized_zero_size_box() {
    assert_eq!(
        &*Box::<()>::new_uninit() as *const _,
        NonNull::<MaybeUninit<()>>::dangling().as_ptr(),
    );
    assert_eq!(
        Box::<[()]>::new_uninit_slice(4).as_ptr(),
        NonNull::<MaybeUninit<()>>::dangling().as_ptr(),
    );
    assert_eq!(
        Box::<[String]>::new_uninit_slice(0).as_ptr(),
        NonNull::<MaybeUninit<String>>::dangling().as_ptr(),
    );
}

#[derive(Clone, PartialEq, Eq, Debug)]
struct Dummy {
    _data: u8,
}

#[test]
fn box_clone_and_clone_from_equivalence() {
    for size in (0..8).map(|i| 2usize.pow(i)) {
        let control = vec![Dummy { _data: 42 }; size].into_boxed_slice();
        let clone = control.clone();
        let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice();
        copy.clone_from(&control);
        assert_eq!(control, clone);
        assert_eq!(control, copy);
    }
}

/// This test might give a false positive in case the box reallocates,
/// but the allocator keeps the original pointer.
///
/// On the other hand, it won't give a false negative: If it fails, then the
/// memory was definitely not reused.
#[test]
fn box_clone_from_ptr_stability() {
    for size in (0..8).map(|i| 2usize.pow(i)) {
        let control = vec![Dummy { _data: 42 }; size].into_boxed_slice();
        let mut copy = vec![Dummy { _data: 84 }; size].into_boxed_slice();
        let copy_raw = copy.as_ptr() as usize;
        copy.clone_from(&control);
        assert_eq!(copy.as_ptr() as usize, copy_raw);
    }
}

#[test]
fn box_deref_lval() {
    let x = Box::new(Cell::new(5));
    x.set(1000);
    assert_eq!(x.get(), 1000);
}
<|endoftext|>