<commit_before>

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

use std::marker::PhantomData;

use prelude::*;

use EdgeType;
use graph::Node;
use graph::{IndexType, Edge};
use stable_graph::StableGraph;
use util::rev;
use serde_utils::MappedSequenceVisitor;
use serde_utils::CollectSeqWithLength;
use serde_utils::{IntoSerializable, FromDeserialized};
use visit::NodeIndexable;

use super::super::serialization::{EdgeProperty, invalid_length_err, invalid_node_err};

// Serialization representation for StableGraph
// Keep in sync with deserialization and Graph
#[derive(Serialize)]
#[serde(rename = "Graph")]
#[serde(bound(serialize = "N: Serialize, E: Serialize, Ix: IndexType + Serialize"))]
pub struct SerStableGraph<'a, N: 'a, E: 'a, Ix: 'a + IndexType> {
    #[serde(serialize_with="ser_stable_graph_nodes")]
    nodes: &'a [Node<Option<N>, Ix>],
    #[serde(serialize_with="ser_stable_graph_node_holes")]
    node_holes: &'a [Node<Option<N>, Ix>],
    edge_property: EdgeProperty,
    #[serde(serialize_with="ser_stable_graph_edges")]
    edges: &'a [Edge<Option<E>, Ix>],
}

// Deserialization representation for StableGraph
// Keep in sync with serialization and Graph
#[derive(Deserialize)]
#[serde(rename = "Graph")]
#[serde(bound(deserialize = "N: Deserialize<'de>, E: Deserialize<'de>, Ix: IndexType + Deserialize<'de>"))]
pub struct DeserStableGraph<N, E, Ix> {
    #[serde(deserialize_with="deser_stable_graph_nodes")]
    nodes: Vec<Node<Option<N>, Ix>>,
    #[serde(default="Vec::new")]
    node_holes: Vec<NodeIndex<Ix>>,
    edge_property: EdgeProperty,
    #[serde(deserialize_with="deser_stable_graph_edges")]
    edges: Vec<Edge<Option<E>, Ix>>,
}

fn ser_stable_graph_nodes<S, N, Ix>(nodes: &&[Node<Option<N>, Ix>], serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer,
          N: Serialize,
          Ix: Serialize + IndexType,
{
    serializer.collect_seq_with_length(
        nodes.iter()
             .filter(|node| node.weight.is_some())
             .count(),
        nodes.iter()
             .filter_map(|node| node.weight.as_ref()))
}

fn ser_stable_graph_node_holes<S, N, Ix>(nodes: &&[Node<Option<N>, Ix>], serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer,
          N: Serialize,
          Ix: Serialize + IndexType,
{
    serializer.collect_seq_with_length(
        nodes.iter()
             .filter(|node| node.weight.is_none())
             .count(),
        nodes.iter()
             .enumerate()
             .filter_map(|(i, node)| if node.weight.is_none() { Some(NodeIndex::<Ix>::new(i)) } else { None }))
}

fn ser_stable_graph_edges<S, E, Ix>(edges: &&[Edge<Option<E>, Ix>], serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer,
          E: Serialize,
          Ix: Serialize + IndexType,
{
    serializer.collect_seq_exact(
        edges.iter()
            .map(|edge| edge.weight.as_ref().map(|w| (
               edge.source(),
               edge.target(),
               w
            ))))
}

fn deser_stable_graph_nodes<'de, D, N, Ix>(deserializer: D) -> Result<Vec<Node<Option<N>, Ix>>, D::Error>
    where D: Deserializer<'de>,
          N: Deserialize<'de>,
          Ix: IndexType + Deserialize<'de>,
{
    deserializer.deserialize_seq(MappedSequenceVisitor::new(|n|
        Ok(Node {
            weight: Some(n),
            next: [EdgeIndex::end(); 2],
        })
    ))
}

fn deser_stable_graph_edges<'de, D, N, Ix>(deserializer: D) -> Result<Vec<Edge<Option<N>, Ix>>, D::Error>
    where D: Deserializer<'de>,
          N: Deserialize<'de>,
          Ix: IndexType + Deserialize<'de>,
{
    deserializer.deserialize_seq(MappedSequenceVisitor::<Option<(NodeIndex<Ix>, NodeIndex<Ix>, N)>, _, _>::new(|x|
        if let Some((i, j, w)) = x {
            Ok(Edge {
                weight: Some(w),
                node: [i, j],
                next: [EdgeIndex::end(); 2],
            })
        } else {
            Ok(Edge {
                weight: None,
                node: [NodeIndex::end(); 2],
                next: [EdgeIndex::end(); 2],
            })
        }
    ))
}

impl<'a, N, E, Ty, Ix> IntoSerializable for &'a StableGraph<N, E, Ty, Ix>
    where Ix: IndexType,
          Ty: EdgeType,
{
    type Output = SerStableGraph<'a, N, E, Ix>;
    fn into_serializable(self) -> Self::Output {
        let nodes = &self.raw_nodes()[..self.node_bound()];
        let edges = &self.raw_edges()[..self.edge_bound()];
        SerStableGraph {
            nodes: nodes,
            node_holes: nodes,
            edges: edges,
            edge_property: EdgeProperty::from(PhantomData::<Ty>),
        }
    }
}

impl<N, E, Ty, Ix> Serialize for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType + Serialize,
          N: Serialize,
          E: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        self.into_serializable().serialize(serializer)
    }
}

impl<'a, N, E, Ty, Ix> FromDeserialized for StableGraph<N, E, Ty, Ix>
    where Ix: IndexType,
          Ty: EdgeType,
{
    type Input = DeserStableGraph<N, E, Ix>;
    fn from_deserialized<E2>(input: Self::Input) -> Result<Self, E2>
        where E2: Error
    {
        let ty = PhantomData::<Ty>::from_deserialized(input.edge_property)?;
        let mut nodes = input.nodes;
        let node_holes = input.node_holes;
        let edges = input.edges;
        if edges.len() >= <Ix as IndexType>::max().index() {
            Err(invalid_length_err::<Ix, _>("edge", edges.len()))?
        }

        // insert Nones for each hole
        let mut offset = node_holes.len();
        let node_bound = node_holes.len() + nodes.len();
        for hole_pos in rev(node_holes) {
            offset -= 1;
            if hole_pos.index() >= node_bound {
                Err(invalid_node_err(hole_pos.index(), node_bound))?;
            }
            let insert_pos = hole_pos.index() - offset;
            nodes.insert(insert_pos, Node {
                weight: None,
                next: [EdgeIndex::end(); 2],
            });
        }

        if nodes.len() >= <Ix as IndexType>::max().index() {
            Err(invalid_length_err::<Ix, _>("node", nodes.len()))?
        }

        let node_bound = nodes.len();
        let mut sgr = StableGraph {
            g: Graph {
                nodes: nodes,
                edges: edges,
                ty: ty,
            },
            node_count: 0,
            edge_count: 0,
            free_edge: EdgeIndex::end(),
            free_node: NodeIndex::end(),
        };
        sgr.link_edges().map_err(|i| invalid_node_err(i.index(), node_bound))?;
        Ok(sgr)
    }
}

impl<'de, N, E, Ty, Ix> Deserialize<'de> for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType + Deserialize<'de>,
          N: Deserialize<'de>,
          E: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        Self::from_deserialized(DeserStableGraph::deserialize(deserializer)?)
    }
}

#[test]
fn test_from_deserialized_with_holes() {
    use graph::node_index;
    use stable_graph::StableUnGraph;
    use serde::de::value::Error as SerdeError;
    use itertools::assert_equal;

    let input = DeserStableGraph::<_, (), u32> {
        nodes: vec![
            Node {
                weight: Some(1),
                next: [EdgeIndex::end(); 2],
            },
            Node {
                weight: Some(4),
                next: [EdgeIndex::end(); 2],
            },
            Node {
                weight: Some(5),
                next: [EdgeIndex::end(); 2],
            },
        ],
        node_holes: vec![
            node_index(0),
            node_index(2),
            node_index(3),
            node_index(6),
        ],
        edges: vec![],
        edge_property: EdgeProperty::Undirected,
    };
    let graph = StableUnGraph::from_deserialized::<SerdeError>(input).unwrap();

    assert_eq!(graph.node_count(), 3);
    assert_equal(
        graph.raw_nodes().iter().map(|n| n.weight.as_ref().cloned()),
        vec![None, Some(1), None, None, Some(4), Some(5), None]);
}

<commit_msg>FEAT: Fix repeated iteration in serialization of StableGraph<commit_after>

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

use std::marker::PhantomData;

use prelude::*;

use EdgeType;
use graph::Node;
use graph::{IndexType, Edge};
use stable_graph::StableGraph;
use util::rev;
use serde_utils::MappedSequenceVisitor;
use serde_utils::CollectSeqWithLength;
use serde_utils::{IntoSerializable, FromDeserialized};
use visit::NodeIndexable;

use super::super::serialization::{EdgeProperty, invalid_length_err, invalid_node_err};

// Serialization representation for StableGraph
// Keep in sync with deserialization and Graph
#[derive(Serialize)]
#[serde(rename = "Graph")]
#[serde(bound(serialize = "N: Serialize, E: Serialize, Ix: IndexType + Serialize"))]
pub struct SerStableGraph<'a, N: 'a, E: 'a, Ix: 'a + IndexType> {
    nodes: Somes<&'a [Node<Option<N>, Ix>]>,
    node_holes: Holes<&'a [Node<Option<N>, Ix>]>,
    edge_property: EdgeProperty,
    #[serde(serialize_with="ser_stable_graph_edges")]
    edges: &'a [Edge<Option<E>, Ix>],
}

// Deserialization representation for StableGraph
// Keep in sync with serialization and Graph
#[derive(Deserialize)]
#[serde(rename = "Graph")]
#[serde(bound(deserialize = "N: Deserialize<'de>, E: Deserialize<'de>, Ix: IndexType + Deserialize<'de>"))]
pub struct DeserStableGraph<N, E, Ix> {
    #[serde(deserialize_with="deser_stable_graph_nodes")]
    nodes: Vec<Node<Option<N>, Ix>>,
    #[serde(default="Vec::new")]
    node_holes: Vec<NodeIndex<Ix>>,
    edge_property: EdgeProperty,
    #[serde(deserialize_with="deser_stable_graph_edges")]
    edges: Vec<Edge<Option<E>, Ix>>,
}

/// Somes are the present node weights N, with known length.
struct Somes<T>(usize, T);

impl<'a, N, Ix> Serialize for Somes<&'a [Node<Option<N>, Ix>]>
    where N: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer,
    {
        serializer.collect_seq_with_length(self.0,
            self.1.iter().filter_map(|node| node.weight.as_ref()))
    }
}

/// Holes are the node indices of vacancies, with known length
struct Holes<T>(usize, T);

impl<'a, N, Ix> Serialize for Holes<&'a [Node<Option<N>, Ix>]>
    where Ix: Serialize + IndexType,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer,
    {
        serializer.collect_seq_with_length(self.0,
            self.1.iter()
                  .enumerate()
                  .filter_map(|(i, node)| if node.weight.is_none() {
                      Some(NodeIndex::<Ix>::new(i))
                  } else {
                      None
                  }))
    }
}

fn ser_stable_graph_edges<S, E, Ix>(edges: &&[Edge<Option<E>, Ix>], serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer,
          E: Serialize,
          Ix: Serialize + IndexType,
{
    serializer.collect_seq_exact(
        edges.iter()
            .map(|edge| edge.weight.as_ref().map(|w| (
               edge.source(),
               edge.target(),
               w
            ))))
}

fn deser_stable_graph_nodes<'de, D, N, Ix>(deserializer: D) -> Result<Vec<Node<Option<N>, Ix>>, D::Error>
    where D: Deserializer<'de>,
          N: Deserialize<'de>,
          Ix: IndexType + Deserialize<'de>,
{
    deserializer.deserialize_seq(MappedSequenceVisitor::new(|n|
        Ok(Node {
            weight: Some(n),
            next: [EdgeIndex::end(); 2],
        })
    ))
}

fn deser_stable_graph_edges<'de, D, N, Ix>(deserializer: D) -> Result<Vec<Edge<Option<N>, Ix>>, D::Error>
    where D: Deserializer<'de>,
          N: Deserialize<'de>,
          Ix: IndexType + Deserialize<'de>,
{
    deserializer.deserialize_seq(MappedSequenceVisitor::<Option<(NodeIndex<Ix>, NodeIndex<Ix>, N)>, _, _>::new(|x|
        if let Some((i, j, w)) = x {
            Ok(Edge {
                weight: Some(w),
                node: [i, j],
                next: [EdgeIndex::end(); 2],
            })
        } else {
            Ok(Edge {
                weight: None,
                node: [NodeIndex::end(); 2],
                next: [EdgeIndex::end(); 2],
            })
        }
    ))
}

impl<'a, N, E, Ty, Ix> IntoSerializable for &'a StableGraph<N, E, Ty, Ix>
    where Ix: IndexType,
          Ty: EdgeType,
{
    type Output = SerStableGraph<'a, N, E, Ix>;
    fn into_serializable(self) -> Self::Output {
        let nodes = &self.raw_nodes()[..self.node_bound()];
        let node_count = self.node_count();
        let hole_count = nodes.len() - node_count;
        let edges = &self.raw_edges()[..self.edge_bound()];
        SerStableGraph {
            nodes: Somes(node_count, nodes),
            node_holes: Holes(hole_count, nodes),
            edges: edges,
            edge_property: EdgeProperty::from(PhantomData::<Ty>),
        }
    }
}

impl<N, E, Ty, Ix> Serialize for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType + Serialize,
          N: Serialize,
          E: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        self.into_serializable().serialize(serializer)
    }
}

