<commit_before>use std::{fmt, iter, ptr};

// ////////////////////////////////////////////////////////////////////////////
// SkipNode
// ////////////////////////////////////////////////////////////////////////////

/// SkipNodes are make up the SkipList.  The SkipList owns the first head-node
/// (which has no value) and each node has ownership of the next node through
/// `next`.
///
/// The node has a `level` which corresponds to how 'high' the node reaches.
///
/// A node of `level` n has (n + 1) links to next nodes, which are stored in
/// a vector. level 0 points to the same node as `self.next`.
///
/// There is a corresponding vector of link lengths which contains the distance
/// between current node and the next node. If there's no next node, the distance
/// is distance between current node and last reachable node.
///
/// Lastly, each node contains a link to the immediately previous node in case
/// one needs to parse the list backwards.
///
/// In cases where the value is not applicable, `None` should be used.  In
/// particular, as there is no tail node, the value of `next` in the last node
/// should be `None`.
#[derive(Clone, Debug)]
pub struct SkipNode<V> {
    // key and value should never be None, with the sole exception being the
    // head node.
    pub value: Option<V>,
    // how high the node reaches.
    pub level: usize,
    // The immediately next element (and owns that next node).
    pub next: Option<Box<SkipNode<V>>>,
    // The immediately previous element.
    pub prev: *mut SkipNode<V>,
    // Vector of links to the next node at the respective level.  This vector
    // *must* be of length `self.level + 1`.  links[0] stores a pointer to the
    // same node as next.
    pub links: Vec<*mut SkipNode<V>>,
    // The corresponding length of each link
    pub links_len: Vec<usize>,
}

// ///////////////////////////////////////////////
// Inherent methods
// ///////////////////////////////////////////////

impl<V> SkipNode<V> {
    /// Create a new head node.
    pub fn head(total_levels: usize) -> Self {
        SkipNode {
            value: None,
            level: total_levels - 1,
            next: None,
            prev: ptr::null_mut(),
            links: iter::repeat(ptr::null_mut()).take(total_levels).collect(),
            links_len: iter::repeat(0).take(total_levels).collect(),
        }
    }

    /// Create a new SkipNode with the given value.  The values of `prev` and
    /// `next` will all be `None` and have to be adjusted.
    pub fn new(value: V, level: usize) -> Self {
        SkipNode {
            value: Some(value),
            level,
            next: None,
            prev: ptr::null_mut(),
            links: iter::repeat(ptr::null_mut()).take(level + 1).collect(),
            links_len: iter::repeat(0).take(level + 1).collect(),
        }
    }

    /// Consumes the node returning the value it contains.
    pub fn into_inner(mut self) -> Option<V> {
        self.value.take()
    }

    /// Returns `true` is the node is a head-node.
    pub fn is_head(&self) -> bool {
        self.prev.is_null()
    }

    /// Distance between current node and the given node at specified level.
    /// If no node is given, then return distance between current node and the
    /// last possible node.
    /// If the node is not reachable on given level, return Err(()).
    pub fn distance(&self, level: usize, target: Option<&Self>) -> Result<usize, ()> {
        let distance = match target {
            Some(target) => {
                let (dest, distance) = self.advance_while(level, |current, _| {
                    current as *const _ != target as *const _
                });
                if dest as *const _ != target as *const _ {
                    return Err(());
                }
                distance
            }
            None => {
                let (dest, distance) = self.advance_while(level, |_, _| true);
                dest.links_len[level] + distance
            }
        };
        Ok(distance)
    }

    /// Try to move to next nth node at specified level.
    /// If it's impossible, then move as far as possible.
    /// Returns a reference to the new node and the distance travelled.
    pub fn advance_atmost(&self, level: usize, mut max_distance: usize) -> (&Self, usize) {
        self.advance_while(level, move |current_node, _| {
            let travelled = current_node.links_len[level];
            if travelled <= max_distance {
                max_distance -= travelled;
                return true;
            } else {
                return false;
            }
        })
    }

    /// Try to move to next nth node at specified level.
    /// If it's impossible, then move as far as possible.
    /// Returns a mutable reference to the new node and the distance travelled.
    pub fn advance_atmost_mut(
        &mut self,
        level: usize,
        mut max_distance: usize,
    ) -> (&mut Self, usize) {
        self.advance_while_mut(level, move |current_node, _| {
            let travelled = current_node.links_len[level];
            if travelled <= max_distance {
                max_distance -= travelled;
                return true;
            } else {
                return false;
            }
        })
    }

    pub fn advance_while(
        &self,
        level: usize,
        mut pred: impl FnMut(&Self, &Self) -> bool,
    ) -> (&Self, usize) {
        let mut current = self;
        let mut travelled = 0;
        loop {
            match current.advance_if(level, &mut pred) {
                Ok((node, steps)) => {
                    current = node;
                    travelled += steps;
                }
                Err(node) => return (node, travelled),
            }
        }
    }

    pub fn advance_while_mut(
        &mut self,
        level: usize,
        mut pred: impl FnMut(&Self, &Self) -> bool,
    ) -> (&mut Self, usize) {
        let mut current = self;
        let mut travelled = 0;
        loop {
            match current.advance_if_mut(level, &mut pred) {
                Ok((node, steps)) => {
                    current = node;
                    travelled += steps;
                }
                Err(node) => return (node, travelled),
            }
        }
    }

    // Due to Rust lifetime semantics, the lifetime of result is the same as self.
    // Sometimes Rust cannot determine the result is unused, e.g. in a loop.
    // As a result, self might be  borrowed forever and caller cannot return that value
    // if they call this function in a loop.
    // Therefore this function always return self when it fails to advance.
    pub fn advance_if_mut<'a>(
        &'a mut self,
        level: usize,
        predicate: impl FnOnce(&Self, &Self) -> bool,
    ) -> Result<(&'a mut Self, usize), &'a mut Self> {
        let next = unsafe { self.links[level].as_mut() };
        match next {
            Some(next) if predicate(self, next) => Ok((next, self.links_len[level])),
            _ => Err(self),
        }
    }

    pub fn advance_if<'a>(
        &'a self,
        level: usize,
        predicate: impl FnOnce(&Self, &Self) -> bool,
    ) -> Result<(&'a Self, usize), &'a Self> {
        let next = unsafe { self.links[level].as_mut() };
        match next {
            Some(next) if predicate(self, next) => Ok((next, self.links_len[level])),
            _ => Err(self),
        }
    }

    /// Find the node after distance units, then insert a new node after that node.
    pub fn insert<'a>(&'a mut self, new_node: Box<Self>, distance: usize) {
        let locater = {
            let mut distance_left = distance;
            move |node: &'a mut Self, level| {
                let (dest, distance) = node.advance_atmost_mut(level, distance_left);
                distance_left -= distance;
                (dest, distance)
            }
        };
        self._insert(self.level, new_node, locater);
    }

    /// Locater finds the element that's before the target in a level.
    /// If the target does not exist in that level,
    /// it finds the last element that's not before target.
    /// In either case it also returns the distance travelled.
    ///
    /// The return value is distance traveled, used for fixup.
    pub fn _insert<'a, F>(
        &'a mut self,
        level: usize,
        mut new_node: Box<Self>,
        mut locater: F,
    ) -> (&'a mut Self, usize)
    where
        F: FnMut(&'a mut Self, usize) -> (&'a mut Self, usize),
    {
        let (prev_node, prev_distance) = locater(self, level);
        let prev_node_p = prev_node as *mut Self;
        if level == 0 {
            if let Some(mut tail) = prev_node.next.take() {
                tail.prev = new_node.as_mut() as *mut _;
                new_node.links[level] = tail.as_mut();
                new_node.next = Some(tail);
                new_node.links_len[level] = 1;
            }
            new_node.prev = prev_node as *mut _;
            prev_node.links[0] = new_node.as_mut() as *mut _;
            prev_node.links_len[level] = 1;
            prev_node.next = Some(new_node);
            return (prev_node.next.as_mut().unwrap(), prev_distance + 1);
        } else {
            let (inserted_node, insert_distance) = prev_node._insert(level - 1, new_node, locater);
            unsafe {
                if level <= inserted_node.level {
                    inserted_node.links[level] = (*prev_node_p).links[level];
                    inserted_node.links_len[level] =
                        (*prev_node_p).links_len[level] + 1 - insert_distance;
                    (*prev_node_p).links[level] = inserted_node as *mut _;
                    (*prev_node_p).links_len[level] = insert_distance;
                } else {
                    (*prev_node_p).links_len[level] += 1;
                }
            }
            return (inserted_node, insert_distance + prev_distance);
        }
    }
}

impl<V> Drop for SkipNode<V> {
    fn drop(&mut self) {
        while let Some(mut node) = self.next.take() {
            self.next = node.next.take();
        }
    }
}

// ///////////////////////////////////////////////
// Trait implementation
// ///////////////////////////////////////////////

impl<V> fmt::Display for SkipNode<V>
where
    V: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref v) = self.value {
            write!(f, "{}", v)
        } else {
            Ok(())
        }
    }
}

// /////////////////////////////////
// Iterators
// /////////////////////////////////
// Since Iterators (currently) only pop from front and back,
// they can be shared by some data structures.
// There's no need for a dummy head (that contains no value) in the iterator.
// so the members are named first and last instaed of head/end to avoid confusion.

/// Consuming iterator.
pub struct IntoIter<T> {
    pub(crate) first: Option<Box<SkipNode<T>>>,
    pub(crate) last: *mut SkipNode<T>,
    pub(crate) size: usize,
}

impl<T> Iterator for IntoIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        let mut popped_node = self.first.take()?;
        self.size -= 1;
        self.first = popped_node.next.take().map(|mut node| {
            node.prev = ptr::null_mut();
            node
        });
        if self.first.is_none() {
            self.last = ptr::null_mut();
        }
        popped_node.into_inner()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.size, Some(self.size))
    }
}

impl<T> DoubleEndedIterator for IntoIter<T> {
    fn next_back(&mut self) -> Option<T> {
        if self.first.is_none() {
            return None;
        }
        assert!(!self.last.is_null());
        unsafe {
            let new_last = (*self.last).prev;
            let popped_node = match new_last.as_mut() {
                Some(new_last) => {
                    self.last = new_last as *mut _;
                    (*new_last).next.take().unwrap()
                }
                None => self.first.take().unwrap(),
            };
            self.size -= 1;
            popped_node.into_inner()
        }
    }
}
<commit_msg>Add some tests to detect undefined behavior using Miri.<commit_after>use std::{fmt, iter, ptr};

/// Minimum levels required for a list of size n.
pub fn levels_required(n: usize) -> usize {
    if n == 0 {
        1
    } else {
        let num_bits = std::mem::size_of::<usize>() * 8;
        num_bits - n.leading_zeros() as usize
    }
}

// ////////////////////////////////////////////////////////////////////////////
// SkipNode
// ////////////////////////////////////////////////////////////////////////////

/// SkipNodes are make up the SkipList.  The SkipList owns the first head-node
/// (which has no value) and each node has ownership of the next node through
/// `next`.
///
/// The node has a `level` which corresponds to how 'high' the node reaches.
///
/// A node of `level` n has (n + 1) links to next nodes, which are stored in
/// a vector. level 0 points to the same node as `self.next`.
///
/// There is a corresponding vector of link lengths which contains the distance
/// between current node and the next node. If there's no next node, the distance
/// is distance between current node and last reachable node.
///
/// Lastly, each node contains a link to the immediately previous node in case
/// one needs to parse the list backwards.
///
/// In cases where the value is not applicable, `None` should be used.  In
/// particular, as there is no tail node, the value of `next` in the last node
/// should be `None`.
#[derive(Clone, Debug)]
pub struct SkipNode<V> {
    // key and value should never be None, with the sole exception being the
    // head node.
    pub value: Option<V>,
    // how high the node reaches.
    pub level: usize,
    // The immediately next element (and owns that next node).
    pub next: Option<Box<SkipNode<V>>>,
    // The immediately previous element.
    pub prev: *mut SkipNode<V>,
    // Vector of links to the next node at the respective level.  This vector
    // *must* be of length `self.level + 1`.  links[0] stores a pointer to the
    // same node as next.
    pub links: Vec<*mut SkipNode<V>>,
    // The corresponding length of each link
    pub links_len: Vec<usize>,
}

// ///////////////////////////////////////////////
// Inherent methods
// ///////////////////////////////////////////////

impl<V> SkipNode<V> {
    /// Create a new head node.
    pub fn head(total_levels: usize) -> Self {
        SkipNode {
            value: None,
            level: total_levels - 1,
            next: None,
            prev: ptr::null_mut(),
            links: iter::repeat(ptr::null_mut()).take(total_levels).collect(),
            links_len: iter::repeat(0).take(total_levels).collect(),
        }
    }

    /// Create a new SkipNode with the given value.  The values of `prev` and
    /// `next` will all be `None` and have to be adjusted.
    pub fn new(value: V, level: usize) -> Self {
        SkipNode {
            value: Some(value),
            level,
            next: None,
            prev: ptr::null_mut(),
            links: iter::repeat(ptr::null_mut()).take(level + 1).collect(),
            links_len: iter::repeat(0).take(level + 1).collect(),
        }
    }

    /// Consumes the node returning the value it contains.
    pub fn into_inner(mut self) -> Option<V> {
        self.value.take()
    }

    /// Returns `true` is the node is a head-node.
    pub fn is_head(&self) -> bool {
        self.prev.is_null()
    }

    /// Distance between current node and the given node at specified level.
    /// If no node is given, then return distance between current node and the
    /// last possible node.
    /// If the node is not reachable on given level, return Err(()).
    pub fn distance(&self, level: usize, target: Option<&Self>) -> Result<usize, ()> {
        let distance = match target {
            Some(target) => {
                let (dest, distance) = self.advance_while(level, |current, _| {
                    current as *const _ != target as *const _
                });
                if dest as *const _ != target as *const _ {
                    return Err(());
                }
                distance
            }
            None => {
                let (dest, distance) = self.advance_while(level, |_, _| true);
                dest.links_len[level] + distance
            }
        };
        Ok(distance)
    }

    /// Try to move to next nth node at specified level.
    /// If it's impossible, then move as far as possible.
    /// Returns a reference to the new node and the distance travelled.
    pub fn advance_atmost(&self, level: usize, mut max_distance: usize) -> (&Self, usize) {
        self.advance_while(level, move |current_node, _| {
            let travelled = current_node.links_len[level];
            if travelled <= max_distance {
                max_distance -= travelled;
                return true;
            } else {
                return false;
            }
        })
    }

    /// Try to move to next nth node at specified level.
    /// If it's impossible, then move as far as possible.
    /// Returns a mutable reference to the new node and the distance travelled.
    pub fn advance_atmost_mut(
        &mut self,
        level: usize,
        mut max_distance: usize,
    ) -> (&mut Self, usize) {
        self.advance_while_mut(level, move |current_node, _| {
            let travelled = current_node.links_len[level];
            if travelled <= max_distance {
                max_distance -= travelled;
                return true;
            } else {
                return false;
            }
        })
    }

    pub fn advance_while(
        &self,
        level: usize,
        mut pred: impl FnMut(&Self, &Self) -> bool,
    ) -> (&Self, usize) {
        let mut current = self;
        let mut travelled = 0;
        loop {
            match current.advance_if(level, &mut pred) {
                Ok((node, steps)) => {
                    current = node;
                    travelled += steps;
                }
                Err(node) => return (node, travelled),
            }
        }
    }

    pub fn advance_while_mut(
        &mut self,
        level: usize,
        mut pred: impl FnMut(&Self, &Self) -> bool,
    ) -> (&mut Self, usize) {
        let mut current = self;
        let mut travelled = 0;
        loop {
            match current.advance_if_mut(level, &mut pred) {
                Ok((node, steps)) => {
                    current = node;
                    travelled += steps;
                }
                Err(node) => return (node, travelled),
            }
        }
    }

    // Due to Rust lifetime semantics, the lifetime of result is the same as self.
    // Sometimes Rust cannot determine the result is unused, e.g. in a loop.
    // As a result, self might be  borrowed forever and caller cannot return that value
    // if they call this function in a loop.
    // Therefore this function always return self when it fails to advance.
    pub fn advance_if_mut<'a>(
        &'a mut self,
        level: usize,
        predicate: impl FnOnce(&Self, &Self) -> bool,
    ) -> Result<(&'a mut Self, usize), &'a mut Self> {
        let next = unsafe { self.links[level].as_mut() };
        match next {
            Some(next) if predicate(self, next) => Ok((next, self.links_len[level])),
            _ => Err(self),
        }
    }

    pub fn advance_if<'a>(
        &'a self,
        level: usize,
        predicate: impl FnOnce(&Self, &Self) -> bool,
    ) -> Result<(&'a Self, usize), &'a Self> {
        let next = unsafe { self.links[level].as_mut() };
        match next {
            Some(next) if predicate(self, next) => Ok((next, self.links_len[level])),
            _ => Err(self),
        }
    }

    /// Find the node after distance units, then insert a new node after that node.
    pub fn insert<'a>(&'a mut self, new_node: Box<Self>, distance: usize) {
        let locater = {
            let mut distance_left = distance;
            move |node: &'a mut Self, level| {
                let (dest, distance) = node.advance_atmost_mut(level, distance_left);
                distance_left -= distance;
                (dest, distance)
            }
        };
        self._insert(self.level, new_node, locater);
    }

    /// Locater finds the element that's before the target in a level.
    /// If the target does not exist in that level,
    /// it finds the last element that's not before target.
    /// In either case it also returns the distance travelled.
    ///
    /// The return value is distance traveled, used for fixup.
    pub fn _insert<'a, F>(
        &'a mut self,
        level: usize,
        mut new_node: Box<Self>,
        mut locater: F,
    ) -> (&'a mut Self, usize)
    where
        F: FnMut(&'a mut Self, usize) -> (&'a mut Self, usize),
    {
        let (prev_node, prev_distance) = locater(self, level);
        let prev_node_p = prev_node as *mut Self;
        if level == 0 {
            if let Some(mut tail) = prev_node.next.take() {
                tail.prev = new_node.as_mut() as *mut _;
                new_node.links[level] = tail.as_mut();
                new_node.next = Some(tail);
                new_node.links_len[level] = 1;
            }
            new_node.prev = prev_node as *mut _;
            prev_node.links[0] = new_node.as_mut() as *mut _;
            prev_node.links_len[level] = 1;
            prev_node.next = Some(new_node);
            return (prev_node.next.as_mut().unwrap(), prev_distance + 1);
        } else {
            let (inserted_node, insert_distance) = prev_node._insert(level - 1, new_node, locater);
            unsafe {
                if level <= inserted_node.level {
                    inserted_node.links[level] = (*prev_node_p).links[level];
                    inserted_node.links_len[level] =
                        (*prev_node_p).links_len[level] + 1 - insert_distance;
                    (*prev_node_p).links[level] = inserted_node as *mut _;
                    (*prev_node_p).links_len[level] = insert_distance;
                } else {
                    (*prev_node_p).links_len[level] += 1;
                }
            }
            return (inserted_node, insert_distance + prev_distance);
        }
    }
}

impl<V> Drop for SkipNode<V> {
    fn drop(&mut self) {
        while let Some(mut node) = self.next.take() {
            self.next = node.next.take();
        }
    }
}

// ///////////////////////////////////////////////
// Trait implementation
// ///////////////////////////////////////////////

impl<V> fmt::Display for SkipNode<V>
where
    V: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref v) = self.value {
            write!(f, "{}", v)
        } else {
            Ok(())
        }
    }
}

// /////////////////////////////////
// Iterators
// /////////////////////////////////
// Since Iterators (currently) only pop from front and back,
// they can be shared by some data structures.
// There's no need for a dummy head (that contains no value) in the iterator.
// so the members are named first and last instaed of head/end to avoid confusion.

/// Consuming iterator.
pub struct IntoIter<T> {
    pub(crate) first: Option<Box<SkipNode<T>>>,
    pub(crate) last: *mut SkipNode<T>,
    pub(crate) size: usize,
}