impl<'a, N, E, Ty, Ix> FromDeserialized for StableGraph<N, E, Ty, Ix>
    where Ix: IndexType,
          Ty: EdgeType,
{
    type Input = DeserStableGraph<N, E, Ix>;
    fn from_deserialized<E2>(input: Self::Input) -> Result<Self, E2>
        where E2: Error
    {
        let ty = PhantomData::<Ty>::from_deserialized(input.edge_property)?;
        let mut nodes = input.nodes;
        let node_holes = input.node_holes;
        let edges = input.edges;
        if edges.len() >= <Ix as IndexType>::max().index() {
            Err(invalid_length_err::<Ix, _>("edge", edges.len()))?
        }

        // insert Nones for each hole
        let mut offset = node_holes.len();
        let node_bound = node_holes.len() + nodes.len();
        for hole_pos in rev(node_holes) {
            offset -= 1;
            if hole_pos.index() >= node_bound {
                Err(invalid_node_err(hole_pos.index(), node_bound))?;
            }
            let insert_pos = hole_pos.index() - offset;
            nodes.insert(insert_pos, Node {
                weight: None,
                next: [EdgeIndex::end(); 2],
            });
        }

        if nodes.len() >= <Ix as IndexType>::max().index() {
            Err(invalid_length_err::<Ix, _>("node", nodes.len()))?
        }

        let node_bound = nodes.len();
        let mut sgr = StableGraph {
            g: Graph {
                nodes: nodes,
                edges: edges,
                ty: ty,
            },
            node_count: 0,
            edge_count: 0,
            free_edge: EdgeIndex::end(),
            free_node: NodeIndex::end(),
        };
        sgr.link_edges().map_err(|i| invalid_node_err(i.index(), node_bound))?;
        Ok(sgr)
    }
}

impl<'de, N, E, Ty, Ix> Deserialize<'de> for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType + Deserialize<'de>,
          N: Deserialize<'de>,
          E: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        Self::from_deserialized(DeserStableGraph::deserialize(deserializer)?)
    }
}

#[test]
fn test_from_deserialized_with_holes() {
    use graph::node_index;
    use stable_graph::StableUnGraph;
    use serde::de::value::Error as SerdeError;
    use itertools::assert_equal;

    let input = DeserStableGraph::<_, (), u32> {
        nodes: vec![
            Node {
                weight: Some(1),
                next: [EdgeIndex::end(); 2],
            },
            Node {
                weight: Some(4),
                next: [EdgeIndex::end(); 2],
            },
            Node {
                weight: Some(5),
                next: [EdgeIndex::end(); 2],
            },
        ],
        node_holes: vec![
            node_index(0),
            node_index(2),
            node_index(3),
            node_index(6),
        ],
        edges: vec![],
        edge_property: EdgeProperty::Undirected,
    };
    let graph = StableUnGraph::from_deserialized::<SerdeError>(input).unwrap();

    assert_eq!(graph.node_count(), 3);
    assert_equal(
        graph.raw_nodes().iter().map(|n| n.weight.as_ref().cloned()),
        vec![None, Some(1), None, None, Some(4), Some(5), None]);
}

<|endoftext|>


<commit_before>//! System Mutexes
//!
//! The Windows implementation of mutexes is a little odd and it may not be
//! immediately obvious what's going on. The primary oddness is that SRWLock is
//! used instead of CriticalSection, and this is done because:
//!
//! 1. SRWLock is several times faster than CriticalSection according to
//!    benchmarks performed on both Windows 8 and Windows 7.
//!
//! 2. CriticalSection allows recursive locking while SRWLock deadlocks. The
//!    Unix implementation deadlocks so consistency is preferred. See #19962 for
//!    more details.
//!
//! 3. While CriticalSection is fair and SRWLock is not, the current Rust policy
//!    is that there are no guarantees of fairness.

use crate::cell::UnsafeCell;
use crate::mem::MaybeUninit;
use crate::sys::c;

pub struct Mutex {
    srwlock: UnsafeCell<c::SRWLOCK>,
}

// Windows SRW Locks are movable (while not borrowed).
// ReentrantMutexes (in Inner) are not, but those are stored indirectly through
// a Box, so do not move when the Mutex it self is moved.
pub type MovableMutex = Mutex;

unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}

#[inline]
pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK {
    m.srwlock.get()
}

impl Mutex {
    pub const fn new() -> Mutex {
        Mutex { srwlock: UnsafeCell::new(c::SRWLOCK_INIT) }
    }
    #[inline]
    pub unsafe fn init(&mut self) {}

    #[inline]
    pub unsafe fn lock(&self) {
        c::AcquireSRWLockExclusive(raw(self));
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        c::TryAcquireSRWLockExclusive(raw(self)) != 0
    }

    #[inline]
    pub unsafe fn unlock(&self) {
        c::ReleaseSRWLockExclusive(raw(self));
    }

    #[inline]
    pub unsafe fn destroy(&self) {
        // SRWLock does not need to be destroyed.
    }
}

pub struct ReentrantMutex {
    inner: MaybeUninit<UnsafeCell<c::CRITICAL_SECTION>>,
}

unsafe impl Send for ReentrantMutex {}
unsafe impl Sync for ReentrantMutex {}

impl ReentrantMutex {
    pub const fn uninitialized() -> ReentrantMutex {
        ReentrantMutex { inner: MaybeUninit::uninit() }
    }

    pub unsafe fn init(&self) {
        c::InitializeCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
    }

    pub unsafe fn lock(&self) {
        c::EnterCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        c::TryEnterCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())) != 0
    }

    pub unsafe fn unlock(&self) {
        c::LeaveCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
    }

    pub unsafe fn destroy(&self) {
        c::DeleteCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
    }
}
<commit_msg>Rollup merge of #81896 - m-ou-se:oudated-comment, r=Mark-Simulacrum<commit_after>//! System Mutexes
//!
//! The Windows implementation of mutexes is a little odd and it may not be
//! immediately obvious what's going on. The primary oddness is that SRWLock is
//! used instead of CriticalSection, and this is done because:
//!
//! 1. SRWLock is several times faster than CriticalSection according to
//!    benchmarks performed on both Windows 8 and Windows 7.
//!
//! 2. CriticalSection allows recursive locking while SRWLock deadlocks. The
//!    Unix implementation deadlocks so consistency is preferred. See #19962 for
//!    more details.
//!
//! 3. While CriticalSection is fair and SRWLock is not, the current Rust policy
//!    is that there are no guarantees of fairness.

use crate::cell::UnsafeCell;
use crate::mem::MaybeUninit;
use crate::sys::c;

pub struct Mutex {
    srwlock: UnsafeCell<c::SRWLOCK>,
}

// Windows SRW Locks are movable (while not borrowed).
pub type MovableMutex = Mutex;

unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}

#[inline]
pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK {
    m.srwlock.get()
}

impl Mutex {
    pub const fn new() -> Mutex {
        Mutex { srwlock: UnsafeCell::new(c::SRWLOCK_INIT) }
    }
    #[inline]
    pub unsafe fn init(&mut self) {}

    #[inline]
    pub unsafe fn lock(&self) {
        c::AcquireSRWLockExclusive(raw(self));
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        c::TryAcquireSRWLockExclusive(raw(self)) != 0
    }

    #[inline]
    pub unsafe fn unlock(&self) {
        c::ReleaseSRWLockExclusive(raw(self));
    }

    #[inline]
    pub unsafe fn destroy(&self) {
        // SRWLock does not need to be destroyed.
    }
}

pub struct ReentrantMutex {
    inner: MaybeUninit<UnsafeCell<c::CRITICAL_SECTION>>,
}

unsafe impl Send for ReentrantMutex {}
unsafe impl Sync for ReentrantMutex {}

impl ReentrantMutex {
    pub const fn uninitialized() -> ReentrantMutex {
        ReentrantMutex { inner: MaybeUninit::uninit() }
    }

    pub unsafe fn init(&self) {
        c::InitializeCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
    }

    pub unsafe fn lock(&self) {
        c::EnterCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
    }

    #[inline]
    pub unsafe fn try_lock(&self) -> bool {
        c::TryEnterCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())) != 0
    }

    pub unsafe fn unlock(&self) {
        c::LeaveCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
    }

    pub unsafe fn destroy(&self) {
        c::DeleteCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr()));
    }
}
<|endoftext|>


<commit_before>/// `CompletionItem` describes a single completion variant in the editor pop-up.
/// It is basically a POD with various properties. To construct a
/// `CompletionItem`, use `new` method and the `Builder` struct.
#[derive(Debug)]
pub struct CompletionItem {
    label: String,
    lookup: Option<String>,
    snippet: Option<String>,
    /// Used only internally in test, to check only specific kind of completion.
    kind: CompletionKind,
}

pub enum InsertText {
    PlainText { text: String },
    Snippet { text: String },
}

#[derive(Debug, PartialEq, Eq)]
pub(crate) enum CompletionKind {
    /// Parser-based keyword completion.
    Keyword,
    /// Your usual "complete all valid identifiers".
    Reference,
    /// "Secret sauce" completions.
    Magic,
    Snippet,
    Unspecified,
}

impl CompletionItem {
    pub(crate) fn new(label: impl Into<String>) -> Builder {
        let label = label.into();
        Builder {
            label,
            lookup: None,
            snippet: None,
            kind: CompletionKind::Unspecified,
        }
    }
    /// What user sees in pop-up in the UI.
    pub fn label(&self) -> &str {
        &self.label
    }
    /// What string is used for filtering.
    pub fn lookup(&self) -> &str {
        self.lookup
            .as_ref()
            .map(|it| it.as_str())
            .unwrap_or(self.label())
    }
    /// What is inserted.
    pub fn insert_text(&self) -> InsertText {
        match &self.snippet {
            None => InsertText::PlainText {
                text: self.label.clone(),
            },
            Some(it) => InsertText::Snippet { text: it.clone() },
        }
    }
}

/// A helper to make `CompletionItem`s.
#[must_use]
pub(crate) struct Builder {
    label: String,
    lookup: Option<String>,
    snippet: Option<String>,
    kind: CompletionKind,
}

impl Builder {
    pub(crate) fn add_to(self, acc: &mut Completions) {
        acc.add(self.build())
    }

    pub(crate) fn build(self) -> CompletionItem {
        CompletionItem {
            label: self.label,
            lookup: self.lookup,
            snippet: self.snippet,
            kind: self.kind,
        }
    }
    pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder {
        self.lookup = Some(lookup.into());
        self
    }
    pub(crate) fn snippet(mut self, snippet: impl Into<String>) -> Builder {
        self.snippet = Some(snippet.into());
        self
    }
    pub(crate) fn kind(mut self, kind: CompletionKind) -> Builder {
        self.kind = kind;
        self
    }
}

impl Into<CompletionItem> for Builder {
    fn into(self) -> CompletionItem {
        self.build()
    }
}

/// Represents an in-progress set of completions being built.
#[derive(Debug, Default)]
pub(crate) struct Completions {
    buf: Vec<CompletionItem>,
}

impl Completions {
    pub(crate) fn add(&mut self, item: impl Into<CompletionItem>) {
        self.buf.push(item.into())
    }
    pub(crate) fn add_all<I>(&mut self, items: I)
    where
        I: IntoIterator,
        I::Item: Into<CompletionItem>,
    {
        items.into_iter().for_each(|item| self.add(item.into()))
    }

    #[cfg(test)]
    pub(crate) fn assert_match(&self, expected: &str, kind: CompletionKind) {
        let expected = normalize(expected);
        let actual = self.debug_render(kind);
        test_utils::assert_eq_text!(expected.as_str(), actual.as_str(),);

        /// Normalize the textual representation of `Completions`:
        /// replace `;` with newlines, normalize whitespace
        fn normalize(expected: &str) -> String {
            use ra_syntax::{tokenize, TextUnit, TextRange, SyntaxKind::SEMI};
            let mut res = String::new();
            for line in expected.trim().lines() {
                let line = line.trim();
                let mut start_offset: TextUnit = 0.into();
                // Yep, we use rust tokenize in completion tests :-)
                for token in tokenize(line) {
                    let range = TextRange::offset_len(start_offset, token.len);
                    start_offset += token.len;
                    if token.kind == SEMI {
                        res.push('\n');
                    } else {
                        res.push_str(&line[range]);
                    }
                }

                res.push('\n');
            }
            res
        }
    }

    #[cfg(test)]
    fn debug_render(&self, kind: CompletionKind) -> String {
        let mut res = String::new();
        for c in self.buf.iter() {
            if c.kind == kind {
                if let Some(lookup) = &c.lookup {
                    res.push_str(lookup);
                    res.push_str(&format!(" {:?}", c.label));
                } else {
                    res.push_str(&c.label);
                }
                if let Some(snippet) = &c.snippet {
                    res.push_str(&format!(" {:?}", snippet));
                }
                res.push('\n');
            }
        }
        res
    }
}

impl Into<Vec<CompletionItem>> for Completions {
    fn into(self) -> Vec<CompletionItem> {
        self.buf
    }
}
<commit_msg>rename completion kind<commit_after>/// `CompletionItem` describes a single completion variant in the editor pop-up.
/// It is basically a POD with various properties. To construct a
/// `CompletionItem`, use `new` method and the `Builder` struct.
#[derive(Debug)]
pub struct CompletionItem {
    label: String,
    lookup: Option<String>,
    snippet: Option<String>,
    /// Used only internally in test, to check only specific kind of completion.
    completion_kind: CompletionKind,
}

pub enum InsertText {
    PlainText { text: String },
    Snippet { text: String },
}

#[derive(Debug, PartialEq, Eq)]
pub(crate) enum CompletionKind {
    /// Parser-based keyword completion.
    Keyword,
    /// Your usual "complete all valid identifiers".
    Reference,
    /// "Secret sauce" completions.
    Magic,
    Snippet,
    Unspecified,
}

impl CompletionItem {
    pub(crate) fn new(label: impl Into<String>) -> Builder {
        let label = label.into();
        Builder {
            label,
            lookup: None,
            snippet: None,
            completion_kind: CompletionKind::Unspecified,
        }
    }
    /// What user sees in pop-up in the UI.
    pub fn label(&self) -> &str {
        &self.label
    }
    /// What string is used for filtering.
    pub fn lookup(&self) -> &str {
        self.lookup
            .as_ref()
            .map(|it| it.as_str())
            .unwrap_or(self.label())
    }
    /// What is inserted.
    pub fn insert_text(&self) -> InsertText {
        match &self.snippet {
            None => InsertText::PlainText {
                text: self.label.clone(),
            },
            Some(it) => InsertText::Snippet { text: it.clone() },
        }
    }
}

/// A helper to make `CompletionItem`s.
#[must_use]
pub(crate) struct Builder {
    label: String,
    lookup: Option<String>,
    snippet: Option<String>,
    completion_kind: CompletionKind,
}

impl Builder {
    pub(crate) fn add_to(self, acc: &mut Completions) {
        acc.add(self.build())
    }

    pub(crate) fn build(self) -> CompletionItem {
        CompletionItem {
            label: self.label,
            lookup: self.lookup,
            snippet: self.snippet,
            completion_kind: self.completion_kind,
        }
    }
    pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder {
        self.lookup = Some(lookup.into());
        self
    }
    pub(crate) fn snippet(mut self, snippet: impl Into<String>) -> Builder {
        self.snippet = Some(snippet.into());
        self
    }
    pub(crate) fn kind(mut self, kind: CompletionKind) -> Builder {
        self.completion_kind = kind;
        self
    }
}

impl Into<CompletionItem> for Builder {
    fn into(self) -> CompletionItem {
        self.build()
    }
}

/// Represents an in-progress set of completions being built.
#[derive(Debug, Default)]
pub(crate) struct Completions {
    buf: Vec<CompletionItem>,
}

impl Completions {
    pub(crate) fn add(&mut self, item: impl Into<CompletionItem>) {
        self.buf.push(item.into())
    }
    pub(crate) fn add_all<I>(&mut self, items: I)
    where
        I: IntoIterator,
        I::Item: Into<CompletionItem>,
    {
        items.into_iter().for_each(|item| self.add(item.into()))
    }

    #[cfg(test)]
    pub(crate) fn assert_match(&self, expected: &str, kind: CompletionKind) {
        let expected = normalize(expected);
        let actual = self.debug_render(kind);
        test_utils::assert_eq_text!(expected.as_str(), actual.as_str(),);

        /// Normalize the textual representation of `Completions`:
        /// replace `;` with newlines, normalize whitespace
        fn normalize(expected: &str) -> String {
            use ra_syntax::{tokenize, TextUnit, TextRange, SyntaxKind::SEMI};
            let mut res = String::new();
            for line in expected.trim().lines() {
                let line = line.trim();
                let mut start_offset: TextUnit = 0.into();
                // Yep, we use rust tokenize in completion tests :-)
                for token in tokenize(line) {
                    let range = TextRange::offset_len(start_offset, token.len);
                    start_offset += token.len;
                    if token.kind == SEMI {
                        res.push('\n');
                    } else {
                        res.push_str(&line[range]);
                    }
                }

                res.push('\n');
            }
            res
        }
    }

    #[cfg(test)]
    fn debug_render(&self, kind: CompletionKind) -> String {
        let mut res = String::new();
        for c in self.buf.iter() {
            if c.completion_kind == kind {
                if let Some(lookup) = &c.lookup {
                    res.push_str(lookup);
                    res.push_str(&format!(" {:?}", c.label));
                } else {
                    res.push_str(&c.label);
                }
                if let Some(snippet) = &c.snippet {
                    res.push_str(&format!(" {:?}", snippet));
                }
                res.push('\n');
            }
        }
        res
    }
}