impl<T> Iterator for IntoIter<T> {
    type Item = T;

    fn next(&mut self) -> Option<T> {
        let mut popped_node = self.first.take()?;
        self.size -= 1;
        self.first = popped_node.next.take().map(|mut node| {
            node.prev = ptr::null_mut();
            node
        });
        if self.first.is_none() {
            self.last = ptr::null_mut();
        }
        popped_node.into_inner()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.size, Some(self.size))
    }
}

impl<T> DoubleEndedIterator for IntoIter<T> {
    fn next_back(&mut self) -> Option<T> {
        if self.first.is_none() {
            return None;
        }
        assert!(!self.last.is_null());
        unsafe {
            let new_last = (*self.last).prev;
            let popped_node = match new_last.as_mut() {
                Some(new_last) => {
                    self.last = new_last as *mut _;
                    (*new_last).next.take().unwrap()
                }
                None => self.first.take().unwrap(),
            };
            self.size -= 1;
            popped_node.into_inner()
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn test_level_required() {
        assert_eq!(levels_required(0), 1);
        assert_eq!(levels_required(1), 1);
        assert_eq!(levels_required(2), 2);
        assert_eq!(levels_required(3), 2);
        assert_eq!(levels_required(1023), 10);
        assert_eq!(levels_required(1024), 11);
    }

    fn level_for_index(mut n: usize) -> usize {
        let mut cnt = 0;
        while n & 0x1 == 1 {
            cnt += 1;
            n /= 2;
        }
        cnt
    }

    #[test]
    fn test_level_index() {
        assert_eq!(level_for_index(0), 0);
        assert_eq!(level_for_index(1), 1);
        assert_eq!(level_for_index(2), 0);
        assert_eq!(level_for_index(3), 2);
        assert_eq!(level_for_index(4), 0);
        assert_eq!(level_for_index(5), 1);
        assert_eq!(level_for_index(6), 0);
        assert_eq!(level_for_index(7), 3);
        assert_eq!(level_for_index(8), 0);
        assert_eq!(level_for_index(9), 1);
        assert_eq!(level_for_index(10), 0);
        assert_eq!(level_for_index(11), 2);
    }

    /// Make a list of size n
    /// levels are evenly spread out
    fn new_list_for_test(n: usize) -> SkipNode<usize> {
        let max_level = levels_required(n);
        let mut head = SkipNode::<usize>::head(max_level);
        assert_eq!(head.links.len(), max_level);
        let mut nodes: Vec<Box<SkipNode<usize>>> = (0..n)
            .map(|n| Box::new(SkipNode::new(n, level_for_index(n))))
            .collect();
        let node_max_level = nodes.iter().map(|node| node.level).max();
        if let Some(node_max_level) = node_max_level {
            assert_eq!(node_max_level + 1, max_level);
        }
        for level in 0..max_level {
            let mut last_node = &mut head as *mut SkipNode<usize>;
            let mut len_left = n;
            unsafe {
                for node in nodes
                    .iter_mut()
                    .filter(|node| level <= node.level)
                    .map(|node| node.as_mut() as *mut SkipNode<usize>)
                {
                    if level == 0 {
                        (*node).prev = last_node;
                    }
                    (*last_node).links[level] = node;
                    (*last_node).links_len[level] = 1 << level;
                    last_node = node;
                    len_left -= 1 << level;
                }
                (*last_node).links_len[level] = len_left;
            }
        }
        let mut last_node = &mut head;
        for node in nodes.into_iter() {
            last_node.next.replace(node);
            last_node = last_node.next.as_mut().unwrap();
        }
        return head;
    }

    #[test]
    fn test_make_new_list() {
        fn test_list_integrity(len: usize) {
            let list = new_list_for_test(len);
            let mut node = list.next.as_ref();
            while let Some(node_inner) = node {
                let idx = node_inner.value.unwrap_or_else(|| panic!());
                assert_eq!(node_inner.level, level_for_index(idx));
                node = node_inner.next.as_ref();
            }

            for level in 0..levels_required(len) {
                let mut len_left = len;
                let mut node = &list;
                unsafe {
                    while let Some(next_node) = node.links[level].as_ref() {
                        len_left -= node.links_len[level];
                        node = next_node;
                    }
                    assert_eq!(len_left, node.links_len[level])
                }
            }
        }
        test_list_integrity(0);
        test_list_integrity(1);
        test_list_integrity(2);
        test_list_integrity(3);
        test_list_integrity(10);
        test_list_integrity(1023);
        test_list_integrity(1024);
        test_list_integrity(1025);
    }
}
<|endoftext|>


<commit_before>// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Resource management and resolution for the virtio-video device.

use std::convert::TryInto;
use std::fmt;

use base::{
    self, FromRawDescriptor, IntoRawDescriptor, MemoryMappingArena, MemoryMappingBuilder,
    MemoryMappingBuilderUnix, MmapError, SafeDescriptor,
};
use vm_memory::{GuestAddress, GuestMemory, GuestMemoryError};

use thiserror::Error as ThisError;

use crate::virtio::resource_bridge::{self, ResourceBridgeError, ResourceInfo, ResourceRequest};
use crate::virtio::video::format::{FramePlane, PlaneFormat};
use crate::virtio::video::protocol::{virtio_video_mem_entry, virtio_video_object_entry};

/// Defines how resources for a given queue are represented.
#[derive(Clone, Copy, Debug)]
pub enum ResourceType {
    /// Resources are backed by guest memory pages.
    GuestPages,
    /// Resources are backed by virtio objects.
    VirtioObject,
}

impl Default for ResourceType {
    fn default() -> Self {
        ResourceType::VirtioObject
    }
}

#[repr(C)]
#[derive(Clone, Copy)]
/// A guest resource entry which type is not decided yet.
pub union UnresolvedResourceEntry {
    pub object: virtio_video_object_entry,
    pub guest_mem: virtio_video_mem_entry,
}
unsafe impl data_model::DataInit for UnresolvedResourceEntry {}

impl fmt::Debug for UnresolvedResourceEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Safe because `self.object` and `self.guest_mem` are the same size and both made of
        // integers, making it safe to display them no matter their value.
        write!(
            f,
            "unresolved {:?} or {:?}",
            unsafe { self.object },
            unsafe { self.guest_mem }
        )
    }
}

/// Trait for types that can serve as video buffer backing memory.
pub trait BufferHandle: Sized {
    /// Try to clone this handle. This must only create a new reference to the same backing memory
    /// and not duplicate the buffer itself.
    fn try_clone(&self) -> Result<Self, base::Error>;

    /// Returns a linear mapping of [`offset`..`offset`+`size`] of the memory backing this buffer.
    fn get_mapping(&self, offset: usize, size: usize) -> Result<MemoryMappingArena, MmapError>;
}

/// Linear memory area of a `GuestMemHandle`
#[derive(Clone)]
pub struct GuestMemArea {
    /// Offset within the guest region to the start of the area.
    pub offset: u64,
    /// Length of the area within the memory region.
    pub length: usize,
}

pub struct GuestMemHandle {
    /// Descriptor to the guest memory region containing the buffer.
    pub desc: SafeDescriptor,
    /// Memory areas (i.e. sg list) that make the memory buffer.
    pub mem_areas: Vec<GuestMemArea>,
}

impl BufferHandle for GuestMemHandle {
    fn try_clone(&self) -> Result<Self, base::Error> {
        Ok(Self {
            desc: self.desc.try_clone()?,
            mem_areas: self.mem_areas.clone(),
        })
    }

    fn get_mapping(&self, offset: usize, size: usize) -> Result<MemoryMappingArena, MmapError> {
        let mut arena = MemoryMappingArena::new(size)?;
        let mut mapped_size = 0;
        let mut area_iter = self.mem_areas.iter();
        let mut area_offset = offset;
        while mapped_size < size {
            let area = match area_iter.next() {
                Some(area) => area,
                None => {
                    return Err(MmapError::InvalidRange(
                        offset,
                        size,
                        self.mem_areas.iter().map(|a| a.length).sum(),
                    ));
                }
            };
            if area_offset > area.length {
                area_offset -= area.length;
            } else {
                let mapping_length = std::cmp::min(area.length - area_offset, size - mapped_size);
                arena.add_fd_offset(mapped_size, mapping_length, &self.desc, area.offset)?;
                mapped_size += mapping_length;
                area_offset = 0;
            }
        }
        Ok(arena)
    }
}

pub struct VirtioObjectHandle {
    /// Descriptor for the object.
    pub desc: SafeDescriptor,
    /// Modifier to apply to frame resources.
    pub modifier: u64,
}

impl BufferHandle for VirtioObjectHandle {
    fn try_clone(&self) -> Result<Self, base::Error> {
        Ok(Self {
            desc: self.desc.try_clone()?,
            modifier: self.modifier,
        })
    }

    fn get_mapping(&self, offset: usize, size: usize) -> Result<MemoryMappingArena, MmapError> {
        MemoryMappingBuilder::new(size)
            .from_descriptor(&self.desc)
            .offset(offset as u64)
            .build()
            .map(MemoryMappingArena::from)
    }
}

pub enum GuestResourceHandle {
    GuestPages(GuestMemHandle),
    VirtioObject(VirtioObjectHandle),
}

impl BufferHandle for GuestResourceHandle {
    fn try_clone(&self) -> Result<Self, base::Error> {
        Ok(match self {
            Self::GuestPages(handle) => Self::GuestPages(handle.try_clone()?),
            Self::VirtioObject(handle) => Self::VirtioObject(handle.try_clone()?),
        })
    }

    fn get_mapping(&self, offset: usize, size: usize) -> Result<MemoryMappingArena, MmapError> {
        match self {
            GuestResourceHandle::GuestPages(handle) => handle.get_mapping(offset, size),
            GuestResourceHandle::VirtioObject(handle) => handle.get_mapping(offset, size),
        }
    }
}

pub struct GuestResource {
    /// Handle to the backing memory.
    pub handle: GuestResourceHandle,
    /// Layout of color planes, if the resource will receive frames.
    pub planes: Vec<FramePlane>,
}

#[derive(Debug, ThisError)]
pub enum GuestMemResourceCreationError {
    #[error("Provided slice of entries is empty")]
    NoEntriesProvided,
    #[error("cannot get shm region: {0}")]
    CantGetShmRegion(GuestMemoryError),
    #[error("cannot get shm offset: {0}")]
    CantGetShmOffset(GuestMemoryError),
    #[error("error while cloning shm region descriptor: {0}")]
    DescriptorCloneError(base::Error),
}

#[derive(Debug, ThisError)]
pub enum ObjectResourceCreationError {
    #[error("uuid {0:08} is larger than 32 bits")]
    UuidNot32Bits(u128),
    #[error("resource returned by bridge is not a buffer")]
    NotABuffer,
    #[error("resource bridge failure: {0}")]
    ResourceBridgeFailure(ResourceBridgeError),
}

impl GuestResource {
    /// Try to convert an unresolved virtio guest memory entry into a resolved guest memory
    /// resource.
    ///
    /// Convert `mem_entry` into the guest memory resource it represents and resolve it through
    /// `mem`. `planes_format` describes the format of the individual planes for the buffer.
    pub fn from_virtio_guest_mem_entry(
        mem_entries: &[virtio_video_mem_entry],
        mem: &GuestMemory,
        planes_format: &[PlaneFormat],
    ) -> Result<GuestResource, GuestMemResourceCreationError> {
        let region_desc = match mem_entries.first() {
            None => return Err(GuestMemResourceCreationError::NoEntriesProvided),
            Some(entry) => {
                let addr: u64 = entry.addr.into();

                let guest_region = mem
                    .shm_region(GuestAddress(addr))
                    .map_err(GuestMemResourceCreationError::CantGetShmRegion)?;
                let desc = base::clone_descriptor(guest_region)
                    .map_err(GuestMemResourceCreationError::DescriptorCloneError)?;
                // Safe because we are the sole owner of the duplicated descriptor.
                unsafe { SafeDescriptor::from_raw_descriptor(desc) }
            }
        };

        let mem_areas = mem_entries
            .iter()
            .map(|entry| {
                let addr: u64 = entry.addr.into();
                let length: u32 = entry.length.into();
                let region_offset = mem
                    .offset_from_base(GuestAddress(addr))
                    .map_err(GuestMemResourceCreationError::CantGetShmOffset)
                    .unwrap();

                GuestMemArea {
                    offset: region_offset,
                    length: length as usize,
                }
            })
            .collect();

        // The plane information can be computed from the currently set format.
        let mut buffer_offset = 0;
        let planes = planes_format
            .iter()
            .map(|p| {
                let plane_offset = buffer_offset;
                buffer_offset += p.plane_size;

                FramePlane {
                    offset: plane_offset as usize,
                    stride: p.stride as usize,
                }
            })
            .collect();

        Ok(GuestResource {
            handle: GuestResourceHandle::GuestPages(GuestMemHandle {
                desc: region_desc,
                mem_areas,
            }),
            planes,
        })
    }

    /// Try to convert an unresolved virtio object entry into a resolved object resource.
    ///
    /// Convert `object` into the object resource it represents and resolve it through `res_bridge`.
    /// Returns an error if the object's UUID is invalid or cannot be resolved to a buffer object
    /// by `res_bridge`.
    pub fn from_virtio_object_entry(
        object: virtio_video_object_entry,
        res_bridge: &base::Tube,
    ) -> Result<GuestResource, ObjectResourceCreationError> {
        // We trust that the caller has chosen the correct object type.
        let uuid = u128::from_be_bytes(object.uuid);

        // TODO(stevensd): `Virtio3DBackend::resource_assign_uuid` is currently implemented to use
        // 32-bits resource_handles as UUIDs. Once it starts using real UUIDs, we need to update
        // this conversion.
        let handle = TryInto::<u32>::try_into(uuid)
            .map_err(|_| ObjectResourceCreationError::UuidNot32Bits(uuid))?;

        let buffer_info = match resource_bridge::get_resource_info(
            res_bridge,
            ResourceRequest::GetBuffer { id: handle },
        ) {
            Ok(ResourceInfo::Buffer(buffer_info)) => buffer_info,
            Ok(_) => return Err(ObjectResourceCreationError::NotABuffer),
            Err(e) => return Err(ObjectResourceCreationError::ResourceBridgeFailure(e)),
        };

        Ok(GuestResource {
            handle: GuestResourceHandle::VirtioObject(VirtioObjectHandle {
                // Safe because `buffer_info.file` is a valid file descriptor and we are stealing
                // it.
                desc: unsafe {
                    SafeDescriptor::from_raw_descriptor(buffer_info.file.into_raw_descriptor())
                },
                modifier: buffer_info.modifier,
            }),
            planes: buffer_info
                .planes
                .iter()
                .take_while(|p| p.offset != 0 || p.stride != 0)
                .map(|p| FramePlane {
                    offset: p.offset as usize,
                    stride: p.stride as usize,
                })
                .collect(),
        })
    }

    #[cfg(feature = "video-encoder")]
    pub fn try_clone(&self) -> Result<Self, base::Error> {
        Ok(Self {
            handle: self.handle.try_clone()?,
            planes: self.planes.clone(),
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use base::{MappedRegion, SafeDescriptor, SharedMemory};

    /// Creates a sparse guest memory handle using as many pages as there are entries in
    /// `page_order`. The page with index `0` will be the first page, `1` will be the second page,
    /// etc.
    ///
    /// The memory handle is filled with increasing u32s starting from page 0, then page 1, and so
    /// on. Finally the handle is mapped into a linear space and we check that the written integers
    /// appear in the expected order.
    fn check_guest_mem_handle(page_order: &[usize]) {
        const PAGE_SIZE: usize = 0x1000;
        const U32_SIZE: usize = std::mem::size_of::<u32>();
        const ENTRIES_PER_PAGE: usize = PAGE_SIZE as usize / std::mem::size_of::<u32>();

        // Fill a vector of the same size as the handle with u32s of increasing value, following
        // the page layout given as argument.
        let mut data = vec![0u8; PAGE_SIZE * page_order.len()];
        for (page_index, page) in page_order.iter().enumerate() {
            let page_slice =
                &mut data[(page * PAGE_SIZE as usize)..((page + 1) * PAGE_SIZE as usize)];
            for (index, chunk) in page_slice.chunks_exact_mut(4).enumerate() {
                let sized_chunk: &mut [u8; 4] = chunk.try_into().unwrap();
                *sized_chunk = (((page_index * ENTRIES_PER_PAGE) + index) as u32).to_ne_bytes();
            }
        }

        // Copy the initialized vector's content into an anonymous shared memory.
        let mem = SharedMemory::anon(data.len() as u64).unwrap();
        let mapping = MemoryMappingBuilder::new(mem.size() as usize)
            .from_shared_memory(&mem)
            .build()
            .unwrap();
        assert_eq!(mapping.write_slice(&data, 0).unwrap(), data.len());

        // Create the `GuestMemHandle` we will try to map and retrieve the data from.
        let mem_handle = GuestResourceHandle::GuestPages(GuestMemHandle {
            desc: unsafe {
                SafeDescriptor::from_raw_descriptor(base::clone_descriptor(&mem).unwrap())
            },
            mem_areas: page_order
                .iter()
                .map(|&page| GuestMemArea {
                    offset: page as u64 * PAGE_SIZE as u64,
                    length: PAGE_SIZE as usize,
                })
                .collect(),
        });

        // Map the handle into a linear memory area, retrieve its data into a new vector, and check
        // that its u32s appear to increase linearly.
        let mapping = mem_handle.get_mapping(0, mem.size() as usize).unwrap();
        let mut data = vec![0u8; PAGE_SIZE * page_order.len()];
        unsafe { std::ptr::copy_nonoverlapping(mapping.as_ptr(), data.as_mut_ptr(), data.len()) };
        for (index, chunk) in data.chunks_exact(U32_SIZE).enumerate() {
            let sized_chunk: &[u8; 4] = chunk.try_into().unwrap();
            assert_eq!(u32::from_ne_bytes(*sized_chunk), index as u32);
        }
    }

    // Fill a guest memory handle with a single memory page.
    // Then check that the data can be properly mapped and appears in the expected order.
    #[test]
    fn test_single_guest_mem_handle() {
        check_guest_mem_handle(&[0])
    }

    // Fill a guest memory handle with 4 memory pages that are contiguous.
    // Then check that the pages appear in the expected order in the mapping.
    #[test]
    fn test_linear_guest_mem_handle() {
        check_guest_mem_handle(&[0, 1, 2, 3])
    }

    // Fill a guest memory handle with 8 pages mapped in non-linear order.
    // Then check that the pages appear in the expected order in the mapping.
    #[test]
    fn test_sparse_guest_mem_handle() {
        check_guest_mem_handle(&[1, 7, 6, 3, 5, 0, 4, 2])
    }
}
<commit_msg>virtio: video: fix broken test<commit_after>// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Resource management and resolution for the virtio-video device.

use std::convert::TryInto;
use std::fmt;

use base::{
    self, FromRawDescriptor, IntoRawDescriptor, MemoryMappingArena, MemoryMappingBuilder,
    MemoryMappingBuilderUnix, MmapError, SafeDescriptor,
};
use vm_memory::{GuestAddress, GuestMemory, GuestMemoryError};

use thiserror::Error as ThisError;

use crate::virtio::resource_bridge::{self, ResourceBridgeError, ResourceInfo, ResourceRequest};
use crate::virtio::video::format::{FramePlane, PlaneFormat};
use crate::virtio::video::protocol::{virtio_video_mem_entry, virtio_video_object_entry};

/// Defines how resources for a given queue are represented.
#[derive(Clone, Copy, Debug)]
pub enum ResourceType {
    /// Resources are backed by guest memory pages.
    GuestPages,
    /// Resources are backed by virtio objects.
    VirtioObject,
}

impl Default for ResourceType {
    fn default() -> Self {
        ResourceType::VirtioObject
    }
}

#[repr(C)]
#[derive(Clone, Copy)]
/// A guest resource entry which type is not decided yet.
pub union UnresolvedResourceEntry {
    pub object: virtio_video_object_entry,
    pub guest_mem: virtio_video_mem_entry,
}
unsafe impl data_model::DataInit for UnresolvedResourceEntry {}

impl fmt::Debug for UnresolvedResourceEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Safe because `self.object` and `self.guest_mem` are the same size and both made of
        // integers, making it safe to display them no matter their value.
        write!(
            f,
            "unresolved {:?} or {:?}",
            unsafe { self.object },
            unsafe { self.guest_mem }
        )
    }
}

/// Trait for types that can serve as video buffer backing memory.
pub trait BufferHandle: Sized {
    /// Try to clone this handle. This must only create a new reference to the same backing memory
    /// and not duplicate the buffer itself.
    fn try_clone(&self) -> Result<Self, base::Error>;