impl Into<Vec<CompletionItem>> for Completions {
    fn into(self) -> Vec<CompletionItem> {
        self.buf
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

use source::{Source, SourceError};

use handlebars::Handlebars;

pub struct DirectorySource {
    pub prefix: PathBuf,
    pub suffix: &'static str,
}

impl DirectorySource {
    pub fn new<P>(prefix: P, suffix: &'static str) -> DirectorySource
        where P: Into<PathBuf>
    {
        DirectorySource {
            prefix: prefix.into(),
            suffix: suffix,
        }
    }
}

// /// return false when file name not satisfied
// fn filter_file(entry: &DirEntry, suffix: &OsStr) -> bool {
//     let path = entry.path();

//     // ignore hidden files, emacs buffers and files with wrong suffix
//     !path.is_file() ||
//     path.file_name()
//         .map(|s| {
//                  let ds = s.to_string_lossy();
//                  ds.starts_with(".") || ds.starts_with("#") ||
//                  !ds.ends_with(suffix.to_string_lossy().as_ref())
//              })
//         .unwrap_or(true)
// }

impl Source for DirectorySource {
    fn load(&self, reg: &mut Handlebars) -> Result<(), SourceError> {
        reg.register_templates_directory(self.suffix, &self.prefix)
            .map_err(SourceError::from)
    }
}
<commit_msg>(chore) remove unused code<commit_after>use std::path::PathBuf;

use source::{Source, SourceError};

use handlebars::Handlebars;

pub struct DirectorySource {
    pub prefix: PathBuf,
    pub suffix: &'static str,
}

impl DirectorySource {
    pub fn new<P>(prefix: P, suffix: &'static str) -> DirectorySource
        where P: Into<PathBuf>
    {
        DirectorySource {
            prefix: prefix.into(),
            suffix: suffix,
        }
    }
}

impl Source for DirectorySource {
    fn load(&self, reg: &mut Handlebars) -> Result<(), SourceError> {
        reg.register_templates_directory(self.suffix, &self.prefix)
            .map_err(SourceError::from)
    }
}
<|endoftext|>


<commit_before>use bot::LalafellBot;
use listeners::ReceivesEvents;
use discord::model::{Event, Message};
use discord::builders::EmbedBuilder;

use std::sync::Arc;

pub struct PollTagger {
  bot: Arc<LalafellBot>
}

impl PollTagger {
  pub fn new(bot: Arc<LalafellBot>) -> Self {
    PollTagger { bot: bot }
  }

  fn tag_poll(&self, message: &Message) {
    let current_user = match self.bot.discord.get_current_user() {
      Ok(c) => c,
      Err(e) => {
        warn!("couldn't get current user: {}", e);
        return;
      }
    };
    if message.embeds.len() != 1 && message.author.id != current_user.id {
      return;
    }
    let footer = match message.embeds[0].get("footer").and_then(|f| f.get("text")).and_then(|t| t.as_str()) {
      Some(f) => f,
      None => return
    };
    let title = match message.embeds[0].get("title").and_then(|t| t.as_str()) {
      Some(t) => t,
      None => return
    };
    let description = match message.embeds[0].get("description").and_then(|d| d.as_str()) {
      Some(d) => d,
      None => return
    };
    if footer != "Loading poll ID..." {
      return;
    }
    self.bot.discord.edit_embed(message.channel_id, message.id, |e: EmbedBuilder| e
      .title(title)
      .description(description)
      .footer(|f| f.text(&format!("{}", message.id.0))))
      .ok();
  }
}

impl ReceivesEvents for PollTagger {
  fn receive(&self, event: &Event) {
    match *event {
      Event::MessageCreate(ref msg) => self.tag_poll(msg),
      _ => {}
    }
  }
}
<commit_msg>refactor: use if let instead of match<commit_after>use bot::LalafellBot;
use listeners::ReceivesEvents;
use discord::model::{Event, Message};
use discord::builders::EmbedBuilder;

use std::sync::Arc;

pub struct PollTagger {
  bot: Arc<LalafellBot>
}

impl PollTagger {
  pub fn new(bot: Arc<LalafellBot>) -> Self {
    PollTagger { bot: bot }
  }

  fn tag_poll(&self, message: &Message) {
    let current_user = match self.bot.discord.get_current_user() {
      Ok(c) => c,
      Err(e) => {
        warn!("couldn't get current user: {}", e);
        return;
      }
    };
    if message.embeds.len() != 1 && message.author.id != current_user.id {
      return;
    }
    let footer = match message.embeds[0].get("footer").and_then(|f| f.get("text")).and_then(|t| t.as_str()) {
      Some(f) => f,
      None => return
    };
    let title = match message.embeds[0].get("title").and_then(|t| t.as_str()) {
      Some(t) => t,
      None => return
    };
    let description = match message.embeds[0].get("description").and_then(|d| d.as_str()) {
      Some(d) => d,
      None => return
    };
    if footer != "Loading poll ID..." {
      return;
    }
    self.bot.discord.edit_embed(message.channel_id, message.id, |e: EmbedBuilder| e
      .title(title)
      .description(description)
      .footer(|f| f.text(&format!("{}", message.id.0))))
      .ok();
  }
}

impl ReceivesEvents for PollTagger {
  fn receive(&self, event: &Event) {
    if let Event::MessageCreate(ref msg) = *event {
      self.tag_poll(msg);
    }
  }
}
<|endoftext|>


<commit_before>extern mod std;

#[test]
fn test_tokenize() {
    assert tokenize( ~"(1 2 3)" ) == ~[~"(", ~"1", ~"2", ~"3", ~")"];
}

#[test]
fn test_tokenize_empty() {
    assert tokenize( ~"" ) == ~[];
}

#[test]
fn test_tokenize_no_spaces() {
    assert tokenize( ~"one" ) == ~[~"one"];
}

#[test]
fn test_pad_parentheses() {
    assert pad_parentheses( ~"(1 2 3)" ) == ~" ( 1 2 3 ) "
}

#[test]
fn test_pad_parentheses_empty() {
    assert pad_parentheses( ~"" ) == ~""
}

#[test]
fn test_pad_parentheses_one() {
    assert pad_parentheses( ~"(" ) == ~" ( ";
    assert pad_parentheses( ~")" ) == ~" ) ";
}

fn pad_parentheses( input:&str ) -> ~str {
    str::replace(str::replace(input, ")", " ) "), "(", " ( ")
}

fn tokenize( input:&str ) -> ~[~str] {
    str::words(pad_parentheses(input))
}

#[test]
fn test_that_atom_can_read_a_symbol() {
    match atom(~"hello") {
        Symbol(~"hello") => (),
            _ => fail
    }
}

#[test]
fn test_that_atom_can_read_an_int() {
    match atom(~"10") {
        Int(10) => (),
            _ => fail
    }
}

#[test]
fn test_that_atom_can_read_a_float() {
    match atom(~"10.1") {
        Float(10.1) => (),
            _ => fail
    }
}

fn atom( input:~str ) -> Expression {
    match int::from_str(input) {
        Some(number) => Int(number),
        None => match float::from_str(input) {
            Some(number) => Float(number),
            None => Symbol(input)
        }
    }
}

#[test]
fn test_that_parse_can_read_an_atom() {
    let atom = parse( ~[~"12"] );
    match atom {
        Int(12) => (),
            _ => fail
    }
}

#[test]
fn test_that_parse_can_read_a_list() {
    let list = parse( ~[ ~"(", ~"1", ~")" ] );
    match list {
        List([Int(1)]) => (),
            _ => fail ~"not a list"
    }
}

#[test]
fn test_that_parse_can_read_a_nested_list() {
    let list = parse( ~[ ~"(", ~"1", ~"(", ~"2", ~")", ~"3", ~")" ] );
    match list {
        List([Int(1), List([Int(2)]), Int(3)]) => (),
        _ => fail
    }
}

fn parse( tokens:~[~str] ) -> Expression {
    fn subexpression( tokens:~[~str] ) -> (Expression, ~[~str]) {
        let token = tokens.head();
        match token {
            ~"(" => {
                let mut accumulator:~[Expression] = ~[];
                let mut remainder = tokens.tail();
                while remainder.len() > 0 && remainder.head() != ~")" {
                    let (expr, new_remainder) = subexpression( remainder );
                    accumulator += [expr];
                    remainder = new_remainder
                }
                (List(accumulator), remainder.tail())
            }
            ~")" => fail,
                _ => (atom(token), tokens.tail())
        }
    }
    let (expression, remainder) = subexpression( tokens );
    expression
}

enum Expression {
    Int(int),
    Float(float),
    Symbol(~str),
    List(~[Expression])
}

fn stringify_expression( expression:Expression ) -> ~str {
    match expression {
        Int(number) => { fmt!("%d", number) }
        Float(number) => {
            if number == (number as int) as float {
                fmt!("%.1f", number)
            } else {
                fmt!("%f", number)
            }
        }
        Symbol(string) => { string }
        List(expressions) => {
            let strings = expressions.map( | &expr | {stringify_expression(expr)} );
            ~"(" + strings.foldl(~"", |&x, &y| { x + ~" " + y } ).trim() + ~")"
        }
    }
}

fn main() {
    io::println(stringify_expression( parse( tokenize( "(1 2 3 (1 2 3))" ) ) ));
    io::println(stringify_expression( parse( tokenize( "((1 2) 3 (1 2 3))" ) ) ));
    let blah:Expression = List(~[Int(1), List(~[Float(1.0), Symbol(~"xyz")])]);
    io::println(stringify_expression(blah));
    io::println( "(begin 1 2)" )
}
<commit_msg>Silence unused variable warning<commit_after>extern mod std;

#[test]
fn test_tokenize() {
    assert tokenize( ~"(1 2 3)" ) == ~[~"(", ~"1", ~"2", ~"3", ~")"];
}

#[test]
fn test_tokenize_empty() {
    assert tokenize( ~"" ) == ~[];
}

#[test]
fn test_tokenize_no_spaces() {
    assert tokenize( ~"one" ) == ~[~"one"];
}

#[test]
fn test_pad_parentheses() {
    assert pad_parentheses( ~"(1 2 3)" ) == ~" ( 1 2 3 ) "
}

#[test]
fn test_pad_parentheses_empty() {
    assert pad_parentheses( ~"" ) == ~""
}

#[test]
fn test_pad_parentheses_one() {
    assert pad_parentheses( ~"(" ) == ~" ( ";
    assert pad_parentheses( ~")" ) == ~" ) ";
}

fn pad_parentheses( input:&str ) -> ~str {
    str::replace(str::replace(input, ")", " ) "), "(", " ( ")
}

fn tokenize( input:&str ) -> ~[~str] {
    str::words(pad_parentheses(input))
}

#[test]
fn test_that_atom_can_read_a_symbol() {
    match atom(~"hello") {
        Symbol(~"hello") => (),
            _ => fail
    }
}

#[test]
fn test_that_atom_can_read_an_int() {
    match atom(~"10") {
        Int(10) => (),
            _ => fail
    }
}

#[test]
fn test_that_atom_can_read_a_float() {
    match atom(~"10.1") {
        Float(10.1) => (),
            _ => fail
    }
}

fn atom( input:~str ) -> Expression {
    match int::from_str(input) {
        Some(number) => Int(number),
        None => match float::from_str(input) {
            Some(number) => Float(number),
            None => Symbol(input)
        }
    }
}

#[test]
fn test_that_parse_can_read_an_atom() {
    let atom = parse( ~[~"12"] );
    match atom {
        Int(12) => (),
            _ => fail
    }
}

#[test]
fn test_that_parse_can_read_a_list() {
    let list = parse( ~[ ~"(", ~"1", ~")" ] );
    match list {
        List([Int(1)]) => (),
            _ => fail ~"not a list"
    }
}

#[test]
fn test_that_parse_can_read_a_nested_list() {
    let list = parse( ~[ ~"(", ~"1", ~"(", ~"2", ~")", ~"3", ~")" ] );
    match list {
        List([Int(1), List([Int(2)]), Int(3)]) => (),
        _ => fail
    }
}

fn parse( tokens:~[~str] ) -> Expression {
    fn subexpression( tokens:~[~str] ) -> (Expression, ~[~str]) {
        let token = tokens.head();
        match token {
            ~"(" => {
                let mut accumulator:~[Expression] = ~[];
                let mut remainder = tokens.tail();
                while remainder.len() > 0 && remainder.head() != ~")" {
                    let (expr, new_remainder) = subexpression( remainder );
                    accumulator += [expr];
                    remainder = new_remainder
                }
                (List(accumulator), remainder.tail())
            }
            ~")" => fail,
                _ => (atom(token), tokens.tail())
        }
    }
    let (expression, _remainder) = subexpression( tokens );
    expression
}

enum Expression {
    Int(int),
    Float(float),
    Symbol(~str),
    List(~[Expression])
}

fn stringify_expression( expression:Expression ) -> ~str {
    match expression {
        Int(number) => { fmt!("%d", number) }
        Float(number) => {
            if number == (number as int) as float {
                fmt!("%.1f", number)
            } else {
                fmt!("%f", number)
            }
        }
        Symbol(string) => { string }
        List(expressions) => {
            let strings = expressions.map( | &expr | {stringify_expression(expr)} );
            ~"(" + strings.foldl(~"", |&x, &y| { x + ~" " + y } ).trim() + ~")"
        }
    }
}

fn main() {
    io::println(stringify_expression( parse( tokenize( "(1 2 3 (1 2 3))" ) ) ));
    io::println(stringify_expression( parse( tokenize( "((1 2) 3 (1 2 3))" ) ) ));
    let blah:Expression = List(~[Int(1), List(~[Float(1.0), Symbol(~"xyz")])]);
    io::println(stringify_expression(blah));
    io::println( "(begin 1 2)" )
}
<|endoftext|>


<commit_before>#![feature(phase)]
#[phase(syntax, link)] extern crate log;
extern crate collections;
extern crate sync;
extern crate rand;
use collections::HashMap;
use std::io::{File, Open, Read, Write, TempDir};
use std::num::Zero;
use std::comm::{Data, Empty, Disconnected};
use sync::{Arc, RWLock};
use sync::Future;
use rand::task_rng;
use rand::distributions::{IndependentSample, Range};
use rand::distributions::range::SampleRange;
use native::io::file;
use native::io::file::FileDesc;
use std::rt::rtio::RtioFileStream;

static PAGE_SIZE: uint = 4 * 1024;
/* how much of the page_id should be reserved for pages */
static PAGE_BITS: uint = 4;

struct BufferManager {
	size: uint,
	entries: HashMap<u64, BufferEntry>,
	path: Path,
}

struct BufferEntry {
	frame: Arc<RWLock<BufferFrame>>,
}

#[deriving(Eq)]
enum Status {
	Free,
	Fixed(uint),
}

struct BufferFrame {
	page_id: u64,
	data: Vec<u8>,
	fixed: Status,
}

/* Destructor trait implementation */
impl Drop for BufferManager {
	fn drop(&mut self) {
		// TODO
		info!("Dropping");
	}
}

impl BufferManager {
	pub fn new(size: uint, path: Path) -> BufferManager {
		let h = HashMap::with_capacity(size);
		BufferManager {size: size, entries: h, path: path}
	}

	fn open_or_create(&self, page_id: u64) -> FileDesc {
		let file_path = self.path.join(page_id.to_str());
		match file::open(&file_path.to_c_str(), Open, Read) {
			Ok(f) => return f,
			Err(_) => self.create(&file_path),
		};
		match file::open(&file_path.to_c_str(), Open, Read) {
			Ok(f) => f,
			Err(e) => fail!("Failed reopening written file: {}", e),
		}
	}

	fn create(&self, page_id: u64) {
		let path = self.path.join(page_id.to_str());
		match file::open(&path.to_c_str(), Open, Write) {
			Ok(mut f) => {
				match f.pwrite([0_u8, ..PAGE_SIZE], 0) {
					Ok(_) => (),
					//Err(e) => fail!("Failed pwriting to file {}: {}", &path.to_c_str().as_str(), e),
					// in this case, err means everything is fine, since there is a bug in Rust' libnative
					Err(e) => (),
				};
			},
			Err(e) => fail!("Failed opening file for write: {}", e),
		};
	}

	/*
	 * returns true if page could be loaded
	 */
	fn load_page(&mut self, page_id: u64) -> bool {
		if self.entries.len() == self.size {
			if !self.evict_page() {
				return false;
			}
		}

		let mut file_handle = self.open_or_create(page_id);
		let content = match file_handle.read_exact(PAGE_SIZE) {
			Ok(c) => Vec::from_slice(c),
			Err(e) => fail!("Couldn't read from page: {}", e),
		};

		let frame = BufferFrame {data: content, page_id: page_id, fixed: Free};
		let entry = BufferEntry {frame: Arc::new(RWLock::new(frame))};
		self.entries.insert(page_id, entry);
		true
	}

	/*
	 * return false if no page could be evicted
	 */
	fn evict_page(&mut self) -> bool {
		let random_key = {
			let mut free_keys = self.entries.iter().filter_map(|e| {
				// iterate over entries, check if they are free
				// and return the keys of the free entries
				let (k,v) = e;
				let frame = v.frame.read();
				if frame.fixed == Free {
					Some(k)
				} else {
					None
				}
			});
			// pick a random key
			sample(&mut free_keys).map(|v| v.clone())
		};

		match random_key {
			None => false,
			Some(key) => self.entries.remove(&key),
		}
	}

	pub fn fix_page(&mut self, page_id: u64) -> Option<Arc<RWLock<BufferFrame>>> {
		if !self.entries.contains_key(&page_id) {
			if !self.load_page(page_id) {
				return None;
			}
		}
		let entry = self.entries.get(&page_id);
		{
			let mut f = entry.frame.write();
			f.fixed = match f.fixed {
				Free => Fixed(1),
				Fixed(n) => Fixed(n+1),
			};
		}
		// Arcs can be cloned and they will all point to the same RWLock
		Some(entry.frame.clone())
	}

	pub fn unfix_page(&mut self, frame: Arc<RWLock<BufferFrame>>, is_dirty: bool) {
		{
			let mut frame = frame.write();
			frame.fixed = match frame.fixed {
				Fixed(1) => Free,
				Fixed(n) => Fixed(n-1),
				Free => fail!("Unfixing unfixed page"),
			};
		}

		if !is_dirty {
			return;
		}
		let frame = frame.read();
		if frame.fixed == Free {
			info!("writing back page \\#{}", frame.page_id);
			self.write_page(frame.page_id, frame.get_data());
		}
	}

	fn write_page(&mut self, page_id: u64, data: &[u8]) {
		let file_path = self.path.join(page_id.to_str());
		let mut handle = match File::open_mode(&file_path, Open, Write) {
			Ok(handle) => handle,
			Err(e) => fail!("Opening file for writing failed: {}", e),
		};

		match handle.write(data) {
			Ok(_) => (),
			Err(e) => fail!("Writing to file failed: {}", e),
		};
	}
}

/*
 * A buffer frame, the unit that gets the data
 */
impl BufferFrame {
	/*
	 * get_mut_data returns a borrowed reference to a mutable slice to the vector
	 * contents.
	 */
	pub fn get_mut_data<'a>(&'a mut self) -> &'a mut [u8] {
		self.data.as_mut_slice()
	}
	pub fn get_data<'a>(&'a self) -> &'a [u8] {
		self.data.as_slice()
	}
}

fn sample<'a, T, I:Iterator<T>>(from: &'a mut I) -> Option<T> {
	let from: ~[T] = from.collect();
	let l = from.len();
	if l == 0 {
		return None;
	}
	let index = randrange(l);
	Some(from[index])
}

fn randrange<X: SampleRange + Ord + Zero>(high: X) -> X {
	let between: Range<X> = Range::new(Zero::zero(), high);
	let mut rng = rand::task_rng();
	between.ind_sample(&mut rng)
}

fn split_segment(num: u64) -> (u64, u64) {
	let high = num >> (64 - PAGE_BITS);
	let low = num & ((1 << PAGE_BITS) - 1);
	(high, low)
}

#[test]
fn test_create() {
	let dir = match TempDir::new("buffermanager") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	let mut bm = BufferManager::new(16, dir.path().clone());
	let pageref = match bm.fix_page(42) {
		Some(p) => p,
		None => fail!("Getting page failed"),
	};
	{
		let mut page = pageref.write();
		let data = page.get_mut_data();
		data[0] = 42;
	}
	bm.unfix_page(pageref, true);
}