    /// Returns a linear mapping of [`offset`..`offset`+`size`] of the memory backing this buffer.
    fn get_mapping(&self, offset: usize, size: usize) -> Result<MemoryMappingArena, MmapError>;
}

/// Linear memory area of a `GuestMemHandle`
#[derive(Clone)]
pub struct GuestMemArea {
    /// Offset within the guest region to the start of the area.
    pub offset: u64,
    /// Length of the area within the memory region.
    pub length: usize,
}

pub struct GuestMemHandle {
    /// Descriptor to the guest memory region containing the buffer.
    pub desc: SafeDescriptor,
    /// Memory areas (i.e. sg list) that make the memory buffer.
    pub mem_areas: Vec<GuestMemArea>,
}

impl BufferHandle for GuestMemHandle {
    fn try_clone(&self) -> Result<Self, base::Error> {
        Ok(Self {
            desc: self.desc.try_clone()?,
            mem_areas: self.mem_areas.clone(),
        })
    }

    fn get_mapping(&self, offset: usize, size: usize) -> Result<MemoryMappingArena, MmapError> {
        let mut arena = MemoryMappingArena::new(size)?;
        let mut mapped_size = 0;
        let mut area_iter = self.mem_areas.iter();
        let mut area_offset = offset;
        while mapped_size < size {
            let area = match area_iter.next() {
                Some(area) => area,
                None => {
                    return Err(MmapError::InvalidRange(
                        offset,
                        size,
                        self.mem_areas.iter().map(|a| a.length).sum(),
                    ));
                }
            };
            if area_offset > area.length {
                area_offset -= area.length;
            } else {
                let mapping_length = std::cmp::min(area.length - area_offset, size - mapped_size);
                arena.add_fd_offset(mapped_size, mapping_length, &self.desc, area.offset)?;
                mapped_size += mapping_length;
                area_offset = 0;
            }
        }
        Ok(arena)
    }
}

pub struct VirtioObjectHandle {
    /// Descriptor for the object.
    pub desc: SafeDescriptor,
    /// Modifier to apply to frame resources.
    pub modifier: u64,
}

impl BufferHandle for VirtioObjectHandle {
    fn try_clone(&self) -> Result<Self, base::Error> {
        Ok(Self {
            desc: self.desc.try_clone()?,
            modifier: self.modifier,
        })
    }

    fn get_mapping(&self, offset: usize, size: usize) -> Result<MemoryMappingArena, MmapError> {
        MemoryMappingBuilder::new(size)
            .from_descriptor(&self.desc)
            .offset(offset as u64)
            .build()
            .map(MemoryMappingArena::from)
    }
}

pub enum GuestResourceHandle {
    GuestPages(GuestMemHandle),
    VirtioObject(VirtioObjectHandle),
}

impl BufferHandle for GuestResourceHandle {
    fn try_clone(&self) -> Result<Self, base::Error> {
        Ok(match self {
            Self::GuestPages(handle) => Self::GuestPages(handle.try_clone()?),
            Self::VirtioObject(handle) => Self::VirtioObject(handle.try_clone()?),
        })
    }

    fn get_mapping(&self, offset: usize, size: usize) -> Result<MemoryMappingArena, MmapError> {
        match self {
            GuestResourceHandle::GuestPages(handle) => handle.get_mapping(offset, size),
            GuestResourceHandle::VirtioObject(handle) => handle.get_mapping(offset, size),
        }
    }
}

pub struct GuestResource {
    /// Handle to the backing memory.
    pub handle: GuestResourceHandle,
    /// Layout of color planes, if the resource will receive frames.
    pub planes: Vec<FramePlane>,
}

#[derive(Debug, ThisError)]
pub enum GuestMemResourceCreationError {
    #[error("Provided slice of entries is empty")]
    NoEntriesProvided,
    #[error("cannot get shm region: {0}")]
    CantGetShmRegion(GuestMemoryError),
    #[error("cannot get shm offset: {0}")]
    CantGetShmOffset(GuestMemoryError),
    #[error("error while cloning shm region descriptor: {0}")]
    DescriptorCloneError(base::Error),
}

#[derive(Debug, ThisError)]
pub enum ObjectResourceCreationError {
    #[error("uuid {0:08} is larger than 32 bits")]
    UuidNot32Bits(u128),
    #[error("resource returned by bridge is not a buffer")]
    NotABuffer,
    #[error("resource bridge failure: {0}")]
    ResourceBridgeFailure(ResourceBridgeError),
}

impl GuestResource {
    /// Try to convert an unresolved virtio guest memory entry into a resolved guest memory
    /// resource.
    ///
    /// Convert `mem_entry` into the guest memory resource it represents and resolve it through
    /// `mem`. `planes_format` describes the format of the individual planes for the buffer.
    pub fn from_virtio_guest_mem_entry(
        mem_entries: &[virtio_video_mem_entry],
        mem: &GuestMemory,
        planes_format: &[PlaneFormat],
    ) -> Result<GuestResource, GuestMemResourceCreationError> {
        let region_desc = match mem_entries.first() {
            None => return Err(GuestMemResourceCreationError::NoEntriesProvided),
            Some(entry) => {
                let addr: u64 = entry.addr.into();

                let guest_region = mem
                    .shm_region(GuestAddress(addr))
                    .map_err(GuestMemResourceCreationError::CantGetShmRegion)?;
                let desc = base::clone_descriptor(guest_region)
                    .map_err(GuestMemResourceCreationError::DescriptorCloneError)?;
                // Safe because we are the sole owner of the duplicated descriptor.
                unsafe { SafeDescriptor::from_raw_descriptor(desc) }
            }
        };

        let mem_areas = mem_entries
            .iter()
            .map(|entry| {
                let addr: u64 = entry.addr.into();
                let length: u32 = entry.length.into();
                let region_offset = mem
                    .offset_from_base(GuestAddress(addr))
                    .map_err(GuestMemResourceCreationError::CantGetShmOffset)
                    .unwrap();

                GuestMemArea {
                    offset: region_offset,
                    length: length as usize,
                }
            })
            .collect();

        // The plane information can be computed from the currently set format.
        let mut buffer_offset = 0;
        let planes = planes_format
            .iter()
            .map(|p| {
                let plane_offset = buffer_offset;
                buffer_offset += p.plane_size;

                FramePlane {
                    offset: plane_offset as usize,
                    stride: p.stride as usize,
                }
            })
            .collect();

        Ok(GuestResource {
            handle: GuestResourceHandle::GuestPages(GuestMemHandle {
                desc: region_desc,
                mem_areas,
            }),
            planes,
        })
    }

    /// Try to convert an unresolved virtio object entry into a resolved object resource.
    ///
    /// Convert `object` into the object resource it represents and resolve it through `res_bridge`.
    /// Returns an error if the object's UUID is invalid or cannot be resolved to a buffer object
    /// by `res_bridge`.
    pub fn from_virtio_object_entry(
        object: virtio_video_object_entry,
        res_bridge: &base::Tube,
    ) -> Result<GuestResource, ObjectResourceCreationError> {
        // We trust that the caller has chosen the correct object type.
        let uuid = u128::from_be_bytes(object.uuid);

        // TODO(stevensd): `Virtio3DBackend::resource_assign_uuid` is currently implemented to use
        // 32-bits resource_handles as UUIDs. Once it starts using real UUIDs, we need to update
        // this conversion.
        let handle = TryInto::<u32>::try_into(uuid)
            .map_err(|_| ObjectResourceCreationError::UuidNot32Bits(uuid))?;

        let buffer_info = match resource_bridge::get_resource_info(
            res_bridge,
            ResourceRequest::GetBuffer { id: handle },
        ) {
            Ok(ResourceInfo::Buffer(buffer_info)) => buffer_info,
            Ok(_) => return Err(ObjectResourceCreationError::NotABuffer),
            Err(e) => return Err(ObjectResourceCreationError::ResourceBridgeFailure(e)),
        };

        Ok(GuestResource {
            handle: GuestResourceHandle::VirtioObject(VirtioObjectHandle {
                // Safe because `buffer_info.file` is a valid file descriptor and we are stealing
                // it.
                desc: unsafe {
                    SafeDescriptor::from_raw_descriptor(buffer_info.file.into_raw_descriptor())
                },
                modifier: buffer_info.modifier,
            }),
            planes: buffer_info
                .planes
                .iter()
                .take_while(|p| p.offset != 0 || p.stride != 0)
                .map(|p| FramePlane {
                    offset: p.offset as usize,
                    stride: p.stride as usize,
                })
                .collect(),
        })
    }