#[test]
fn test_threads() {
	use rand::random;
	use std::task::spawn;
	use std::os;

	let pages_in_ram: uint = match os::getenv("PAGES_IN_RAM") {
		Some(v) => from_str(v).expect("PAGES_IN_RAM expects integer"),
		None => 1,
	};
	let pages_on_disk: u64 = match os::getenv("PAGES_ON_DISK") {
		Some(v) => from_str(v).expect("PAGES_ON_DISK expects integer"),
		None => 20,
	};
	let thread_count: uint = match os::getenv("THREADS") {
		Some(v) => from_str(v).expect("THREADS expects integer"),
		None => 3,
	};
	let dir = match TempDir::new("buffermanager") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};
	let p = dir.path();
	let p = Path::new(".");

	let mut buffermanager = BufferManager::new(pages_in_ram, p.clone());

	for i in range(0, pages_on_disk) {
		let bf = match buffermanager.fix_page(i) {
			Some(frame) => frame,
			None => fail!("Couldn't fix page {}", i),
		};
		{
			let mut lock = bf.write();
			lock.get_mut_data()[0] = 0;
		}
		buffermanager.unfix_page(bf, true);
	}
	let bm = Arc::new(RWLock::new(buffermanager));

	// start scan thread
	let (tx, rx) = channel();
	let bm_scan = bm.clone();
	let mut scan = Future::spawn(proc() {
		let mut counters = Vec::from_elem(pages_on_disk as uint, 0_u8);
		loop {
			info!("Running scan thread...");
			match rx.try_recv() {
				Empty => {
					let page_number = randrange(pages_on_disk);
					let mut bm = bm_scan.write();
					let bf = match bm.fix_page(page_number) {
						Some(frame) => frame,
						None => fail!("Couldn't scan/fix page"),
					};
					let current_val = {
						let lock = bf.read();
						lock.get_data()[0]
					};
					bm.unfix_page(bf, false);
					bm.downgrade();
					// check if the value is going up
					assert!(&current_val >= counters.get(page_number as uint));
					// set to the new value
					let v = counters.get_mut(page_number as uint);
					*v = current_val;

				},
				/*
				 * terminate on both disconnect and when any kind of
				 * data arrives
				 */
				Disconnected => break,
				Data(_) => break,
			};
		}
	});

	// start read/write threads
	let mut rw_threads: Vec<Future<int>> = Vec::new();
	for _ in range(0, thread_count) {
		let bm = bm.clone();
		rw_threads.push(Future::spawn(proc() {
			let is_write = random::<bool>();
			info!("Creating new {} task",
				if is_write {"write"} else {"read"});
			let page_number = randrange(pages_on_disk);
			let mut bm = bm.write();
			if is_write {
				let bf = match bm.fix_page(page_number) {
					Some(frame) => frame,
					None => fail!("Couldn't fix page"),
				};
				{
					let mut lock = bf.write();
					let data = lock.get_mut_data();
					data[0] = data[0] + 1;
					info!("Wrote to page {}", page_number);
					debug!("data: {}", Vec::from_slice(data));
				}
				bm.unfix_page(bf, is_write);
			} else {
				let bf = match bm.fix_page(page_number) {
					Some(frame) => frame,
					None => fail!("Couldn't fix page"),
				};
				bm.unfix_page(bf, is_write);
			}
			// return whether we wrote (1) or read (0) as future
			if is_write {1} else {0}
		}));
	}

	// Rust does not have join, but we can wait on Futures which does the same
	let total_count = rw_threads.mut_iter().fold(0, |acc, val| acc + val.get());
	info!("Total count in RAM: {}", total_count);

	// terminate the scan thread and wait until it has completed
	tx.send("terminate");
	scan.get();

	// re-open the pages and check whether all numbers got saved
	let mut bm = BufferManager::new(pages_in_ram, p.clone());
	let mut total_count_on_disk = 0;
	for i in range(0, pages_on_disk) {
		let bf = match bm.fix_page(i) {
			Some(frame) => frame,
			None => fail!("Couldn't fix page")
		};
		let value = {
			let lock = bf.read();
			let data = lock.get_data();
			data[0]
		};
		bm.unfix_page(bf, false);
		// cast up from u8 to int
		total_count_on_disk += value as int;
	}
	info!("Total count on disk: {}", total_count_on_disk);
	assert_eq!(total_count, total_count_on_disk);
}
<commit_msg>Reading and writing with pread works now<commit_after>#![feature(phase)]
#[phase(syntax, link)] extern crate log;
extern crate collections;
extern crate sync;
extern crate rand;
use collections::HashMap;
use std::io::{Open, Read, Write, TempDir};
use std::num::Zero;
use std::comm::{Data, Empty, Disconnected};
use sync::{Arc, RWLock};
use sync::Future;
use rand::task_rng;
use rand::distributions::{IndependentSample, Range};
use rand::distributions::range::SampleRange;
use native::io::file;
use native::io::file::FileDesc;
use std::rt::rtio::RtioFileStream;

static PAGE_SIZE: uint = 4 * 1024;
/* how much of the page_id should be reserved for pages */
static PAGE_BITS: uint = 4;

struct BufferManager {
	size: uint,
	entries: HashMap<u64, BufferEntry>,
	path: Path,
}

struct BufferEntry {
	frame: Arc<RWLock<BufferFrame>>,
}

#[deriving(Eq)]
enum Status {
	Free,
	Fixed(uint),
}

struct BufferFrame {
	page_id: u64,
	data: Vec<u8>,
	fixed: Status,
}

/* Destructor trait implementation */
impl Drop for BufferManager {
	fn drop(&mut self) {
		// TODO
		info!("Dropping");
	}
}

impl BufferManager {
	pub fn new(size: uint, path: Path) -> BufferManager {
		let h = HashMap::with_capacity(size);
		BufferManager {size: size, entries: h, path: path}
	}

	fn open_or_create(&self, page_id: u64) -> FileDesc {
		let (segment, _) = split_segment(page_id);
		let file_path = self.path.join(segment.to_str());
		match file::open(&file_path.to_c_str(), Open, Read) {
			Ok(f) => return f,
			Err(_) => self.create(page_id),
		};
		match file::open(&file_path.to_c_str(), Open, Read) {
			Ok(f) => f,
			Err(e) => fail!("Failed reopening written file: {}", e),
		}
	}

	fn create(&self, page_id: u64) {
		let (segment, offset) = split_segment(page_id);
		let path = self.path.join(segment.to_str());

		match file::open(&path.to_c_str(), Open, Write) {
			Ok(mut f) => {
				match f.pwrite([0_u8, ..PAGE_SIZE], offset * PAGE_SIZE as u64) {
					Ok(_) => (),
					//Err(e) => fail!("Failed pwriting to file {}: {}", &path.to_c_str().as_str(), e),
					// in this case, err means everything is fine, since there is a bug in Rust' libnative
					Err(_) => (),
				};
			},
			Err(e) => fail!("Failed opening file for write: {}", e),
		};
	}

	/*
	 * returns true if page could be loaded
	 */
	fn load_page(&mut self, page_id: u64) -> bool {
		if self.entries.len() == self.size {
			if !self.evict_page() {
				return false;
			}
		}
		let (_, offset) = split_segment(page_id);

		let mut file_handle = self.open_or_create(page_id);
		let mut buf = [0_u8, ..PAGE_SIZE];
		let content = match file_handle.pread(buf, offset * PAGE_SIZE as u64) {
			Ok(_) => {
				Vec::from_slice(buf)
				/*
				if n == PAGE_SIZE as int {
					Vec::from_slice(buf)
				} else {
					fail!("pread failed: wanted {}, got {}",
						PAGE_SIZE, n)
				}*/
			},
			Err(e) => fail!("Couldn't read from page: {}", e),
		};

		let frame = BufferFrame {data: content, page_id: page_id, fixed: Free};
		let entry = BufferEntry {frame: Arc::new(RWLock::new(frame))};
		self.entries.insert(page_id, entry);
		true
	}

	/*
	 * return false if no page could be evicted
	 */
	fn evict_page(&mut self) -> bool {
		let random_key = {
			let mut free_keys = self.entries.iter().filter_map(|e| {
				// iterate over entries, check if they are free
				// and return the keys of the free entries
				let (k,v) = e;
				let frame = v.frame.read();
				if frame.fixed == Free {
					Some(k)
				} else {
					None
				}
			});
			// pick a random key
			sample(&mut free_keys).map(|v| v.clone())
		};

		match random_key {
			None => false,
			Some(key) => self.entries.remove(&key),
		}
	}

	pub fn fix_page(&mut self, page_id: u64) -> Option<Arc<RWLock<BufferFrame>>> {
		if !self.entries.contains_key(&page_id) {
			if !self.load_page(page_id) {
				return None;
			}
		}
		let entry = self.entries.get(&page_id);
		{
			let mut f = entry.frame.write();
			f.fixed = match f.fixed {
				Free => Fixed(1),
				Fixed(n) => Fixed(n+1),
			};
		}
		// Arcs can be cloned and they will all point to the same RWLock
		Some(entry.frame.clone())
	}

	pub fn unfix_page(&mut self, frame: Arc<RWLock<BufferFrame>>, is_dirty: bool) {
		{
			let mut frame = frame.write();
			frame.fixed = match frame.fixed {
				Fixed(1) => Free,
				Fixed(n) => Fixed(n-1),
				Free => fail!("Unfixing unfixed page"),
			};
		}

		if !is_dirty {
			return;
		}
		let frame = frame.read();
		if frame.fixed == Free {
			//info!("writing back page \\#{}", frame.page_id);
			self.write_page(frame.page_id, frame.get_data());
		}
	}

	fn write_page(&mut self, page_id: u64, data: &[u8]) {
		let (segment, offset) = split_segment(page_id);
		let file_path = self.path.join(segment.to_str());
		let mut handle = match file::open(&file_path.to_c_str(), Open, Write) {
			Ok(handle) => handle,
			Err(e) => fail!("Opening file for writing failed: {}", e),
		};

		println!("Writing to segment {}, page {}", segment, offset);
		match handle.pwrite(data, offset * PAGE_SIZE as u64) {
			Ok(_) => (),
			//Err(e) => fail!("Writing to file failed: {}", e),
			// again Rust 0.10 pwrite error
			Err(_) => (),
		};
	}
}

/*
 * A buffer frame, the unit that gets the data
 */
impl BufferFrame {
	/*
	 * get_mut_data returns a borrowed reference to a mutable slice to the vector
	 * contents.
	 */
	pub fn get_mut_data<'a>(&'a mut self) -> &'a mut [u8] {
		self.data.as_mut_slice()
	}
	pub fn get_data<'a>(&'a self) -> &'a [u8] {
		self.data.as_slice()
	}
}

fn sample<'a, T, I:Iterator<T>>(from: &'a mut I) -> Option<T> {
	let from: ~[T] = from.collect();
	let l = from.len();
	if l == 0 {
		return None;
	}
	let index = randrange(l);
	Some(from[index])
}

fn randrange<X: SampleRange + Ord + Zero>(high: X) -> X {
	let between: Range<X> = Range::new(Zero::zero(), high);
	let mut rng = rand::task_rng();
	between.ind_sample(&mut rng)
}

fn split_segment(num: u64) -> (u64, u64) {
	let high = num >> PAGE_BITS;
	let low = num & ((1 << PAGE_BITS) - 1);
	(high, low)
}

#[test]
fn test_create() {
	let dir = match TempDir::new("buffermanager") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};

	let mut bm = BufferManager::new(16, dir.path().clone());
	let pageref = match bm.fix_page(42) {
		Some(p) => p,
		None => fail!("Getting page failed"),
	};
	{
		let mut page = pageref.write();
		let data = page.get_mut_data();
		data[0] = 42;
	}
	bm.unfix_page(pageref, true);
}

#[test]
fn test_threads() {
	use rand::random;
	use std::task::spawn;
	use std::os;

	let pages_in_ram: uint = match os::getenv("PAGES_IN_RAM") {
		Some(v) => from_str(v).expect("PAGES_IN_RAM expects integer"),
		None => 1,
	};
	let pages_on_disk: u64 = match os::getenv("PAGES_ON_DISK") {
		Some(v) => from_str(v).expect("PAGES_ON_DISK expects integer"),
		None => 20,
	};
	let thread_count: uint = match os::getenv("THREADS") {
		Some(v) => from_str(v).expect("THREADS expects integer"),
		None => 3,
	};
	let dir = match TempDir::new("buffermanager") {
		Some(temp_dir) => temp_dir,
		None => fail!("creation of temporary directory"),
	};
	let p = dir.path();
	let p = Path::new(".");

	let mut buffermanager = BufferManager::new(pages_in_ram, p.clone());

	for i in range(0, pages_on_disk) {
		let bf = match buffermanager.fix_page(i) {
			Some(frame) => frame,
			None => fail!("Couldn't fix page {}", i),
		};
		{
			let mut lock = bf.write();
			lock.get_mut_data()[0] = 0;
		}
		buffermanager.unfix_page(bf, true);
	}
	let bm = Arc::new(RWLock::new(buffermanager));

	// start scan thread
	let (tx, rx) = channel();
	let bm_scan = bm.clone();
	let mut scan = Future::spawn(proc() {
		let mut counters = Vec::from_elem(pages_on_disk as uint, 0_u8);
		loop {
			info!("Running scan thread...");
			match rx.try_recv() {
				Empty => {
					let page_number = randrange(pages_on_disk);
					let mut bm = bm_scan.write();
					let bf = match bm.fix_page(page_number) {
						Some(frame) => frame,
						None => fail!("Couldn't scan/fix page"),
					};
					let current_val = {
						let lock = bf.read();
						lock.get_data()[0]
					};
					bm.unfix_page(bf, false);
					bm.downgrade();
					// check if the value is going up
					assert!(&current_val >= counters.get(page_number as uint));
					// set to the new value
					let v = counters.get_mut(page_number as uint);
					*v = current_val;

				},
				/*
				 * terminate on both disconnect and when any kind of
				 * data arrives
				 */
				Disconnected => break,
				Data(_) => break,
			};
		}
	});

	// start read/write threads
	let mut rw_threads: Vec<Future<int>> = Vec::new();
	for _ in range(0, thread_count) {
		let bm = bm.clone();
		rw_threads.push(Future::spawn(proc() {
			let is_write = random::<bool>();
			info!("Creating new {} task",
				if is_write {"write"} else {"read"});
			let page_number = randrange(pages_on_disk);
			let mut bm = bm.write();
			if is_write {
				let bf = match bm.fix_page(page_number) {
					Some(frame) => frame,
					None => fail!("Couldn't fix page"),
				};
				{
					let mut lock = bf.write();
					let data = lock.get_mut_data();
					data[0] = data[0] + 1;
					info!("Wrote to page {}", page_number);
					debug!("data: {}", Vec::from_slice(data));
				}
				bm.unfix_page(bf, is_write);
			} else {
				let bf = match bm.fix_page(page_number) {
					Some(frame) => frame,
					None => fail!("Couldn't fix page"),
				};
				bm.unfix_page(bf, is_write);
			}
			// return whether we wrote (1) or read (0) as future
			if is_write {1} else {0}
		}));
	}

	// Rust does not have join, but we can wait on Futures which does the same
	let total_count = rw_threads.mut_iter().fold(0, |acc, val| acc + val.get());
	info!("Total count in RAM: {}", total_count);

	// terminate the scan thread and wait until it has completed
	tx.send("terminate");
	scan.get();

	// re-open the pages and check whether all numbers got saved
	let mut bm = BufferManager::new(pages_in_ram, p.clone());
	let mut total_count_on_disk = 0;
	for i in range(0, pages_on_disk) {
		let bf = match bm.fix_page(i) {
			Some(frame) => frame,
			None => fail!("Couldn't fix page")
		};
		let value = {
			let lock = bf.read();
			let data = lock.get_data();
			data[0]
		};
		bm.unfix_page(bf, false);
		// cast up from u8 to int
		total_count_on_disk += value as int;
	}
	info!("Total count on disk: {}", total_count_on_disk);
	assert_eq!(total_count, total_count_on_disk);
}
<|endoftext|>


<commit_before>use crate::types::Storage;
use parking_lot::Mutex;
use std::ops;
use std::sync::{mpsc, Arc};

/// Defines a signal that contains shared storage.
pub trait SharedSignal<T> {
    /// Obtains the internal storage.
    fn get_storage(&self) -> &Storage<T>;
    /// Samples the signal.
    fn sample(&self) -> &Storage<T>;
}

/// A signal that contains only storage.
pub struct SharedStorage<T, S> {
    storage: Storage<T>,
    _source: S,
}

impl<T, S> SharedStorage<T, S> {
    pub fn new(initial: T, source: S) -> Self {
        SharedStorage {
            storage: Storage::new(initial),
            _source: source,
        }
    }
}

impl<T, S> SharedSignal<T> for SharedStorage<T, S> {
    fn get_storage(&self) -> &Storage<T> {
        &self.storage
    }

    fn sample(&self) -> &Storage<T> {
        &self.storage
    }
}

impl<T, S> ops::Deref for SharedStorage<T, S> {
    type Target = Storage<T>;

    fn deref(&self) -> &Self::Target {
        &self.storage
    }
}

/// A signal that maps a parent shared signal.
pub struct SharedMap<T, S, F> {
    storage: Storage<T>,
    source: Arc<dyn SharedSignal<S> + Send + Sync>,
    f: F,
}

impl<T, S, F> SharedMap<T, S, F> {
    pub fn new(source: Arc<dyn SharedSignal<S> + Send + Sync>, f: F) -> Arc<Self> {
        Arc::new(SharedMap {
            storage: Default::default(),
            source,
            f,
        })
    }
}

impl<T, S, F> SharedSignal<T> for SharedMap<T, S, F>
where
    F: Fn(S) -> T + 'static,
    S: Clone,
{
    fn get_storage(&self) -> &Storage<T> {
        &self.storage
    }

    fn sample(&self) -> &Storage<T> {
        let res = (self.f)(self.source.sample().get());
        self.storage.set(res);
        &self.storage
    }
}

/// A signal that folds a parent signal.
pub struct SharedFold<T, S, F> {
    storage: Storage<T>,
    source: S,
    f: F,
}

impl<T, S, F> SharedFold<T, S, F> {
    pub fn new(initial: T, f: F, source: S) -> Arc<Self> {
        Arc::new(SharedFold {
            storage: Storage::new(initial),
            source,
            f,
        })
    }
}

impl<T, S, V, F> SharedSignal<T> for SharedFold<T, S, F>
where
    F: Fn(T, V) -> T,
    S: Fn() -> V,
{
    fn get_storage(&self) -> &Storage<T> {
        &self.storage
    }

    fn sample(&self) -> &Storage<T> {
        let val = (self.source)();
        self.storage.replace_with(|acc| (self.f)(acc, val));
        &self.storage
    }
}

/// A signal that folds a channel.
pub struct SharedChannel<T, S, F> {
    storage: Storage<T>,
    source: Mutex<mpsc::Receiver<S>>,
    f: F,
}

impl<T, S, F> SharedChannel<T, S, F> {
    pub fn new(initial: T, rx: mpsc::Receiver<S>, f: F) -> Arc<Self> {
        Arc::new(SharedChannel {
            storage: Storage::new(initial),
            source: Mutex::new(rx),
            f,
        })
    }
}

impl<T, S, F> SharedSignal<T> for SharedChannel<T, S, F>
where
    F: Fn(T, S) -> T + 'static,
{
    fn get_storage(&self) -> &Storage<T> {
        &self.storage
    }

    fn sample(&self) -> &Storage<T> {
        let source = self.source.lock();
        if let Ok(first) = source.try_recv() {
            self.storage.replace_with(|old| {
                let acc = (self.f)(old, first);
                source.try_iter().fold(acc, &self.f)
            });
        }
        &self.storage
    }
}
<commit_msg>removed redundant lifetime bounds<commit_after>use crate::types::Storage;
use parking_lot::Mutex;
use std::ops;
use std::sync::{mpsc, Arc};

/// Defines a signal that contains shared storage.
pub trait SharedSignal<T> {
    /// Obtains the internal storage.
    fn get_storage(&self) -> &Storage<T>;
    /// Samples the signal.
    fn sample(&self) -> &Storage<T>;
}

/// A signal that contains only storage.
pub struct SharedStorage<T, S> {
    storage: Storage<T>,
    _source: S,
}

impl<T, S> SharedStorage<T, S> {
    pub fn new(initial: T, source: S) -> Self {
        SharedStorage {
            storage: Storage::new(initial),
            _source: source,
        }
    }
}

impl<T, S> SharedSignal<T> for SharedStorage<T, S> {
    fn get_storage(&self) -> &Storage<T> {
        &self.storage
    }

    fn sample(&self) -> &Storage<T> {
        &self.storage
    }
}

impl<T, S> ops::Deref for SharedStorage<T, S> {
    type Target = Storage<T>;

    fn deref(&self) -> &Self::Target {
        &self.storage
    }
}

/// A signal that maps a parent shared signal.
pub struct SharedMap<T, S, F> {
    storage: Storage<T>,
    source: Arc<dyn SharedSignal<S> + Send + Sync>,
    f: F,
}

impl<T, S, F> SharedMap<T, S, F> {
    pub fn new(source: Arc<dyn SharedSignal<S> + Send + Sync>, f: F) -> Arc<Self> {
        Arc::new(SharedMap {
            storage: Default::default(),
            source,
            f,
        })
    }
}

impl<T, S, F> SharedSignal<T> for SharedMap<T, S, F>
where
    F: Fn(S) -> T,
    S: Clone,
{
    fn get_storage(&self) -> &Storage<T> {
        &self.storage
    }

    fn sample(&self) -> &Storage<T> {
        let res = (self.f)(self.source.sample().get());
        self.storage.set(res);
        &self.storage
    }
}

/// A signal that folds a parent signal.
pub struct SharedFold<T, S, F> {
    storage: Storage<T>,
    source: S,
    f: F,
}

impl<T, S, F> SharedFold<T, S, F> {
    pub fn new(initial: T, f: F, source: S) -> Arc<Self> {
        Arc::new(SharedFold {
            storage: Storage::new(initial),
            source,
            f,
        })
    }
}

impl<T, S, V, F> SharedSignal<T> for SharedFold<T, S, F>
where
    F: Fn(T, V) -> T,
    S: Fn() -> V,
{
    fn get_storage(&self) -> &Storage<T> {
        &self.storage
    }

    fn sample(&self) -> &Storage<T> {
        let val = (self.source)();
        self.storage.replace_with(|acc| (self.f)(acc, val));
        &self.storage
    }
}

/// A signal that folds a channel.
pub struct SharedChannel<T, S, F> {
    storage: Storage<T>,
    source: Mutex<mpsc::Receiver<S>>,
    f: F,
}

impl<T, S, F> SharedChannel<T, S, F> {
    pub fn new(initial: T, rx: mpsc::Receiver<S>, f: F) -> Arc<Self> {
        Arc::new(SharedChannel {
            storage: Storage::new(initial),
            source: Mutex::new(rx),
            f,
        })
    }
}

impl<T, S, F> SharedSignal<T> for SharedChannel<T, S, F>
where
    F: Fn(T, S) -> T,
{
    fn get_storage(&self) -> &Storage<T> {
        &self.storage
    }

    fn sample(&self) -> &Storage<T> {
        let source = self.source.lock();
        if let Ok(first) = source.try_recv() {
            self.storage.replace_with(|old| {
                let acc = (self.f)(old, first);
                source.try_iter().fold(acc, &self.f)
            });
        }
        &self.storage
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013-2014, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;
use common::*;
use arena::*;
use layout;

pub struct ReaderOptions {
    traversalLimitInWords : u64,
    nestingLimit : uint
}

pub static DEFAULT_READER_OPTIONS : ReaderOptions =
    ReaderOptions { traversalLimitInWords : 8 * 1024 * 1024, nestingLimit : 64 };

type SegmentId = u32;

pub trait MessageReader {
    fn get_segment<'a>(&'a self, id : uint) -> &'a [Word];
    fn arena<'a>(&'a self) -> &'a ReaderArena;
    fn get_options<'a>(&'a self) -> &'a ReaderOptions;
    fn get_root<'a, T : layout::FromStructReader<'a>>(&'a self) -> T {
        unsafe {
            let segment : *SegmentReader = std::ptr::to_unsafe_ptr(&self.arena().segment0);

            let pointer_reader = layout::PointerReader::get_root::<'a>(
                segment, (*segment).get_start_ptr(), self.get_options().nestingLimit as int);

            let result : T = layout::FromStructReader::from_struct_reader(
                pointer_reader.get_struct::<'a>(std::ptr::null()));

            result
        }

    }
}

pub struct SegmentArrayMessageReader<'a> {
    priv segments : &'a [ &'a [Word]],
    priv options : ReaderOptions,
    priv arena : ~ReaderArena
}

impl <'a> MessageReader for SegmentArrayMessageReader<'a> {
    fn get_segment<'b>(&'b self, id : uint) -> &'b [Word] {
        self.segments[id]
    }

    fn arena<'b>(&'b self) -> &'b ReaderArena {
        &*self.arena
    }

    fn get_options<'b>(&'b self) -> &'b ReaderOptions {
        return &self.options;
    }
}

impl <'a> SegmentArrayMessageReader<'a> {

    pub fn new<'b>(segments : &'b [&'b [Word]], options : ReaderOptions) -> SegmentArrayMessageReader<'b> {
        assert!(segments.len() > 0);
        SegmentArrayMessageReader {
            segments : segments,
            arena : ReaderArena::new(segments),
            options : options
        }
    }
}

pub enum AllocationStrategy {
    FIXED_SIZE,
    GROW_HEURISTICALLY
}

pub static SUGGESTED_FIRST_SEGMENT_WORDS : uint = 1024;
pub static SUGGESTED_ALLOCATION_STRATEGY : AllocationStrategy = GROW_HEURISTICALLY;

pub trait MessageBuilder {
    fn arena<'a>(&'a mut self) -> &'a mut BuilderArena;