    #[cfg(feature = "video-encoder")]
    pub fn try_clone(&self) -> Result<Self, base::Error> {
        Ok(Self {
            handle: self.handle.try_clone()?,
            planes: self.planes.clone(),
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use base::{MappedRegion, SafeDescriptor, SharedMemory};

    /// Creates a sparse guest memory handle using as many pages as there are entries in
    /// `page_order`. The page with index `0` will be the first page, `1` will be the second page,
    /// etc.
    ///
    /// The memory handle is filled with increasing u32s starting from page 0, then page 1, and so
    /// on. Finally the handle is mapped into a linear space and we check that the written integers
    /// appear in the expected order.
    fn check_guest_mem_handle(page_order: &[usize]) {
        const PAGE_SIZE: usize = 0x1000;
        const U32_SIZE: usize = std::mem::size_of::<u32>();
        const ENTRIES_PER_PAGE: usize = PAGE_SIZE as usize / std::mem::size_of::<u32>();

        // Fill a vector of the same size as the handle with u32s of increasing value, following
        // the page layout given as argument.
        let mut data = vec![0u8; PAGE_SIZE * page_order.len()];
        for (page_index, page) in page_order.iter().enumerate() {
            let page_slice =
                &mut data[(page * PAGE_SIZE as usize)..((page + 1) * PAGE_SIZE as usize)];
            for (index, chunk) in page_slice.chunks_exact_mut(4).enumerate() {
                let sized_chunk: &mut [u8; 4] = chunk.try_into().unwrap();
                *sized_chunk = (((page_index * ENTRIES_PER_PAGE) + index) as u32).to_ne_bytes();
            }
        }

        // Copy the initialized vector's content into an anonymous shared memory.
        let mem = SharedMemory::new("data-dest", data.len() as u64).unwrap();
        let mapping = MemoryMappingBuilder::new(mem.size() as usize)
            .from_shared_memory(&mem)
            .build()
            .unwrap();
        assert_eq!(mapping.write_slice(&data, 0).unwrap(), data.len());

        // Create the `GuestMemHandle` we will try to map and retrieve the data from.
        let mem_handle = GuestResourceHandle::GuestPages(GuestMemHandle {
            desc: unsafe {
                SafeDescriptor::from_raw_descriptor(base::clone_descriptor(&mem).unwrap())
            },
            mem_areas: page_order
                .iter()
                .map(|&page| GuestMemArea {
                    offset: page as u64 * PAGE_SIZE as u64,
                    length: PAGE_SIZE as usize,
                })
                .collect(),
        });

        // Map the handle into a linear memory area, retrieve its data into a new vector, and check
        // that its u32s appear to increase linearly.
        let mapping = mem_handle.get_mapping(0, mem.size() as usize).unwrap();
        let mut data = vec![0u8; PAGE_SIZE * page_order.len()];
        unsafe { std::ptr::copy_nonoverlapping(mapping.as_ptr(), data.as_mut_ptr(), data.len()) };
        for (index, chunk) in data.chunks_exact(U32_SIZE).enumerate() {
            let sized_chunk: &[u8; 4] = chunk.try_into().unwrap();
            assert_eq!(u32::from_ne_bytes(*sized_chunk), index as u32);
        }
    }

    // Fill a guest memory handle with a single memory page.
    // Then check that the data can be properly mapped and appears in the expected order.
    #[test]
    fn test_single_guest_mem_handle() {
        check_guest_mem_handle(&[0])
    }

    // Fill a guest memory handle with 4 memory pages that are contiguous.
    // Then check that the pages appear in the expected order in the mapping.
    #[test]
    fn test_linear_guest_mem_handle() {
        check_guest_mem_handle(&[0, 1, 2, 3])
    }

    // Fill a guest memory handle with 8 pages mapped in non-linear order.
    // Then check that the pages appear in the expected order in the mapping.
    #[test]
    fn test_sparse_guest_mem_handle() {
        check_guest_mem_handle(&[1, 7, 6, 3, 5, 0, 4, 2])
    }
}
<|endoftext|>


<commit_before>extern crate libsqlite3_sys as ffi;

use std::ffi::{CStr, CString};
use std::io::{stderr, Write};
use std::os::raw as libc;
use std::ptr::{self, NonNull};

use super::raw::RawConnection;
use super::serialized_value::SerializedValue;
use super::sqlite_value::SqliteRow;
use super::SqliteValue;
use crate::result::Error::DatabaseError;
use crate::result::*;
use crate::sqlite::SqliteType;

pub struct Statement {
    inner_statement: NonNull<ffi::sqlite3_stmt>,
    bind_index: libc::c_int,
}

impl Statement {
    pub fn prepare(raw_connection: &RawConnection, sql: &str) -> QueryResult<Self> {
        let mut stmt = ptr::null_mut();
        let mut unused_portion = ptr::null();
        let prepare_result = unsafe {
            ffi::sqlite3_prepare_v2(
                raw_connection.internal_connection.as_ptr(),
                CString::new(sql)?.as_ptr(),
                sql.len() as libc::c_int,
                &mut stmt,
                &mut unused_portion,
            )
        };

        ensure_sqlite_ok(prepare_result, raw_connection.internal_connection.as_ptr()).map(|_| {
            Statement {
                inner_statement: unsafe { NonNull::new_unchecked(stmt) },
                bind_index: 0,
            }
        })
    }

    pub fn bind(&mut self, tpe: SqliteType, value: Option<Vec<u8>>) -> QueryResult<()> {
        self.bind_index += 1;
        let value = SerializedValue {
            ty: tpe,
            data: value,
        };
        let result = value.bind_to(self.inner_statement, self.bind_index);

        ensure_sqlite_ok(result, self.raw_connection())
    }

    fn reset(&mut self) {
        self.bind_index = 0;
        unsafe { ffi::sqlite3_reset(self.inner_statement.as_ptr()) };
    }

    fn raw_connection(&self) -> *mut ffi::sqlite3 {
        unsafe { ffi::sqlite3_db_handle(self.inner_statement.as_ptr()) }
    }
}

fn ensure_sqlite_ok(code: libc::c_int, raw_connection: *mut ffi::sqlite3) -> QueryResult<()> {
    if code == ffi::SQLITE_OK {
        Ok(())
    } else {
        Err(last_error(raw_connection))
    }
}

fn last_error(raw_connection: *mut ffi::sqlite3) -> Error {
    let error_message = last_error_message(raw_connection);
    let error_information = Box::new(error_message);
    let error_kind = match last_error_code(raw_connection) {
        ffi::SQLITE_CONSTRAINT_UNIQUE | ffi::SQLITE_CONSTRAINT_PRIMARYKEY => {
            DatabaseErrorKind::UniqueViolation
        }
        ffi::SQLITE_CONSTRAINT_FOREIGNKEY => DatabaseErrorKind::ForeignKeyViolation,
        ffi::SQLITE_CONSTRAINT_NOTNULL => DatabaseErrorKind::NotNullViolation,
        ffi::SQLITE_CONSTRAINT_CHECK => DatabaseErrorKind::CheckViolation,
        _ => DatabaseErrorKind::__Unknown,
    };
    DatabaseError(error_kind, error_information)
}

fn last_error_message(conn: *mut ffi::sqlite3) -> String {
    let c_str = unsafe { CStr::from_ptr(ffi::sqlite3_errmsg(conn)) };
    c_str.to_string_lossy().into_owned()
}

fn last_error_code(conn: *mut ffi::sqlite3) -> libc::c_int {
    unsafe { ffi::sqlite3_extended_errcode(conn) }
}

impl Drop for Statement {
    fn drop(&mut self) {
        use std::thread::panicking;

        let raw_connection = self.raw_connection();
        let finalize_result = unsafe { ffi::sqlite3_finalize(self.inner_statement.as_ptr()) };
        if let Err(e) = ensure_sqlite_ok(finalize_result, raw_connection) {
            if panicking() {
                write!(
                    stderr(),
                    "Error finalizing SQLite prepared statement: {:?}",
                    e
                )
                .expect("Error writing to `stderr`");
            } else {
                panic!("Error finalizing SQLite prepared statement: {:?}", e);
            }
        }
    }
}

pub struct StatementUse<'a: 'b, 'b> {
    statement: &'a mut Statement,
    column_names: Vec<&'b str>,
}

impl<'a, 'b> StatementUse<'a, 'b> {
    pub(in crate::sqlite::connection) fn new(statement: &'a mut Statement) -> Self {
        StatementUse {
            statement,
            // Init with empty vector because column names
            // can change till the first call to `step()`
            column_names: Vec::new(),
        }
    }

    pub(in crate::sqlite::connection) fn run(&mut self) -> QueryResult<()> {
        self.step().map(|_| ())
    }

    pub(in crate::sqlite::connection) fn step<'c>(
        &'c mut self,
    ) -> QueryResult<Option<SqliteRow<'a, 'b, 'c>>>
    where
        'b: 'c,
    {
        let res = unsafe {
            match ffi::sqlite3_step(self.statement.inner_statement.as_ptr()) {
                ffi::SQLITE_DONE => Ok(None),
                ffi::SQLITE_ROW => Ok(Some(())),
                _ => Err(last_error(self.statement.raw_connection())),
            }
        }?;
        if self.column_names.is_empty() {
            self.column_names = (0..self.column_count())
                .map(|idx| unsafe { self.column_name(idx) })
                .collect();
        }
        Ok(res.map(move |()| SqliteRow::new(self)))
    }

    // The returned string pointer is valid until either the prepared statement is
    // destroyed by sqlite3_finalize() or until the statement is automatically
    // reprepared by the first call to sqlite3_step() for a particular run or
    // until the next call to sqlite3_column_name() or sqlite3_column_name16()
    // on the same column.
    //
    // https://sqlite.org/c3ref/column_name.html
    //
    // As result of this requirements: Never use that function outside of `ColumnInformation`
    // and never use `ColumnInformation` outside of `StatementUse`
    unsafe fn column_name(&mut self, idx: i32) -> &'b str {
        let name = {
            let column_name =
                ffi::sqlite3_column_name(self.statement.inner_statement.as_ptr(), idx);
            assert!(
                !column_name.is_null(),
                "The Sqlite documentation states that it only returns a \
                 null pointer here if we are in a OOM condition."
            );
            CStr::from_ptr(column_name)
        };
        let name = name.to_str().expect(
            "The Sqlite documentation states that this is UTF8. \
             If you see this error message something has gone \
             horribliy wrong. Please open an issue at the \
             diesel repository.",
        );
        name
    }

    pub(in crate::sqlite::connection) fn column_count(&self) -> i32 {
        unsafe { ffi::sqlite3_column_count(self.statement.inner_statement.as_ptr()) }
    }

    pub(in crate::sqlite::connection) fn index_for_column_name(
        &self,
        field_name: &str,
    ) -> Option<usize> {
        self.column_names
            .iter()
            .enumerate()
            .find(|(_, name)| name == &&field_name)
            .map(|(idx, _)| idx)
    }