    fn init_root<'a, T : layout::FromStructBuilder<'a> + layout::HasStructSize>(&'a mut self) -> T {
        let rootSegment = std::ptr::to_mut_unsafe_ptr(&mut self.arena().segment0);

        match self.arena().segment0.allocate(WORDS_PER_POINTER) {
            None => {fail!("could not allocate root pointer") }
            Some(location) => {
                //assert!(location == 0,
                //        "First allocated word of new segment was not at offset 0");

                let pb = layout::PointerBuilder::get_root(rootSegment, location);

                return layout::FromStructBuilder::from_struct_builder(
                    pb.init_struct(layout::HasStructSize::struct_size(None::<T>)));
            }
        }

    }

    fn get_segments_for_output<T>(&mut self, cont : |&[&[Word]]| -> T) -> T {
        self.arena().get_segments_for_output(cont)
    }

}

pub struct MallocMessageBuilder {
    priv arena : ~BuilderArena,
}

impl Drop for MallocMessageBuilder {
    fn drop(&mut self) { }
}

impl MallocMessageBuilder {

    pub fn new(first_segment_size : uint, allocationStrategy : AllocationStrategy) -> MallocMessageBuilder {
        let arena = BuilderArena::new(allocationStrategy, NumWords(first_segment_size));

        MallocMessageBuilder { arena : arena }
    }

    pub fn new_default() -> MallocMessageBuilder {
        MallocMessageBuilder::new(SUGGESTED_FIRST_SEGMENT_WORDS, SUGGESTED_ALLOCATION_STRATEGY)
    }

}

impl MessageBuilder for MallocMessageBuilder {
    fn arena<'a>(&'a mut self) -> &'a mut BuilderArena {
        &mut *self.arena
    }

}

pub struct ScratchSpaceMallocMessageBuilder<'a> {
    priv arena : ~BuilderArena,
    priv scratch_space : &'a mut [Word],
}

// TODO: figure out why rust thinks this is unsafe.
#[unsafe_destructor]
impl <'a> Drop for ScratchSpaceMallocMessageBuilder<'a> {
    fn drop(&mut self) {
        unsafe {
            let len = self.scratch_space.len();
            std::ptr::zero_memory(self.scratch_space.as_mut_ptr(), len);
        }
    }
}

impl <'a> ScratchSpaceMallocMessageBuilder<'a> {

    pub fn new<'b>(scratch_space : &'b mut [Word], allocationStrategy : AllocationStrategy)
               -> ScratchSpaceMallocMessageBuilder<'b> {
        let arena = BuilderArena::new(allocationStrategy, ZeroedWords(scratch_space));

        ScratchSpaceMallocMessageBuilder { arena : arena, scratch_space : scratch_space }
    }

    pub fn new_default<'b>(scratch_space : &'b mut [Word]) -> ScratchSpaceMallocMessageBuilder<'b> {
        ScratchSpaceMallocMessageBuilder::new(scratch_space, SUGGESTED_ALLOCATION_STRATEGY)
    }

}

impl <'a> MessageBuilder for ScratchSpaceMallocMessageBuilder<'a> {
    fn arena<'a>(&'a mut self) -> &'a mut BuilderArena {
        &mut *self.arena
    }
}
<commit_msg>ah, that's better<commit_after>/*
 * Copyright (c) 2013-2014, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;
use common::*;
use arena::*;
use layout;

pub struct ReaderOptions {
    traversalLimitInWords : u64,
    nestingLimit : uint
}

pub static DEFAULT_READER_OPTIONS : ReaderOptions =
    ReaderOptions { traversalLimitInWords : 8 * 1024 * 1024, nestingLimit : 64 };

type SegmentId = u32;

pub trait MessageReader {
    fn get_segment<'a>(&'a self, id : uint) -> &'a [Word];
    fn arena<'a>(&'a self) -> &'a ReaderArena;
    fn get_options<'a>(&'a self) -> &'a ReaderOptions;
    fn get_root<'a, T : layout::FromStructReader<'a>>(&'a self) -> T {
        unsafe {
            let segment : *SegmentReader = std::ptr::to_unsafe_ptr(&self.arena().segment0);

            let pointer_reader = layout::PointerReader::get_root::<'a>(
                segment, (*segment).get_start_ptr(), self.get_options().nestingLimit as int);

            let result : T = layout::FromStructReader::from_struct_reader(
                pointer_reader.get_struct::<'a>(std::ptr::null()));

            result
        }

    }
}

pub struct SegmentArrayMessageReader<'a> {
    priv segments : &'a [ &'a [Word]],
    priv options : ReaderOptions,
    priv arena : ~ReaderArena
}

impl <'a> MessageReader for SegmentArrayMessageReader<'a> {
    fn get_segment<'b>(&'b self, id : uint) -> &'b [Word] {
        self.segments[id]
    }

    fn arena<'b>(&'b self) -> &'b ReaderArena {
        &*self.arena
    }

    fn get_options<'b>(&'b self) -> &'b ReaderOptions {
        return &self.options;
    }
}

impl <'a> SegmentArrayMessageReader<'a> {

    pub fn new<'b>(segments : &'b [&'b [Word]], options : ReaderOptions) -> SegmentArrayMessageReader<'b> {
        assert!(segments.len() > 0);
        SegmentArrayMessageReader {
            segments : segments,
            arena : ReaderArena::new(segments),
            options : options
        }
    }
}

pub enum AllocationStrategy {
    FIXED_SIZE,
    GROW_HEURISTICALLY
}

pub static SUGGESTED_FIRST_SEGMENT_WORDS : uint = 1024;
pub static SUGGESTED_ALLOCATION_STRATEGY : AllocationStrategy = GROW_HEURISTICALLY;

pub trait MessageBuilder {
    fn arena<'a>(&'a mut self) -> &'a mut BuilderArena;

    fn init_root<'a, T : layout::FromStructBuilder<'a> + layout::HasStructSize>(&'a mut self) -> T {
        let rootSegment = std::ptr::to_mut_unsafe_ptr(&mut self.arena().segment0);

        match self.arena().segment0.allocate(WORDS_PER_POINTER) {
            None => {fail!("could not allocate root pointer") }
            Some(location) => {
                //assert!(location == 0,
                //        "First allocated word of new segment was not at offset 0");

                let pb = layout::PointerBuilder::get_root(rootSegment, location);

                return layout::FromStructBuilder::from_struct_builder(
                    pb.init_struct(layout::HasStructSize::struct_size(None::<T>)));
            }
        }

    }

    fn get_segments_for_output<T>(&mut self, cont : |&[&[Word]]| -> T) -> T {
        self.arena().get_segments_for_output(cont)
    }

}

pub struct MallocMessageBuilder {
    priv arena : ~BuilderArena,
}

impl Drop for MallocMessageBuilder {
    fn drop(&mut self) { }
}

impl MallocMessageBuilder {

    pub fn new(first_segment_size : uint, allocationStrategy : AllocationStrategy) -> MallocMessageBuilder {
        let arena = BuilderArena::new(allocationStrategy, NumWords(first_segment_size));

        MallocMessageBuilder { arena : arena }
    }

    pub fn new_default() -> MallocMessageBuilder {
        MallocMessageBuilder::new(SUGGESTED_FIRST_SEGMENT_WORDS, SUGGESTED_ALLOCATION_STRATEGY)
    }

}

impl MessageBuilder for MallocMessageBuilder {
    fn arena<'a>(&'a mut self) -> &'a mut BuilderArena {
        &mut *self.arena
    }

}

pub struct ScratchSpaceMallocMessageBuilder<'a> {
    priv arena : ~BuilderArena,
    priv scratch_space : &'a mut [Word],
}

// TODO: figure out why rust thinks this is unsafe.
#[unsafe_destructor]
impl <'a> Drop for ScratchSpaceMallocMessageBuilder<'a> {
    fn drop(&mut self) {
        let ptr = self.scratch_space.as_mut_ptr();
        self.get_segments_for_output(|segments| {
                unsafe {
                    std::ptr::zero_memory(ptr, segments[0].len());
                }
            });
    }
}

impl <'a> ScratchSpaceMallocMessageBuilder<'a> {

    pub fn new<'b>(scratch_space : &'b mut [Word], allocationStrategy : AllocationStrategy)
               -> ScratchSpaceMallocMessageBuilder<'b> {
        let arena = BuilderArena::new(allocationStrategy, ZeroedWords(scratch_space));

        ScratchSpaceMallocMessageBuilder { arena : arena, scratch_space : scratch_space }
    }

    pub fn new_default<'b>(scratch_space : &'b mut [Word]) -> ScratchSpaceMallocMessageBuilder<'b> {
        ScratchSpaceMallocMessageBuilder::new(scratch_space, SUGGESTED_ALLOCATION_STRATEGY)
    }

}

impl <'a> MessageBuilder for ScratchSpaceMallocMessageBuilder<'a> {
    fn arena<'a>(&'a mut self) -> &'a mut BuilderArena {
        &mut *self.arena
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2021-present, Gregory Szorc
// All rights reserved.
//
// This software may be modified and distributed under the terms
// of the BSD license. See the LICENSE file for details.

use {
    crate::decompressor::DCtx,
    pyo3::{buffer::PyBuffer, exceptions::PyNotImplementedError, prelude::*},
    std::sync::Arc,
};

#[pyclass(module = "zstandard.backend_rust")]
pub struct ZstdDecompressionReader {
    dctx: Arc<DCtx<'static>>,
    reader: PyObject,
    read_size: usize,
    read_across_frames: bool,
    closefd: bool,
}

impl ZstdDecompressionReader {
    pub fn new(
        py: Python,
        dctx: Arc<DCtx<'static>>,
        reader: &PyAny,
        read_size: usize,
        read_across_frames: bool,
        closefd: bool,
    ) -> PyResult<Self> {
        Ok(Self {
            dctx,
            reader: reader.into_py(py),
            read_size,
            read_across_frames,
            closefd,
        })
    }
}

#[pymethods]
impl ZstdDecompressionReader {
    // TODO __enter__
    // TODO __exit__

    fn readable(&self) -> bool {
        true
    }

    fn writable(&self) -> bool {
        false
    }

    fn seekable(&self) -> bool {
        false
    }

    #[args(size = "None")]
    fn readline(&self, py: Python, _size: Option<&PyAny>) -> PyResult<()> {
        let io = py.import("io")?;
        let exc = io.getattr("UnsupportedOperation")?;

        Err(PyErr::from_instance(exc))
    }

    #[args(size = "None")]
    fn readlines(&self, py: Python, _hint: Option<&PyAny>) -> PyResult<()> {
        let io = py.import("io")?;
        let exc = io.getattr("UnsupportedOperation")?;

        Err(PyErr::from_instance(exc))
    }

    fn write(&self, py: Python, _data: &PyAny) -> PyResult<()> {
        let io = py.import("io")?;
        let exc = io.getattr("UnsupportedOperation")?;

        Err(PyErr::from_instance(exc))
    }

    fn writelines(&self, py: Python, _lines: &PyAny) -> PyResult<()> {
        let io = py.import("io")?;
        let exc = io.getattr("UnsupportedOperation")?;

        Err(PyErr::from_instance(exc))
    }

    fn isatty(&self) -> bool {
        false
    }

    fn flush(&self) -> PyResult<()> {
        Ok(())
    }

    fn close(&self) -> PyResult<()> {
        Err(PyNotImplementedError::new_err(()))
    }

    #[getter]
    fn closed(&self) -> PyResult<()> {
        Err(PyNotImplementedError::new_err(()))
    }

    fn tell(&self) -> PyResult<()> {
        Err(PyNotImplementedError::new_err(()))
    }

    fn readall(&self) -> PyResult<()> {
        Err(PyNotImplementedError::new_err(()))
    }

    // TODO __iter__
    // TODO __next__

    #[args(size = "None")]
    fn read(&self, size: Option<usize>) -> PyResult<()> {
        Err(PyNotImplementedError::new_err(()))
    }

    fn readinto(&self, buffer: PyBuffer<u8>) -> PyResult<()> {
        Err(PyNotImplementedError::new_err(()))
    }

    #[args(size = "None")]
    fn read1(&self, size: Option<usize>) -> PyResult<()> {
        Err(PyNotImplementedError::new_err(()))
    }

    fn readinto1(&self, buffer: PyBuffer<u8>) -> PyResult<()> {
        Err(PyNotImplementedError::new_err(()))
    }

    #[args(pos, whence = "None")]
    fn seek(&self, pos: isize, whence: Option<i32>) -> PyResult<()> {
        Err(PyNotImplementedError::new_err(()))
    }
}
<commit_msg>rust: implement ZstdDecompressionReader<commit_after>// Copyright (c) 2021-present, Gregory Szorc
// All rights reserved.
//
// This software may be modified and distributed under the terms
// of the BSD license. See the LICENSE file for details.

use {
    crate::{
        decompressor::DCtx,
        exceptions::ZstdError,
        stream::{make_in_buffer_source, InBufferSource},
    },
    pyo3::{
        buffer::PyBuffer,
        exceptions::{PyOSError, PyValueError},
        prelude::*,
        types::{PyBytes, PyList},
        PyIterProtocol,
    },
    std::{cmp::min, sync::Arc},
};

#[pyclass(module = "zstandard.backend_rust")]
pub struct ZstdDecompressionReader {
    dctx: Arc<DCtx<'static>>,
    source: Box<dyn InBufferSource + Send>,
    read_size: usize,
    read_across_frames: bool,
    closefd: bool,
    entered: bool,
    closed: bool,
    bytes_decompressed: usize,
    finished_output: bool,
}

impl ZstdDecompressionReader {
    pub fn new(
        py: Python,
        dctx: Arc<DCtx<'static>>,
        reader: &PyAny,
        read_size: usize,
        read_across_frames: bool,
        closefd: bool,
    ) -> PyResult<Self> {
        Ok(Self {
            dctx,
            source: make_in_buffer_source(py, reader, read_size)?,
            read_size,
            read_across_frames,
            closefd,
            entered: false,
            closed: false,
            bytes_decompressed: 0,
            finished_output: false,
        })
    }
}

impl ZstdDecompressionReader {
    fn decompress_into_buffer(
        &mut self,
        py: Python,
        out_buffer: &mut zstd_sys::ZSTD_outBuffer,
    ) -> PyResult<bool> {
        let mut in_buffer =
            self.source
                .input_buffer(py)?
                .unwrap_or_else(|| zstd_sys::ZSTD_inBuffer {
                    src: std::ptr::null_mut(),
                    size: 0,
                    pos: 0,
                });

        let old_pos = in_buffer.pos;

        let zresult = unsafe {
            zstd_sys::ZSTD_decompressStream(
                self.dctx.dctx(),
                out_buffer as *mut _,
                &mut in_buffer as *mut _,
            )
        };

        if in_buffer.pos - old_pos > 0 {
            self.source.record_bytes_read(in_buffer.pos - old_pos);
        }

        if unsafe { zstd_sys::ZSTD_isError(zresult) } != 0 {
            return Err(ZstdError::new_err(format!(
                "zstd decompress error: {}",
                zstd_safe::get_error_name(zresult)
            )));
        }

        // Emit data if there is data AND either:
        // a) output buffer is full (read amount is satisfied)
        // b) we're at the end of a frame and not in frame spanning mode
        return Ok(out_buffer.pos != 0
            && (out_buffer.pos == out_buffer.size || zresult == 0 && !self.read_across_frames));
    }
}

#[pymethods]
impl ZstdDecompressionReader {
    fn __enter__<'p>(mut slf: PyRefMut<'p, Self>, _py: Python<'p>) -> PyResult<PyRefMut<'p, Self>> {
        if slf.entered {
            Err(PyValueError::new_err("cannot __enter__ multiple times"))
        } else if slf.closed {
            Err(PyValueError::new_err("stream is closed"))
        } else {
            slf.entered = true;
            Ok(slf)
        }
    }

    fn __exit__<'p>(
        mut slf: PyRefMut<'p, Self>,
        py: Python<'p>,
        exc_type: &PyAny,
        exc_value: &PyAny,
        exc_tb: &PyAny,
    ) -> PyResult<bool> {
        slf.entered = false;
        // TODO release decompressor and source?
        slf.close(py)?;

        Ok(false)
    }

    fn readable(&self) -> bool {
        true
    }

    fn writable(&self) -> bool {
        false
    }

    fn seekable(&self) -> bool {
        false
    }

    #[args(size = "None")]
    fn readline(&self, py: Python, size: Option<&PyAny>) -> PyResult<()> {
        let io = py.import("io")?;
        let exc = io.getattr("UnsupportedOperation")?;

        Err(PyErr::from_instance(exc))
    }

    #[args(size = "None")]
    fn readlines(&self, py: Python, hint: Option<&PyAny>) -> PyResult<()> {
        let io = py.import("io")?;
        let exc = io.getattr("UnsupportedOperation")?;

        Err(PyErr::from_instance(exc))
    }

    fn write(&self, py: Python, data: &PyAny) -> PyResult<()> {
        let io = py.import("io")?;
        let exc = io.getattr("UnsupportedOperation")?;

        Err(PyErr::from_instance(exc))
    }

    fn writelines(&self, py: Python, lines: &PyAny) -> PyResult<()> {
        let io = py.import("io")?;
        let exc = io.getattr("UnsupportedOperation")?;

        Err(PyErr::from_instance(exc))
    }

    fn isatty(&self) -> bool {
        false
    }

    fn flush(&self) -> PyResult<()> {
        Ok(())
    }

    fn close(&mut self, py: Python) -> PyResult<()> {
        if self.closed {
            return Ok(());
        }

        self.closed = true;

        if let Ok(close) = self.source.source_object().getattr(py, "close") {
            if self.closefd {
                close.call0(py)?;
            }
        }

        Ok(())
    }

    #[getter]
    fn closed(&self) -> bool {
        self.closed
    }

    fn tell(&self) -> usize {
        self.bytes_decompressed
    }

    fn readall<'p>(&mut self, py: Python<'p>) -> PyResult<&'p PyAny> {
        let chunks = PyList::empty(py);

        loop {
            let chunk = self.read(py, Some(1048576))?;
            if chunk.len()? == 0 {
                break;
            }

            chunks.append(chunk)?;
        }

        let empty = PyBytes::new(py, &[]);

        empty.call_method1("join", (chunks,))
    }

    #[args(size = "None")]
    fn read<'p>(&mut self, py: Python<'p>, size: Option<isize>) -> PyResult<&'p PyAny> {
        if self.closed {
            return Err(PyValueError::new_err("stream is closed"));
        }

        let size = size.unwrap_or(-1);

        if size < -1 {
            return Err(PyValueError::new_err(
                "cannot read negative amounts less than -1",
            ));
        }

        if size == -1 {
            return self.readall(py);
        }

        if self.finished_output || size == 0 {
            return Ok(PyBytes::new(py, &[]));
        }

        let mut dest_buffer: Vec<u8> = Vec::with_capacity(size as _);
        let mut out_buffer = zstd_sys::ZSTD_outBuffer {
            dst: dest_buffer.as_mut_ptr() as *mut _,
            size: dest_buffer.capacity(),
            pos: 0,
        };

        if self.decompress_into_buffer(py, &mut out_buffer)? {
            self.bytes_decompressed += out_buffer.pos;
            unsafe {
                dest_buffer.set_len(out_buffer.pos);
            }

            // TODO avoid buffer copy.
            let chunk = PyBytes::new(py, &dest_buffer);
            return Ok(chunk);
        }

        while !self.source.finished() {
            if self.decompress_into_buffer(py, &mut out_buffer)? {
                self.bytes_decompressed += out_buffer.pos;
                unsafe {
                    dest_buffer.set_len(out_buffer.pos);
                }

                // TODO avoid buffer copy.
                let chunk = PyBytes::new(py, &dest_buffer);
                return Ok(chunk);
            }
        }

        self.bytes_decompressed += out_buffer.pos;
        unsafe {
            dest_buffer.set_len(out_buffer.pos);
        }

        // TODO avoid buffer copy.
        let chunk = PyBytes::new(py, &dest_buffer);
        return Ok(chunk);
    }

    fn readinto(&mut self, py: Python, buffer: PyBuffer<u8>) -> PyResult<usize> {
        if buffer.readonly() {
            return Err(PyValueError::new_err("buffer is not writable"));
        }

        if self.closed {
            return Err(PyValueError::new_err("stream is closed"));
        }

        if self.finished_output {
            return Ok(0);
        }

        let mut out_buffer = zstd_sys::ZSTD_outBuffer {
            dst: buffer.buf_ptr() as *mut _,
            size: buffer.len_bytes(),
            pos: 0,
        };

        if self.decompress_into_buffer(py, &mut out_buffer)? {
            self.bytes_decompressed += out_buffer.pos;

            return Ok(out_buffer.pos);
        }

        while !self.source.finished() {
            if self.decompress_into_buffer(py, &mut out_buffer)? {
                self.bytes_decompressed += out_buffer.pos;

                return Ok(out_buffer.pos);
            }
        }

        self.bytes_decompressed += out_buffer.pos;

        Ok(out_buffer.pos)
    }

    #[args(size = "None")]
    fn read1<'p>(&mut self, py: Python<'p>, size: Option<isize>) -> PyResult<&'p PyAny> {
        if self.closed {
            return Err(PyValueError::new_err("stream is closed"));
        }

        let size = size.unwrap_or(-1);

        if size < -1 {
            return Err(PyValueError::new_err(
                "cannot read negative amounts less than -1",
            ));
        }

        if self.finished_output || size == 0 {
            return Ok(PyBytes::new(py, &[]));
        }

        // -1 returns arbitrary number of bytes.
        let size = match size {
            -1 => zstd_safe::dstream_out_size(),
            size => size as _,
        };

        let mut dest_buffer: Vec<u8> = Vec::with_capacity(size);
        let mut out_buffer = zstd_sys::ZSTD_outBuffer {
            dst: dest_buffer.as_mut_ptr() as *mut _,
            size: dest_buffer.capacity(),
            pos: 0,
        };

        // read1() dictates that we can perform at most 1 call to underlying
        // stream to get input. However, we can't satisfy this restriction with
        // decompression because not all input generates output. So we allow
        // multiple read(). But unlike read(), we stop once we have any output.
        while !self.source.finished() {
            self.decompress_into_buffer(py, &mut out_buffer)?;

            if out_buffer.pos > 0 {
                break;
            }
        }

        unsafe {
            dest_buffer.set_len(out_buffer.pos);
        }
        self.bytes_decompressed += out_buffer.pos;

        // TODO avoid buffer copy.
        let chunk = PyBytes::new(py, &dest_buffer);
        Ok(chunk)
    }

    fn readinto1(&mut self, py: Python, buffer: PyBuffer<u8>) -> PyResult<usize> {
        if buffer.readonly() {
            return Err(PyValueError::new_err("buffer is not writable"));
        }

        if self.closed {
            return Err(PyValueError::new_err("stream is closed"));
        }

        if self.finished_output {
            return Ok(0);
        }

        let mut out_buffer = zstd_sys::ZSTD_outBuffer {
            dst: buffer.buf_ptr(),
            size: buffer.len_bytes(),
            pos: 0,
        };

        while !self.source.finished() && !self.finished_output {
            self.decompress_into_buffer(py, &mut out_buffer)?;

            if out_buffer.pos > 0 {
                break;
            }
        }

        self.bytes_decompressed += out_buffer.pos;

        Ok(out_buffer.pos)
    }

    #[args(pos, whence = "None")]
    fn seek(&mut self, py: Python, pos: isize, whence: Option<i32>) -> PyResult<usize> {
        if self.closed {
            return Err(PyValueError::new_err("stream is closed"));
        }

        let os = py.import("os")?;

        let seek_set = os.getattr("SEEK_SET")?.extract::<i32>()?;
        let seek_cur = os.getattr("SEEK_CUR")?.extract::<i32>()?;
        let seek_end = os.getattr("SEEK_END")?.extract::<i32>()?;

        let whence = whence.unwrap_or(seek_set);

        let mut read_amount = if whence == seek_set {
            if pos < 0 {
                return Err(PyOSError::new_err(
                    "cannot seek to negative position with SEEK_SET",
                ));
            }

            if pos < self.bytes_decompressed as isize {
                return Err(PyOSError::new_err(
                    "cannot seek zstd decompression stream backwards",
                ));
            }

            pos as usize - self.bytes_decompressed
        } else if whence == seek_cur {
            if pos < 0 {
                return Err(PyOSError::new_err(
                    "cannot seek zstd decompression stream backwards",
                ));
            }

            pos as usize
        } else if whence == seek_end {
            return Err(PyOSError::new_err(
                "zstd decompression streams cannot be seeked with SEEK_END",
            ));
        } else {
            0
        };

        while read_amount > 0 {
            let result = self.read(
                py,
                Some(min(read_amount, zstd_safe::dstream_out_size()) as _),
            )?;

            if result.len()? == 0 {
                break;
            }

            read_amount -= result.len()?;
        }

        Ok(self.bytes_decompressed)
    }
}

#[pyproto]
impl PyIterProtocol for ZstdDecompressionReader {
    fn __iter__(slf: PyRef<Self>) -> PyResult<()> {
        let py = unsafe { Python::assume_gil_acquired() };
        let io = py.import("io")?;
        let exc = io.getattr("UnsupportedOperation")?;

        Err(PyErr::from_instance(exc))
    }

    fn __next__(slf: PyRef<Self>) -> PyResult<Option<()>> {
        let py = unsafe { Python::assume_gil_acquired() };
        let io = py.import("io")?;
        let exc = io.getattr("UnsupportedOperation")?;

        Err(PyErr::from_instance(exc))
    }
}
<|endoftext|>