    pub(in crate::sqlite::connection) fn field_name<'c>(&'c self, idx: i32) -> Option<&'c str>
    where
        'b: 'c,
    {
        self.column_names.get(idx as usize).map(|a| *a)
    }

    pub(in crate::sqlite::connection) fn value<'c>(
        &'c self,
        idx: i32,
    ) -> Option<super::SqliteValue<'c>>
    where
        'b: 'c,
    {
        unsafe {
            let ptr = ffi::sqlite3_column_value(self.statement.inner_statement.as_ptr(), idx);
            SqliteValue::new(ptr)
        }
    }
}

impl<'a, 'b> Drop for StatementUse<'a, 'b> {
    fn drop(&mut self) {
        self.statement.reset();
    }
}
<commit_msg>Fix Clippy warning<commit_after>extern crate libsqlite3_sys as ffi;

use std::ffi::{CStr, CString};
use std::io::{stderr, Write};
use std::os::raw as libc;
use std::ptr::{self, NonNull};

use super::raw::RawConnection;
use super::serialized_value::SerializedValue;
use super::sqlite_value::SqliteRow;
use super::SqliteValue;
use crate::result::Error::DatabaseError;
use crate::result::*;
use crate::sqlite::SqliteType;

pub struct Statement {
    inner_statement: NonNull<ffi::sqlite3_stmt>,
    bind_index: libc::c_int,
}

impl Statement {
    pub fn prepare(raw_connection: &RawConnection, sql: &str) -> QueryResult<Self> {
        let mut stmt = ptr::null_mut();
        let mut unused_portion = ptr::null();
        let prepare_result = unsafe {
            ffi::sqlite3_prepare_v2(
                raw_connection.internal_connection.as_ptr(),
                CString::new(sql)?.as_ptr(),
                sql.len() as libc::c_int,
                &mut stmt,
                &mut unused_portion,
            )
        };

        ensure_sqlite_ok(prepare_result, raw_connection.internal_connection.as_ptr()).map(|_| {
            Statement {
                inner_statement: unsafe { NonNull::new_unchecked(stmt) },
                bind_index: 0,
            }
        })
    }

    pub fn bind(&mut self, tpe: SqliteType, value: Option<Vec<u8>>) -> QueryResult<()> {
        self.bind_index += 1;
        let value = SerializedValue {
            ty: tpe,
            data: value,
        };
        let result = value.bind_to(self.inner_statement, self.bind_index);

        ensure_sqlite_ok(result, self.raw_connection())
    }

    fn reset(&mut self) {
        self.bind_index = 0;
        unsafe { ffi::sqlite3_reset(self.inner_statement.as_ptr()) };
    }

    fn raw_connection(&self) -> *mut ffi::sqlite3 {
        unsafe { ffi::sqlite3_db_handle(self.inner_statement.as_ptr()) }
    }
}

fn ensure_sqlite_ok(code: libc::c_int, raw_connection: *mut ffi::sqlite3) -> QueryResult<()> {
    if code == ffi::SQLITE_OK {
        Ok(())
    } else {
        Err(last_error(raw_connection))
    }
}

fn last_error(raw_connection: *mut ffi::sqlite3) -> Error {
    let error_message = last_error_message(raw_connection);
    let error_information = Box::new(error_message);
    let error_kind = match last_error_code(raw_connection) {
        ffi::SQLITE_CONSTRAINT_UNIQUE | ffi::SQLITE_CONSTRAINT_PRIMARYKEY => {
            DatabaseErrorKind::UniqueViolation
        }
        ffi::SQLITE_CONSTRAINT_FOREIGNKEY => DatabaseErrorKind::ForeignKeyViolation,
        ffi::SQLITE_CONSTRAINT_NOTNULL => DatabaseErrorKind::NotNullViolation,
        ffi::SQLITE_CONSTRAINT_CHECK => DatabaseErrorKind::CheckViolation,
        _ => DatabaseErrorKind::__Unknown,
    };
    DatabaseError(error_kind, error_information)
}

fn last_error_message(conn: *mut ffi::sqlite3) -> String {
    let c_str = unsafe { CStr::from_ptr(ffi::sqlite3_errmsg(conn)) };
    c_str.to_string_lossy().into_owned()
}

fn last_error_code(conn: *mut ffi::sqlite3) -> libc::c_int {
    unsafe { ffi::sqlite3_extended_errcode(conn) }
}

impl Drop for Statement {
    fn drop(&mut self) {
        use std::thread::panicking;

        let raw_connection = self.raw_connection();
        let finalize_result = unsafe { ffi::sqlite3_finalize(self.inner_statement.as_ptr()) };
        if let Err(e) = ensure_sqlite_ok(finalize_result, raw_connection) {
            if panicking() {
                write!(
                    stderr(),
                    "Error finalizing SQLite prepared statement: {:?}",
                    e
                )
                .expect("Error writing to `stderr`");
            } else {
                panic!("Error finalizing SQLite prepared statement: {:?}", e);
            }
        }
    }
}

pub struct StatementUse<'a: 'b, 'b> {
    statement: &'a mut Statement,
    column_names: Vec<&'b str>,
}

impl<'a, 'b> StatementUse<'a, 'b> {
    pub(in crate::sqlite::connection) fn new(statement: &'a mut Statement) -> Self {
        StatementUse {
            statement,
            // Init with empty vector because column names
            // can change till the first call to `step()`
            column_names: Vec::new(),
        }
    }

    pub(in crate::sqlite::connection) fn run(&mut self) -> QueryResult<()> {
        self.step().map(|_| ())
    }

    pub(in crate::sqlite::connection) fn step<'c>(
        &'c mut self,
    ) -> QueryResult<Option<SqliteRow<'a, 'b, 'c>>>
    where
        'b: 'c,
    {
        let res = unsafe {
            match ffi::sqlite3_step(self.statement.inner_statement.as_ptr()) {
                ffi::SQLITE_DONE => Ok(None),
                ffi::SQLITE_ROW => Ok(Some(())),
                _ => Err(last_error(self.statement.raw_connection())),
            }
        }?;
        if self.column_names.is_empty() {
            self.column_names = (0..self.column_count())
                .map(|idx| unsafe { self.column_name(idx) })
                .collect();
        }
        Ok(res.map(move |()| SqliteRow::new(self)))
    }

    // The returned string pointer is valid until either the prepared statement is
    // destroyed by sqlite3_finalize() or until the statement is automatically
    // reprepared by the first call to sqlite3_step() for a particular run or
    // until the next call to sqlite3_column_name() or sqlite3_column_name16()
    // on the same column.
    //
    // https://sqlite.org/c3ref/column_name.html
    //
    // As result of this requirements: Never use that function outside of `ColumnInformation`
    // and never use `ColumnInformation` outside of `StatementUse`
    unsafe fn column_name(&mut self, idx: i32) -> &'b str {
        let name = {
            let column_name =
                ffi::sqlite3_column_name(self.statement.inner_statement.as_ptr(), idx);
            assert!(
                !column_name.is_null(),
                "The Sqlite documentation states that it only returns a \
                 null pointer here if we are in a OOM condition."
            );
            CStr::from_ptr(column_name)
        };
        name.to_str().expect(
            "The Sqlite documentation states that this is UTF8. \
             If you see this error message something has gone \
             horribliy wrong. Please open an issue at the \
             diesel repository.",
        )
    }

    pub(in crate::sqlite::connection) fn column_count(&self) -> i32 {
        unsafe { ffi::sqlite3_column_count(self.statement.inner_statement.as_ptr()) }
    }

    pub(in crate::sqlite::connection) fn index_for_column_name(
        &self,
        field_name: &str,
    ) -> Option<usize> {
        self.column_names
            .iter()
            .enumerate()
            .find(|(_, name)| name == &&field_name)
            .map(|(idx, _)| idx)
    }

    pub(in crate::sqlite::connection) fn field_name<'c>(&'c self, idx: i32) -> Option<&'c str>
    where
        'b: 'c,
    {
        self.column_names.get(idx as usize).copied()
    }

    pub(in crate::sqlite::connection) fn value<'c>(
        &'c self,
        idx: i32,
    ) -> Option<super::SqliteValue<'c>>
    where
        'b: 'c,
    {
        unsafe {
            let ptr = ffi::sqlite3_column_value(self.statement.inner_statement.as_ptr(), idx);
            SqliteValue::new(ptr)
        }
    }
}

impl<'a, 'b> Drop for StatementUse<'a, 'b> {
    fn drop(&mut self) {
        self.statement.reset();
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::Write;
use std::sync;

use liquid_error::Result;
use liquid_interpreter as interpreter;
use liquid_interpreter::Renderable;

pub struct Template {
    pub(crate) template: interpreter::Template,
    pub(crate) filters: sync::Arc<HashMap<&'static str, interpreter::BoxedValueFilter>>,
}

impl Template {
    /// Renders an instance of the Template, using the given globals.
    pub fn render(&self, globals: &interpreter::Globals) -> Result<String> {
        let mut data = Vec::new();
        self.render_to(&mut data, globals)?;
        Ok(String::from_utf8(data).expect("render only writes UTF-8"))
    }

    /// Renders an instance of the Template, using the given globals.
    pub fn render_to(&self, writer: &mut Write, globals: &interpreter::Globals) -> Result<()> {
        let mut data = interpreter::ContextBuilder::new()
            .set_filters(&self.filters)
            .set_globals(globals)
            .build();
        self.template.render_to(writer, &mut data)
    }
}
<commit_msg>perf: Default buffer size<commit_after>use std::collections::HashMap;
use std::io::Write;
use std::sync;

use liquid_error::Result;
use liquid_interpreter as interpreter;
use liquid_interpreter::Renderable;

pub struct Template {
    pub(crate) template: interpreter::Template,
    pub(crate) filters: sync::Arc<HashMap<&'static str, interpreter::BoxedValueFilter>>,
}

impl Template {
    /// Renders an instance of the Template, using the given globals.
    pub fn render(&self, globals: &interpreter::Globals) -> Result<String> {
        const BEST_GUESS: usize = 10_000;
        let mut data = Vec::with_capacity(BEST_GUESS);
        self.render_to(&mut data, globals)?;
        Ok(String::from_utf8(data).expect("render only writes UTF-8"))
    }

    /// Renders an instance of the Template, using the given globals.
    pub fn render_to(&self, writer: &mut Write, globals: &interpreter::Globals) -> Result<()> {
        let mut data = interpreter::ContextBuilder::new()
            .set_filters(&self.filters)
            .set_globals(globals)
            .build();
        self.template.render_to(writer, &mut data)
    }
}
<|endoftext|>


<commit_before>use bincode::{serialize, deserialize, Infinite};

use leveldb::database::Database;
use leveldb::kv::KV;
use leveldb::iterator::Iterable;
use leveldb::options::{Options,WriteOptions,ReadOptions};

use std::path::Path;

use serde_json;

#[derive(Serialize, Deserialize)]
pub struct ShapeshiftDeposit {
    pub status: Option<String>,
    pub address: String,              // altcoin address
    pub withdraw: Option<String>,     //[withdrawal address],
    pub incomingCoin: Option<String>, //[amount deposited],
    pub incomingType: Option<String>, //[coin type of deposit],
    pub outgoingCoin: Option<String>, //[amount sent to withdrawal address],
    pub outgoingType: Option<String>, //[coin type of withdrawal],
    pub transaction: Option<String>,  //[transaction id of coin sent to withdrawal address],
    pub orderId: String,
    pub expiration: usize,
    pub id: usize,
}

#[derive(Serialize, Deserialize)]
pub struct RegisteredToken {
    pub token_address: String,
    pub crowdsale_address: String,
    pub name: String,
    pub symbol: String,
    pub decimal: u8,
    pub tok_type: String,
    pub icon: String,
    pub url: String,
    pub blerb: String,
    pub date_changed: usize,
    pub changed_by: String,
    pub change_reason: String,
}

pub struct TokenDB {
  db: Database<i32>
}

impl TokenDB {
  pub fn new(path: &Path) -> TokenDB {
      let mut options = Options::new();
      options.create_if_missing = true;
      let db = match Database::open(path, options) {
        Ok(db) => { db },
        Err(e) => { panic!("failed to open database: {:?}", e) }
      };
      TokenDB {
        db: db,
      }
  }

  pub fn write_deposit(&self, deposit: &ShapeshiftDeposit) -> () {
      let write_opts = WriteOptions::new();
      // turn into buffer
      let bytes: Vec<u8> = serialize(deposit, Infinite).unwrap();
      match self.db.put(write_opts, deposit.id as i32, &bytes) {
          Ok(_) => { () },
          Err(e) => { panic!("failed to write to database: {:?}", e) }
      };
  }

  pub fn read_deposit(&self, key: i32) -> Option<Vec<u8>> {
      let read_opts = ReadOptions::new();
      let res = self.db.get(read_opts, key);
      let data = match res {
        Ok(data) => { data },
        Err(e) => { panic!("failed reading data: {:?}", e) }
      };
      data
  }

  pub fn delete_deposit(&self, key: i32) -> () {
      let write_opts = WriteOptions::new();
      let res = self.db.delete(write_opts, key);
      let data = match res {
        Ok(_) => { () },
        Err(e) => { panic!("failed deleting data: {:?}", e) }
      };
  }

  pub fn dump(&self) -> Vec<Vec<u8>> {
      let read_opts = ReadOptions::new();
      let mut iter = self.db.value_iter(read_opts);
      let mut data = vec![];
      loop {
          match iter.next() {
              Some(d) => {
                  data.push(d);
                },
                _ => { break; }
          };
      };
      data
  }

  pub fn dump_addrs(&self) -> Vec<String> {
      let read_opts = ReadOptions::new();
      let mut iter = self.db.value_iter(read_opts);
      let mut data = vec![];
      loop {
          match iter.next() {
              Some(d) => {
                  data.push(deserialize::<ShapeshiftDeposit>(&d).unwrap().address);
                },
                _ => { break; }
          };
      };
      data
  }

}
<commit_msg>update data fields<commit_after>use bincode::{serialize, deserialize, Infinite};

use leveldb::database::Database;
use leveldb::kv::KV;
use leveldb::iterator::Iterable;
use leveldb::options::{Options,WriteOptions,ReadOptions};

use std::path::Path;

use serde_json;

#[derive(Serialize, Deserialize)]
pub struct ShapeshiftDeposit {
    pub status: Option<String>,
    pub address: String,              // recipient new wallet address
    pub deposit: String,              //[altcoin deposit address],
    pub withdrawal: String,           //[withdrawal (RELAY) address],
    pub withdrawalAmount: String,     //[amount to be relayed],
    pub depositAmount: String,        //[amount deposited],
    pub depositType: String,          //[coin type of deposit],
    pub transaction: Option<String>,  //[transaction id of coin sent to withdrawal address],
    pub orderId: String,
    pub expiration: usize,
    pub id: usize,
}

#[derive(Serialize, Deserialize)]
pub struct RegisteredToken {
    pub token_address: String,
    pub crowdsale_address: String,
    pub name: String,
    pub symbol: String,
    pub decimal: u8,
    pub tok_type: String,
    pub icon: String,
    pub url: String,
    pub blerb: String,
    pub date_changed: usize,
    pub changed_by: String,
    pub change_reason: String,
}

pub struct TokenDB {
  db: Database<i32>
}

impl TokenDB {
  pub fn new(path: &Path) -> TokenDB {
      let mut options = Options::new();
      options.create_if_missing = true;
      let db = match Database::open(path, options) {
        Ok(db) => { db },
        Err(e) => { panic!("failed to open database: {:?}", e) }
      };
      TokenDB {
        db: db,
      }
  }

  pub fn write_deposit(&self, deposit: &ShapeshiftDeposit) -> () {
      let write_opts = WriteOptions::new();
      // turn into buffer
      let bytes: Vec<u8> = serialize(deposit, Infinite).unwrap();
      match self.db.put(write_opts, deposit.id as i32, &bytes) {
          Ok(_) => { () },
          Err(e) => { panic!("failed to write to database: {:?}", e) }
      };
  }

  pub fn read_deposit(&self, key: i32) -> Option<Vec<u8>> {
      let read_opts = ReadOptions::new();
      let res = self.db.get(read_opts, key);
      let data = match res {
        Ok(data) => { data },
        Err(e) => { panic!("failed reading data: {:?}", e) }
      };
      data
  }

  pub fn delete_deposit(&self, key: i32) -> () {
      let write_opts = WriteOptions::new();
      let res = self.db.delete(write_opts, key);
      let data = match res {
        Ok(_) => { () },
        Err(e) => { panic!("failed deleting data: {:?}", e) }
      };
  }

  pub fn dump(&self) -> Vec<Vec<u8>> {
      let read_opts = ReadOptions::new();
      let mut iter = self.db.value_iter(read_opts);
      let mut data = vec![];
      loop {
          match iter.next() {
              Some(d) => {
                  data.push(d);
                },
                _ => { break; }
          };
      };
      data
  }

  pub fn dump_addrs(&self) -> Vec<String> {
      let read_opts = ReadOptions::new();
      let mut iter = self.db.value_iter(read_opts);
      let mut data = vec![];
      loop {
          match iter.next() {
              Some(d) => {
                  data.push(deserialize::<ShapeshiftDeposit>(&d).unwrap().address);
                },
                _ => { break; }
          };
      };
      data
  }

}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::mem;
use std::ptr;

/// Unsafe wrapper around a trait object.
///
/// This struct can be used to move around a trait object when its lifetime is not expressible. Be
/// aware though that moving the object from which the trait has been built will cause crashes,
/// since the pointer stored in this struct will not change with it. For this reason, getting the
/// trait back from this object is unsafe.
pub struct UnsafeTraitObject<T: ?Sized> {
    raw_ptr: Vec<u8>,
    _phantom: PhantomData<T>,
}

impl<T: ?Sized> UnsafeTraitObject<T> {
    pub fn new(e: &T) -> Self {
        let mut r = vec![0u8; mem::size_of_val(e)];
        unsafe {
            let ptr: *mut &T = mem::transmute(r.as_mut_ptr());
            ptr::write(ptr, e);
        };
        UnsafeTraitObject {
            raw_ptr: r,
            _phantom: PhantomData,
        }
    }

    #[allow(dead_code)]
    pub unsafe fn as_inner(&self) -> &T {
        let ptr: *mut &T = mem::transmute(self.raw_ptr.as_ptr());
        ptr::read(ptr)
    }

    pub unsafe fn as_inner_mut(&mut self) -> &mut T {
        let ptr: *mut &mut T = mem::transmute(self.raw_ptr.as_ptr());
        ptr::read(ptr)
    }
}
<commit_msg>Fixed crash in UnsafeTraitObject<commit_after>use std::marker::PhantomData;
use std::mem;
use std::ptr;

/// Unsafe wrapper around a trait object.
///
/// This struct can be used to move around a trait object when its lifetime is not expressible. Be
/// aware though that moving the object from which the trait has been built will cause crashes,
/// since the pointer stored in this struct will not change with it. For this reason, getting the
/// trait back from this object is unsafe.
pub struct UnsafeTraitObject<T: ?Sized> {
    raw_ptr: Vec<u8>,
    _phantom: PhantomData<T>,
}

impl<T: ?Sized> UnsafeTraitObject<T> {
    pub fn new(e: &T) -> Self {
        let mut r = vec![0u8; mem::size_of::<&T>()];
        unsafe {
            let ptr: *mut &T = mem::transmute(r.as_mut_ptr());
            ptr::write(ptr, e);
        };
        UnsafeTraitObject {
            raw_ptr: r,
            _phantom: PhantomData,
        }
    }

    #[allow(dead_code)]
    pub unsafe fn as_inner(&self) -> &T {
        let ptr: *mut &T = mem::transmute(self.raw_ptr.as_ptr());
        ptr::read(ptr)
    }

    pub unsafe fn as_inner_mut(&mut self) -> &mut T {
        let ptr: *mut &mut T = mem::transmute(self.raw_ptr.as_ptr());
        ptr::read(ptr)
    }
}
<|endoftext|>