<commit_before>extern crate futures;
extern crate futures_cpupool;
extern crate serde_json;
extern crate tokio_core;
extern crate tokio_service;

use std;
use std::collections::HashMap;
use std::io::Read;
use std::sync::{Arc, Mutex};
use std::error::Error as StdError;

use self::futures::{Future, Stream, Sink};
use self::futures::sync::mpsc;
use self::tokio_core::io::Io;
use self::tokio_service::Service as TokioService;

use super::error::Error;
use super::grammar;
use super::runtime;
use super::value::Obj;

#[derive(Serialize, Deserialize)]
pub enum Request {
    Add { source: String, name: String },
    Remove { name: String },
    // Start { name: String },
    // Stop { name: String },
    List,
    SendTo(Envelope), /* RecvFrom { handle: String },
                       * Introduce { names: Vec<String> }, */
}

#[derive(Serialize, Deserialize)]
pub enum Response {
    Add,
    Remove,
    // Start,
    // Stop,
    List { names: Vec<String> },
    SendTo, /* RecvFrom { topic: String, contents: Obj },
             * Introduce, */
}

pub struct Codec;

impl tokio_core::io::Codec for Codec {
    type In = Request;
    type Out = Response;

    fn decode(&mut self, buf: &mut tokio_core::io::EasyBuf) -> std::io::Result<Option<Self::In>> {
        if let Some(i) = buf.as_slice().iter().position(|&b| b == b'\n') {
            // remove the serialized frame from the buffer.
            let line = buf.drain_to(i);

            // Also remove the '\n'
            buf.drain_to(1);

            // Turn this data into a UTF string and
            // return it in a Frame.
            let maybe_req: Result<Self::In, serde_json::error::Error> =
                serde_json::from_slice(line.as_slice());
            match maybe_req {
                Ok(req) => Ok(Some(req)),
                Err(e) => {
                    println!("decode failed: {}", e);
                    Err(std::io::Error::new(std::io::ErrorKind::Other, e.description()))
                }
            }
        } else {
            Ok(None)
        }
    }

    fn encode(&mut self, msg: Self::Out, buf: &mut Vec<u8>) -> std::io::Result<()> {
        match serde_json::to_writer(buf, &msg) {
            Ok(_) => Ok(()),
            Err(e) => Err(std::io::Error::new(std::io::ErrorKind::Other, e.description())),
        }
    }
}

#[derive(Serialize, Deserialize)]
pub struct Envelope {
    // src: String,
    dst: String,
    topic: String,
    contents: Obj,
}

pub struct Agent {
    matches: Vec<runtime::Match>,
    st: runtime::State,
    receiver: mpsc::Receiver<Envelope>,
    match_index: usize,
}

impl Agent {
    pub fn new_from_file(path: &str, receiver: mpsc::Receiver<Envelope>) -> Result<Agent, Error> {
        let glop_contents = read_file(path)?;
        let glop = grammar::glop(&glop_contents).map_err(Error::Parse)?;
        let mut st = runtime::State::new();
        st.push_msg("init", Obj::new());
        let m_excs = glop.matches
            .iter()
            .map(|m_ast| runtime::Match::new_from_ast(&m_ast))
            .collect::<Vec<_>>();
        Ok(Agent {
            matches: m_excs,
            st: st,
            receiver: receiver,
            match_index: 0,
        })
    }
}

impl Agent {
    fn poll_matches(&mut self) -> futures::Poll<Option<()>, runtime::Error> {
        let i = self.match_index % self.matches.len();
        let m = &self.matches[i];
        let actions = match self.st.eval(m) {
            Some(ref mut txn) => {
                match txn.apply(m) {
                    Ok(actions) => actions,
                    Err(e) => return Err(e),
                }
            }
            None => {
                return Ok(futures::Async::NotReady);
            }
        };
        // TODO: intelligent selection of next match?
        self.match_index = self.match_index + 1;
        // TODO: graceful agent termination (nothing left to do)?
        match self.st.commit(&actions) {
            Ok(_) => Ok(futures::Async::Ready(Some(()))),
            Err(e) => Err(e),
        }
    }
}

impl futures::stream::Stream for Agent {
    type Item = ();
    type Error = runtime::Error;

    fn poll(&mut self) -> futures::Poll<Option<Self::Item>, Self::Error> {
        // TODO: poll mpsc channel (receiver end) for state changes & apply?
        match self.receiver.poll() {
            Ok(futures::Async::Ready(Some(env))) => self.st.push_msg(&env.topic, env.contents),
            Ok(futures::Async::Ready(None)) => return Ok(futures::Async::Ready(None)),
            Ok(futures::Async::NotReady) => {}
            Err(_) => return Ok(futures::Async::Ready(None)),
        }
        let result = self.poll_matches();
        std::thread::sleep(std::time::Duration::from_millis(100));
        result
    }
}

fn read_file(path: &str) -> Result<String, Error> {
    let mut f = std::fs::File::open(path)?;
    let mut s = String::new();
    f.read_to_string(&mut s).map_err(Error::IO)?;
    Ok(s)
}

#[derive(Clone)]
pub struct Service {
    senders: Arc<Mutex<HashMap<String, mpsc::Sender<Envelope>>>>,
    handle: tokio_core::reactor::Handle,
    pool: futures_cpupool::CpuPool,
}

impl Service {
    pub fn new(h: &tokio_core::reactor::Handle) -> Service {
        Service {
            senders: Arc::new(Mutex::new(HashMap::new())),
            handle: h.clone(),
            pool: futures_cpupool::CpuPool::new_num_cpus(),
        }
    }

    fn do_call(&self, req: Request) -> Result<Response, runtime::Error> {
        let mut senders = self.senders.lock().unwrap();
        let res = match req {
            Request::Add { source: ref add_source, name: ref add_name } => {
                let (sender, receiver) = mpsc::channel(10);
                senders.insert(add_name.clone(), sender);
                let agent =
                    Agent::new_from_file(add_source, receiver).map_err(runtime::Error::Base)?;
                self.handle.spawn(self.pool
                    .spawn(agent.for_each(|_| Ok(()))
                        .or_else(|e| {
                            println!("{}", e);
                            Err(e)
                        })
                        .then(|_| Ok(()))));
                Response::Add
            }
            Request::Remove { ref name } => {
                senders.remove(name);
                Response::Remove
            }
            // Start { name: String },
            // Stop { name: String },
            Request::List => Response::List { names: senders.keys().cloned().collect() },
            Request::SendTo(env) => {
                let sender = match senders.get(&env.dst) {
                    Some(s) => s.clone(),
                    None => return Ok(Response::SendTo), // TODO: handle unmatched dst
                };
                self.handle.spawn(sender.send(env).then(|_| Ok(())));
                Response::SendTo
            }
            // RecvFrom { handle: String },
            // Introduce { names: Vec<String> },
        };
        Ok(res)
    }
}

impl TokioService for Service {
    type Request = Request;
    type Response = Response;

    type Error = std::io::Error;

    type Future = futures::BoxFuture<Self::Response, Self::Error>;

    fn call(&self, req: Self::Request) -> Self::Future {
        match self.do_call(req) {
            Ok(res) => futures::future::ok(res).boxed(),
            Err(err) => {
                futures::future::err(std::io::Error::new(std::io::ErrorKind::Other,
                                                         err.description()))
                    .boxed()
            }
        }
    }
}

pub fn run_server() -> Result<(), std::io::Error> {
    let mut core = tokio_core::reactor::Core::new()?;
    let handle = core.handle();
    let addr = "127.0.0.1:0".parse().unwrap();
    let listener = tokio_core::net::TcpListener::bind(&addr, &handle)?;
    let listen_addr = &listener.local_addr()?;
    println!("{}", listen_addr);
    let connections = listener.incoming();
    let service = Service::new(&handle);
    let server = connections.for_each(move |(socket, _peer_addr)| {
        let (wr, rd) = socket.framed(Codec).split();
        let service = service.clone();
        let responses = rd.and_then(move |req| service.call(req));
        let responder = wr.send_all(responses)
            .or_else(|e| {
                println!("{}", e);
                Err(e)
            })
            .then(|_| Ok(()));
        handle.spawn(responder);
        Ok(())
    });
    core.run(server)
}
<commit_msg>Agents: Not cattle. Not pets. A fucking swarm of bees.<commit_after>extern crate futures;
extern crate futures_cpupool;
extern crate serde_json;
extern crate tokio_core;
extern crate tokio_service;

use std;
use std::collections::HashMap;
use std::io::Read;
use std::sync::{Arc, Mutex};
use std::error::Error as StdError;

use self::futures::{Future, Stream, Sink};
use self::futures::sync::mpsc;
use self::tokio_core::io::Io;
use self::tokio_service::Service as TokioService;

use super::error::Error;
use super::grammar;
use super::runtime;
use super::value::Obj;

#[derive(Serialize, Deserialize)]
pub enum Request {
    Add { source: String, name: String },
    Remove { name: String },
    List,
    SendTo(Envelope), /* RecvFrom { handle: String },
                       * Introduce { names: Vec<String> }, */
}

#[derive(Serialize, Deserialize)]
pub enum Response {
    Add,
    Remove,
    List { names: Vec<String> },
    SendTo, /* RecvFrom { topic: String, contents: Obj },
             * Introduce, */
}

pub struct Codec;

impl tokio_core::io::Codec for Codec {
    type In = Request;
    type Out = Response;

    fn decode(&mut self, buf: &mut tokio_core::io::EasyBuf) -> std::io::Result<Option<Self::In>> {
        if let Some(i) = buf.as_slice().iter().position(|&b| b == b'\n') {
            // remove the serialized frame from the buffer.
            let line = buf.drain_to(i);

            // Also remove the '\n'
            buf.drain_to(1);

            // Turn this data into a UTF string and
            // return it in a Frame.
            let maybe_req: Result<Self::In, serde_json::error::Error> =
                serde_json::from_slice(line.as_slice());
            match maybe_req {
                Ok(req) => Ok(Some(req)),
                Err(e) => {
                    println!("decode failed: {}", e);
                    Err(std::io::Error::new(std::io::ErrorKind::Other, e.description()))
                }
            }
        } else {
            Ok(None)
        }
    }

    fn encode(&mut self, msg: Self::Out, buf: &mut Vec<u8>) -> std::io::Result<()> {
        match serde_json::to_writer(buf, &msg) {
            Ok(_) => Ok(()),
            Err(e) => Err(std::io::Error::new(std::io::ErrorKind::Other, e.description())),
        }
    }
}

#[derive(Serialize, Deserialize)]
pub struct Envelope {
    // src: String,
    dst: String,
    topic: String,
    contents: Obj,
}

pub struct Agent {
    matches: Vec<runtime::Match>,
    st: runtime::State,
    receiver: mpsc::Receiver<Envelope>,
    match_index: usize,
}

impl Agent {
    pub fn new_from_file(path: &str, receiver: mpsc::Receiver<Envelope>) -> Result<Agent, Error> {
        let glop_contents = read_file(path)?;
        let glop = grammar::glop(&glop_contents).map_err(Error::Parse)?;
        let mut st = runtime::State::new();
        st.push_msg("init", Obj::new());
        let m_excs = glop.matches
            .iter()
            .map(|m_ast| runtime::Match::new_from_ast(&m_ast))
            .collect::<Vec<_>>();
        Ok(Agent {
            matches: m_excs,
            st: st,
            receiver: receiver,
            match_index: 0,
        })
    }
}

impl Agent {
    fn poll_matches(&mut self) -> futures::Poll<Option<()>, runtime::Error> {
        let i = self.match_index % self.matches.len();
        let m = &self.matches[i];
        let actions = match self.st.eval(m) {
            Some(ref mut txn) => {
                match txn.apply(m) {
                    Ok(actions) => actions,
                    Err(e) => return Err(e),
                }
            }
            None => {
                return Ok(futures::Async::NotReady);
            }
        };
        // TODO: intelligent selection of next match?
        self.match_index = self.match_index + 1;
        // TODO: graceful agent termination (nothing left to do)?
        match self.st.commit(&actions) {
            Ok(_) => Ok(futures::Async::Ready(Some(()))),
            Err(e) => Err(e),
        }
    }
}

impl futures::stream::Stream for Agent {
    type Item = ();
    type Error = runtime::Error;

    fn poll(&mut self) -> futures::Poll<Option<Self::Item>, Self::Error> {
        // TODO: poll mpsc channel (receiver end) for state changes & apply?
        match self.receiver.poll() {
            Ok(futures::Async::Ready(Some(env))) => self.st.push_msg(&env.topic, env.contents),
            Ok(futures::Async::Ready(None)) => return Ok(futures::Async::Ready(None)),
            Ok(futures::Async::NotReady) => {}
            Err(_) => return Ok(futures::Async::Ready(None)),
        }
        let result = self.poll_matches();
        std::thread::sleep(std::time::Duration::from_millis(100));
        result
    }
}

fn read_file(path: &str) -> Result<String, Error> {
    let mut f = std::fs::File::open(path)?;
    let mut s = String::new();
    f.read_to_string(&mut s).map_err(Error::IO)?;
    Ok(s)
}

#[derive(Clone)]
pub struct Service {
    senders: Arc<Mutex<HashMap<String, mpsc::Sender<Envelope>>>>,
    handle: tokio_core::reactor::Handle,
    pool: futures_cpupool::CpuPool,
}

impl Service {
    pub fn new(h: &tokio_core::reactor::Handle) -> Service {
        Service {
            senders: Arc::new(Mutex::new(HashMap::new())),
            handle: h.clone(),
            pool: futures_cpupool::CpuPool::new_num_cpus(),
        }
    }

    fn do_call(&self, req: Request) -> Result<Response, runtime::Error> {
        let mut senders = self.senders.lock().unwrap();
        let res = match req {
            Request::Add { source: ref add_source, name: ref add_name } => {
                let (sender, receiver) = mpsc::channel(10);
                senders.insert(add_name.clone(), sender);
                let agent =
                    Agent::new_from_file(add_source, receiver).map_err(runtime::Error::Base)?;
                self.handle.spawn(self.pool
                    .spawn(agent.for_each(|_| Ok(()))
                        .or_else(|e| {
                            println!("{}", e);
                            Err(e)
                        })
                        .then(|_| Ok(()))));
                Response::Add
            }
            Request::Remove { ref name } => {
                senders.remove(name);
                Response::Remove
            }
            Request::List => Response::List { names: senders.keys().cloned().collect() },
            Request::SendTo(env) => {
                let sender = match senders.get(&env.dst) {
                    Some(s) => s.clone(),
                    None => return Ok(Response::SendTo), // TODO: handle unmatched dst
                };
                self.handle.spawn(sender.send(env).then(|_| Ok(())));
                Response::SendTo
            }
            // RecvFrom { handle: String },
            // Introduce { names: Vec<String> },
        };
        Ok(res)
    }
}

impl TokioService for Service {
    type Request = Request;
    type Response = Response;

    type Error = std::io::Error;

    type Future = futures::BoxFuture<Self::Response, Self::Error>;

    fn call(&self, req: Self::Request) -> Self::Future {
        match self.do_call(req) {
            Ok(res) => futures::future::ok(res).boxed(),
            Err(err) => {
                futures::future::err(std::io::Error::new(std::io::ErrorKind::Other,
                                                         err.description()))
                    .boxed()
            }
        }
    }
}

pub fn run_server() -> Result<(), std::io::Error> {
    let mut core = tokio_core::reactor::Core::new()?;
    let handle = core.handle();
    let addr = "127.0.0.1:0".parse().unwrap();
    let listener = tokio_core::net::TcpListener::bind(&addr, &handle)?;
    let listen_addr = &listener.local_addr()?;
    println!("{}", listen_addr);
    let connections = listener.incoming();
    let service = Service::new(&handle);
    let server = connections.for_each(move |(socket, _peer_addr)| {
        let (wr, rd) = socket.framed(Codec).split();
        let service = service.clone();
        let responses = rd.and_then(move |req| service.call(req));
        let responder = wr.send_all(responses)
            .or_else(|e| {
                println!("{}", e);
                Err(e)
            })
            .then(|_| Ok(()));
        handle.spawn(responder);
        Ok(())
    });
    core.run(server)
}
<|endoftext|>


<commit_before>
use npyffi;
use pyffi;
use cpython::*;
use npyffi::PyArrayModule;
use super::*;

pub struct PyArray(PyObject);

impl PyArray {
    pub fn as_ptr(&self) -> *mut npyffi::PyArrayObject {
        self.0.as_ptr() as *mut npyffi::PyArrayObject
    }

    pub fn steal_ptr(self) -> *mut npyffi::PyArrayObject {
        self.0.steal_ptr() as *mut npyffi::PyArrayObject
    }

    pub unsafe fn from_owned_ptr(py: Python, ptr: *mut pyffi::PyObject) -> Self {
        let obj = PyObject::from_owned_ptr(py, ptr);
        PyArray(obj)
    }

    pub unsafe fn from_borrowed_ptr(py: Python, ptr: *mut pyffi::PyObject) -> Self {
        let obj = PyObject::from_borrowed_ptr(py, ptr);
        PyArray(obj)
    }

    /// The number of dimensions in the array
    /// https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_NDIM
    pub fn ndim(&self) -> usize {
        let ptr = self.as_ptr();
        unsafe { (*ptr).nd as usize }
    }

    /// dimensions of the array
    /// https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_DIMS
    pub fn dims(&self) -> Vec<usize> {
        let n = self.ndim();
        let ptr = self.as_ptr();
        let dims = unsafe {
            let p = (*ptr).dimensions;
            ::std::slice::from_raw_parts(p, n)
        };
        dims.into_iter().map(|d| *d as usize).collect()
    }

    pub fn len(&self) -> usize {
        self.dims().iter().fold(1, |a, b| a * b)
    }

    /// A synonym for PyArray_DIMS, named to be consistent with the ‘shape’ usage within Python.
    pub fn shape(&self) -> Vec<usize> {
        self.dims()
    }

    /// The number of elements matches the number of dimensions of the array
    /// https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_STRIDES
    /// For the explaination of stride, see also https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.strides.html#numpy.ndarray.strides
    pub fn strides(&self) -> Vec<isize> {
        let n = self.ndim();
        let ptr = self.as_ptr();
        let dims = unsafe {
            let p = (*ptr).strides;
            ::std::slice::from_raw_parts(p, n)
        };
        dims.into_iter().map(|d| *d as isize).collect()
    }

    /// Get data as a Rust immutable slice
    pub fn as_slice<T>(&self) -> &[T] {
        let n = self.len();
        let ptr = self.as_ptr();
        unsafe {
            let p = (*ptr).data as *mut T;
            ::std::slice::from_raw_parts(p, n)
        }
    }

    /// Get data as a Rust mutable slice
    pub fn as_slice_mut<T>(&mut self) -> &mut [T] {
        let n = self.len();
        let ptr = self.as_ptr();
        unsafe {
            let p = (*ptr).data as *mut T;
            ::std::slice::from_raw_parts_mut(p, n)
        }
    }

    /// a wrapper of PyArray_SimpleNew
    /// https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_SimpleNew
    pub fn new(py: Python, np: &PyArrayModule, dims: &[usize], typenum: NPY_TYPES) -> Self {
        let dims: Vec<npy_intp> = dims.iter().map(|d| *d as npy_intp).collect();
        unsafe {
            let ptr = np.PyArray_New(np.get_type_object(npyffi::ArrayType::PyArray_Type),
                                     dims.len() as i32,
                                     dims.as_ptr() as *mut npy_intp,
                                     typenum as i32,
                                     ::std::ptr::null_mut(),
                                     ::std::ptr::null_mut(),
                                     0,
                                     0,
                                     ::std::ptr::null_mut());
            Self::from_owned_ptr(py, ptr)
        }
    }

    /// a wrapper of PyArray_ZEROS
    /// https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_ZEROS
    pub fn zeros(py: Python,
                 np: &PyArrayModule,
                 dims: &[usize],
                 typenum: NPY_TYPES,
                 order: NPY_ORDER)
                 -> Self {
        let dims: Vec<npy_intp> = dims.iter().map(|d| *d as npy_intp).collect();
        unsafe {
            let descr = np.PyArray_DescrFromType(typenum as i32);
            let ptr = np.PyArray_Zeros(dims.len() as i32,
                                       dims.as_ptr() as *mut npy_intp,
                                       descr,
                                       order as i32);
            Self::from_owned_ptr(py, ptr)
        }
    }

    /// a wrapper of PyArray_Arange
    /// https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_Arange
    pub fn arange(py: Python,
                  np: &PyArrayModule,
                  start: f64,
                  stop: f64,
                  step: f64,
                  typenum: NPY_TYPES)
                  -> Self {
        unsafe {
            let ptr = np.PyArray_Arange(start, stop, step, typenum as i32);
            Self::from_owned_ptr(py, ptr)
        }
    }
}

impl ToPyObject for PyArray {
    type ObjectType = Self;

    fn to_py_object(&self, py: Python) -> Self {
        PyClone::clone_ref(self, py)
    }
}

impl PythonObject for PyArray {
    #[inline]
    fn as_object(&self) -> &PyObject {
        &self.0
    }

    #[inline]
    fn into_object(self) -> PyObject {
        self.0
    }

    #[inline]
    unsafe fn unchecked_downcast_from(obj: PyObject) -> Self {
        PyArray(obj)
    }

    #[inline]
    unsafe fn unchecked_downcast_borrow_from<'a>(obj: &'a PyObject) -> &'a Self {
        ::std::mem::transmute(obj)
    }
}

impl PythonObjectWithCheckedDowncast for PyArray {
    fn downcast_from<'p>(py: Python<'p>,
                         obj: PyObject)
                         -> Result<PyArray, PythonObjectDowncastError<'p>> {
        let np = PyArrayModule::import(py).unwrap();
        unsafe {
            if npyffi::PyArray_Check(&np, obj.as_ptr()) != 0 {
                Ok(PyArray(obj))
            } else {
                Err(PythonObjectDowncastError(py))
            }
        }
    }

    fn downcast_borrow_from<'a, 'p>(py: Python<'p>,
                                    obj: &'a PyObject)
                                    -> Result<&'a PyArray, PythonObjectDowncastError<'p>> {
        let np = PyArrayModule::import(py).unwrap();
        unsafe {
            if npyffi::PyArray_Check(&np, obj.as_ptr()) != 0 {
                Ok(::std::mem::transmute(obj))
            } else {
                Err(PythonObjectDowncastError(py))
            }
        }
    }
}
<commit_msg>Update document of numpy::array<commit_after>//! Untyped safe interface for NumPy ndarray

use npyffi;
use pyffi;
use cpython::*;
use npyffi::PyArrayModule;
use super::*;

/// Untyped safe interface for NumPy ndarray.
pub struct PyArray(PyObject);

impl PyArray {
    pub fn as_ptr(&self) -> *mut npyffi::PyArrayObject {
        self.0.as_ptr() as *mut npyffi::PyArrayObject
    }

    pub fn steal_ptr(self) -> *mut npyffi::PyArrayObject {
        self.0.steal_ptr() as *mut npyffi::PyArrayObject
    }

    pub unsafe fn from_owned_ptr(py: Python, ptr: *mut pyffi::PyObject) -> Self {
        let obj = PyObject::from_owned_ptr(py, ptr);
        PyArray(obj)
    }

    pub unsafe fn from_borrowed_ptr(py: Python, ptr: *mut pyffi::PyObject) -> Self {
        let obj = PyObject::from_borrowed_ptr(py, ptr);
        PyArray(obj)
    }

    /// The number of dimensions in the array
    ///
    /// https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_NDIM
    pub fn ndim(&self) -> usize {
        let ptr = self.as_ptr();
        unsafe { (*ptr).nd as usize }
    }

    /// dimensions of the array
    ///
    /// https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_DIMS
    pub fn dims(&self) -> Vec<usize> {
        let n = self.ndim();
        let ptr = self.as_ptr();
        let dims = unsafe {
            let p = (*ptr).dimensions;
            ::std::slice::from_raw_parts(p, n)
        };
        dims.into_iter().map(|d| *d as usize).collect()
    }

    pub fn len(&self) -> usize {
        self.dims().iter().fold(1, |a, b| a * b)
    }

    /// A synonym for PyArray_DIMS, named to be consistent with the ‘shape’ usage within Python.
    pub fn shape(&self) -> Vec<usize> {
        self.dims()
    }

    /// The number of elements matches the number of dimensions of the array
    ///
    /// - https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_STRIDES
    /// - https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.strides.html#numpy.ndarray.strides
    pub fn strides(&self) -> Vec<isize> {
        let n = self.ndim();
        let ptr = self.as_ptr();
        let dims = unsafe {
            let p = (*ptr).strides;
            ::std::slice::from_raw_parts(p, n)
        };
        dims.into_iter().map(|d| *d as isize).collect()
    }

    /// Get data as a Rust immutable slice
    pub fn as_slice<T>(&self) -> &[T] {
        let n = self.len();
        let ptr = self.as_ptr();
        unsafe {
            let p = (*ptr).data as *mut T;
            ::std::slice::from_raw_parts(p, n)
        }
    }

    /// Get data as a Rust mutable slice
    pub fn as_slice_mut<T>(&mut self) -> &mut [T] {
        let n = self.len();
        let ptr = self.as_ptr();
        unsafe {
            let p = (*ptr).data as *mut T;
            ::std::slice::from_raw_parts_mut(p, n)
        }
    }

    /// a wrapper of [PyArray_SimpleNew](https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_SimpleNew)
    pub fn new(py: Python, np: &PyArrayModule, dims: &[usize], typenum: NPY_TYPES) -> Self {
        let dims: Vec<npy_intp> = dims.iter().map(|d| *d as npy_intp).collect();
        unsafe {
            let ptr = np.PyArray_New(np.get_type_object(npyffi::ArrayType::PyArray_Type),
                                     dims.len() as i32,
                                     dims.as_ptr() as *mut npy_intp,
                                     typenum as i32,
                                     ::std::ptr::null_mut(),
                                     ::std::ptr::null_mut(),
                                     0,
                                     0,
                                     ::std::ptr::null_mut());
            Self::from_owned_ptr(py, ptr)
        }
    }

    /// a wrapper of [PyArray_ZEROS](https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_ZEROS)
    pub fn zeros(py: Python,
                 np: &PyArrayModule,
                 dims: &[usize],
                 typenum: NPY_TYPES,
                 order: NPY_ORDER)
                 -> Self {
        let dims: Vec<npy_intp> = dims.iter().map(|d| *d as npy_intp).collect();
        unsafe {
            let descr = np.PyArray_DescrFromType(typenum as i32);
            let ptr = np.PyArray_Zeros(dims.len() as i32,
                                       dims.as_ptr() as *mut npy_intp,
                                       descr,
                                       order as i32);
            Self::from_owned_ptr(py, ptr)
        }
    }

    /// a wrapper of [PyArray_Arange](https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_Arange)
    pub fn arange(py: Python,
                  np: &PyArrayModule,
                  start: f64,
                  stop: f64,
                  step: f64,
                  typenum: NPY_TYPES)
                  -> Self {
        unsafe {
            let ptr = np.PyArray_Arange(start, stop, step, typenum as i32);
            Self::from_owned_ptr(py, ptr)
        }
    }
}

impl ToPyObject for PyArray {
    type ObjectType = Self;

    fn to_py_object(&self, py: Python) -> Self {
        PyClone::clone_ref(self, py)
    }
}

impl PythonObject for PyArray {
    #[inline]
    fn as_object(&self) -> &PyObject {
        &self.0
    }

    #[inline]
    fn into_object(self) -> PyObject {
        self.0
    }

    #[inline]
    unsafe fn unchecked_downcast_from(obj: PyObject) -> Self {
        PyArray(obj)
    }

    #[inline]
    unsafe fn unchecked_downcast_borrow_from<'a>(obj: &'a PyObject) -> &'a Self {
        ::std::mem::transmute(obj)
    }
}

impl PythonObjectWithCheckedDowncast for PyArray {
    fn downcast_from<'p>(py: Python<'p>,
                         obj: PyObject)
                         -> Result<PyArray, PythonObjectDowncastError<'p>> {
        let np = PyArrayModule::import(py).unwrap();
        unsafe {
            if npyffi::PyArray_Check(&np, obj.as_ptr()) != 0 {
                Ok(PyArray(obj))
            } else {
                Err(PythonObjectDowncastError(py))
            }
        }
    }

    fn downcast_borrow_from<'a, 'p>(py: Python<'p>,
                                    obj: &'a PyObject)
                                    -> Result<&'a PyArray, PythonObjectDowncastError<'p>> {
        let np = PyArrayModule::import(py).unwrap();
        unsafe {
            if npyffi::PyArray_Check(&np, obj.as_ptr()) != 0 {
                Ok(::std::mem::transmute(obj))
            } else {
                Err(PythonObjectDowncastError(py))
            }
        }
    }
}
<|endoftext|>


<commit_before>//! This module implements a simple asset loader and cache.
//!
//! While ggez offers functions to load raw game assets such as
//! music files, images, etc, it provides no facilities for managing
//! them.  Ideally you want to load all the assets you need at once,
//! hold on to them for a time (the course of a level for instance),
//! and then potentially ditch the ones you don't need.
//! This module offers cache-like functionality to do exactly this.
//!
//! It will return an `Rc` containing the item loaded, so multiple
//! items can safely access (read-only) instances of the same asset.

// TODO: This is not thread safe; should we offer one that it?

use std::collections::BTreeMap;
use std::rc::Rc;
use std::boxed::Box;

pub struct AssetCache<K,V>
    where K: Ord + Clone {
    contents: BTreeMap<K,Rc<V>>,
    loader: Box<FnMut(&K) -> V>,
}

impl<K,V> AssetCache<K,V>
    where K: Ord + Clone {
    /// Creates a new `AssetCache` that loads assets
    /// when necessary with the given loader function.
    pub fn new(loaderfunc: Box<FnMut(&K) -> V>) -> Self {
        let map = BTreeMap::new();
        AssetCache {
            contents: map,
            loader: loaderfunc,
        }
    }

    /// Gets the given asset, loading it if necessary.
    pub fn get(&mut self, key: &K) -> Rc<V> {
        let loader = &mut self.loader;
        let f = || {
            let item = loader(key);
            Rc::new(item)
        };
        let entry = self.contents.entry(key.clone());
        //let loader = self.loader;
        entry.or_insert_with(f).clone()
    }

    /// Removes all assets from the cache
    /// and frees any excess memory it uses.
    pub fn clear(&mut self) {
        let map = BTreeMap::new();
        self.contents = map;
    }

    /// Returns true if the given asset is loaded.
    pub fn loaded(&self, key: &K) -> bool {
        self.contents.contains_key(key)
    }

    /// Takes a slice containing a list of keys,
    /// and loads all the keys so that their objects
    /// are immediately accessible.
    pub fn preload(&mut self, keys: &[K]) {
        for k in keys {
            let _ = self.get(k);
        }
    }
}

mod tests {
    use super::AssetCache;

    // It would be nice to get rid of the double references here somehow,
    // but then AssetCache ends up with a type of <str, String>
    // and `str` is not sized so it always has to involve a reference.
    #[test]
    fn test_assetcache() {
        //let mut loaderState = 0;
        let loader = |s: &&str| {
            //loaderState += 1;
            match *s {
                "foo" => "FooBaz".to_owned(),
                "bar" => "BarBaz".to_owned(),
                _ => "Something else".to_owned(),
            }
        };

        let mut a = AssetCache::new(Box::new(loader));
        assert!(!a.loaded(&"foo"));
        let s1 = a.get(&"foo");
        assert_eq!(*s1, "FooBaz".to_owned());
        assert!(a.loaded(&"foo"));
    }
}
<commit_msg>Added another variant of AssetCache...<commit_after>//! This module implements a simple asset loader and cache.
//!
//! While ggez offers functions to load raw game assets such as
//! music files, images, etc, it provides no facilities for managing
//! them.  Ideally you want to load all the assets you need at once,
//! hold on to them for a time (the course of a level for instance),
//! and then potentially ditch the ones you don't need.
//! This module offers cache-like functionality to do exactly this.
//!
//! It will return an `Rc` containing the item loaded, so multiple
//! items can safely access (read-only) instances of the same asset.

// TODO: This is not thread safe; should we offer one that it?

use std::collections::BTreeMap;
use std::rc::Rc;
use std::boxed::Box;

pub struct AssetCache<K,V>
    where K: Ord + Clone {
    contents: BTreeMap<K,Rc<V>>,
    loader: Box<FnMut(&K) -> V>,
}

impl<K,V> AssetCache<K,V>
    where K: Ord + Clone {
    /// Creates a new `AssetCache` that loads assets
    /// when necessary with the given loader function.
    pub fn new(loaderfunc: Box<FnMut(&K) -> V>) -> Self {
        let map = BTreeMap::new();
        AssetCache {
            contents: map,
            loader: loaderfunc,
        }
    }

    /// Gets the given asset, loading it if necessary.
    pub fn get(&mut self, key: &K) -> Rc<V> {
        let loader = &mut self.loader;
        let f = || {
            let item = loader(key);
            Rc::new(item)
        };
        let entry = self.contents.entry(key.clone());
        //let loader = self.loader;
        entry.or_insert_with(f).clone()
    }

    /// Removes all assets from the cache
    /// and frees any excess memory it uses.
    pub fn clear(&mut self) {
        let map = BTreeMap::new();
        self.contents = map;
    }

    /// Returns true if the given asset is loaded.
    pub fn loaded(&self, key: &K) -> bool {
        self.contents.contains_key(key)
    }

    /// Takes a slice containing a list of keys,
    /// and loads all the keys so that their objects
    /// are immediately accessible.
    pub fn preload(&mut self, keys: &[K]) {
        for k in keys {
            let _ = self.get(k);
        }
    }
}

pub struct StatefulAssetCache<K,V,S>
    where K: Ord + Clone {
    contents: BTreeMap<K,Rc<V>>,
    loader: fn(&K, &mut S) -> V,
    state: S,
}

impl<K,V,S> StatefulAssetCache<K,V,S>
    where K: Ord + Clone {
    /// Creates a new `AssetCache` that loads assets
    /// when necessary with the given loader function.
    pub fn new(loaderfunc: fn(&K, &mut S) -> V, state: S) -> Self {
        let map = BTreeMap::new();
        StatefulAssetCache {
            contents: map,
            loader: loaderfunc,
            state: state,
        }
    }

    /// Gets the given asset, loading it if necessary.
    pub fn get(&mut self, key: &K) -> Rc<V> {
        let loader = self.loader;
        let state = &mut self.state;
        let f = || {
            let item = loader(key, state);
            Rc::new(item)
        };
        let entry = self.contents.entry(key.clone());
        //let loader = self.loader;
        entry.or_insert_with(f).clone()
    }

    /// Removes all assets from the cache
    /// and frees any excess memory it uses.
    pub fn clear(&mut self) {
        let map = BTreeMap::new();
        self.contents = map;
    }

    /// Returns true if the given asset is loaded.
    pub fn loaded(&self, key: &K) -> bool {
        self.contents.contains_key(key)
    }

    /// Takes a slice containing a list of keys,
    /// and loads all the keys so that their objects
    /// are immediately accessible.
    pub fn preload(&mut self, keys: &[K]) {
        for k in keys {
            let _ = self.get(k);
        }
    }
}

mod tests {
    use super::*;

    // It would be nice to get rid of the double references here somehow,
    // but then AssetCache ends up with a type of <str, String>
    // and `str` is not sized so it always has to involve a reference.
    #[test]
    fn test_assetcache() {
        //let mut loaderState = 0;
        let loader = |s: &&str| {
            //loaderState += 1;
            match *s {
                "foo" => "FooBaz".to_owned(),
                "bar" => "BarBaz".to_owned(),
                _ => "Something else".to_owned(),
            }
        };

        let mut a = AssetCache::new(Box::new(loader));
        assert!(!a.loaded(&"foo"));
        let s1 = a.get(&"foo");
        assert_eq!(*s1, "FooBaz".to_owned());
        assert!(a.loaded(&"foo"));
    }

    #[test]
    fn test_stateful_assetcache() {
        fn loader(s: &&str, loaderinfo: &mut u32) -> String {
            *loaderinfo += 1;
            match *s {
                "foo" => "FooBaz".to_owned(),
                "bar" => "BarBaz".to_owned(),
                _ => "Something else".to_owned(),
            }
        }

        let mut a = StatefulAssetCache::new(loader, 0);
        assert!(!a.loaded(&"foo"));
        let s1 = a.get(&"foo");
        assert_eq!(*s1, "FooBaz".to_owned());
        assert!(a.loaded(&"foo"));
    }

}
<|endoftext|>


<commit_before>//! This module contains utilities for turning SyntaxNodes and HIR types
//! into types that may be used to render in a UI.

mod navigation_target;
mod short_label;

use syntax::{
    ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner},
    SyntaxKind::{ATTR, COMMENT},
};

use ast::VisibilityOwner;
use stdx::format_to;

pub use navigation_target::NavigationTarget;
pub(crate) use navigation_target::{ToNav, TryToNav};
pub(crate) use short_label::ShortLabel;

pub(crate) fn function_declaration(node: &ast::Fn) -> String {
    let mut buf = String::new();
    if let Some(vis) = node.visibility() {
        format_to!(buf, "{} ", vis);
    }
    if node.async_token().is_some() {
        format_to!(buf, "async ");
    }
    if node.const_token().is_some() {
        format_to!(buf, "const ");
    }
    if node.unsafe_token().is_some() {
        format_to!(buf, "unsafe ");
    }
    if let Some(abi) = node.abi() {
        // Keyword `extern` is included in the string.
        format_to!(buf, "{} ", abi);
    }
    if let Some(name) = node.name() {
        format_to!(buf, "fn {}", name)
    }
    if let Some(type_params) = node.generic_param_list() {
        format_to!(buf, "{}", type_params);
    }
    if let Some(param_list) = node.param_list() {
        let mut params = match param_list.self_param() {
            Some(self_param) => vec![self_param.to_string()],
            None => vec![],
        };
        params.extend(param_list.params().map(|param| param.to_string()));
        // Useful to inline parameters
        format_to!(buf, "({})", params.join(", "));
    }
    if let Some(ret_type) = node.ret_type() {
        if ret_type.ty().is_some() {
            format_to!(buf, " {}", ret_type);
        }
    }
    if let Some(where_clause) = node.where_clause() {
        format_to!(buf, "\n{}", where_clause);
    }
    buf
}

pub(crate) fn const_label(node: &ast::Const) -> String {
    let label: String = node
        .syntax()
        .children_with_tokens()
        .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR))
        .map(|node| node.to_string())
        .collect();

    label.trim().to_owned()
}

pub(crate) fn type_label(node: &ast::TypeAlias) -> String {
    let label: String = node
        .syntax()
        .children_with_tokens()
        .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR))
        .map(|node| node.to_string())
        .collect();

    label.trim().to_owned()
}

pub(crate) fn macro_label(node: &ast::MacroCall) -> String {
    let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default();
    let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" };
    format!("{}macro_rules! {}", vis, name)
}
<commit_msg>inline parameters for a function description #6002<commit_after>//! This module contains utilities for turning SyntaxNodes and HIR types
//! into types that may be used to render in a UI.

mod navigation_target;
mod short_label;

use syntax::{
    ast::{self, AstNode, AttrsOwner, GenericParamsOwner, NameOwner},
    SyntaxKind::{ATTR, COMMENT},
};

use ast::VisibilityOwner;
use stdx::format_to;

pub use navigation_target::NavigationTarget;
pub(crate) use navigation_target::{ToNav, TryToNav};
pub(crate) use short_label::ShortLabel;

pub(crate) fn function_declaration(node: &ast::Fn) -> String {
    let mut buf = String::new();
    if let Some(vis) = node.visibility() {
        format_to!(buf, "{} ", vis);
    }
    if node.async_token().is_some() {
        format_to!(buf, "async ");
    }
    if node.const_token().is_some() {
        format_to!(buf, "const ");
    }
    if node.unsafe_token().is_some() {
        format_to!(buf, "unsafe ");
    }
    if let Some(abi) = node.abi() {
        // Keyword `extern` is included in the string.
        format_to!(buf, "{} ", abi);
    }
    if let Some(name) = node.name() {
        format_to!(buf, "fn {}", name)
    }
    if let Some(type_params) = node.generic_param_list() {
        format_to!(buf, "{}", type_params);
    }
    if let Some(param_list) = node.param_list() {
        let params: Vec<String> = param_list
            .self_param()
            .into_iter()
            .map(|self_param| self_param.to_string())
            .chain(param_list.params().map(|param| param.to_string()))
            .collect();
        // Useful to inline parameters
        format_to!(buf, "({})", params.join(", "));
    }
    if let Some(ret_type) = node.ret_type() {
        if ret_type.ty().is_some() {
            format_to!(buf, " {}", ret_type);
        }
    }
    if let Some(where_clause) = node.where_clause() {
        format_to!(buf, "\n{}", where_clause);
    }
    buf
}

pub(crate) fn const_label(node: &ast::Const) -> String {
    let label: String = node
        .syntax()
        .children_with_tokens()
        .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR))
        .map(|node| node.to_string())
        .collect();

    label.trim().to_owned()
}

pub(crate) fn type_label(node: &ast::TypeAlias) -> String {
    let label: String = node
        .syntax()
        .children_with_tokens()
        .filter(|child| !(child.kind() == COMMENT || child.kind() == ATTR))
        .map(|node| node.to_string())
        .collect();

    label.trim().to_owned()
}

pub(crate) fn macro_label(node: &ast::MacroCall) -> String {
    let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default();
    let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" };
    format!("{}macro_rules! {}", vis, name)
}
<|endoftext|>


<commit_before>//! This module implements a simple asset loader and cache.
//!
//! While ggez offers functions to load raw game assets such as
//! music files, images, etc, it provides no facilities for managing
//! them.  Ideally you want to load all the assets you need at once,
//! hold on to them for a time (the course of a level for instance),
//! and then potentially ditch the ones you don't need.
//! This module offers cache-like functionality to do exactly this.
//!
//! It will return an `Rc` containing the item loaded, so multiple
//! items can safely access (read-only) instances of the same asset.

// TODO: This is not thread safe; should we offer one that it?
// TODO: Check out calx-resource:
// https://github.com/rsaarelm/calx/blob/master/calx-resource/src/lib.rs
// It has a) nifty macros to build these automatically,
// and b) an asset type that will serialize to a key, and then
// deserialize the key to that asset.  Very neat!  But also
// a bit labyrenthine.
// It DOES also make thread-safety work through thread_local!().

use std::collections::BTreeMap;
use std::path::Path;
use std::rc::Rc;
use ggez;
use ggez::{Context, GameError};
use ggez::graphics;

pub trait Loadable<K, E> {
    fn load(_key: &K) -> Result<Self, E> where Self: Sized;
}

pub trait StateLoadable<K, E, S> {
    fn load_state(_key: &K, &mut S) -> Result<Self, E> where Self: Sized;
}

pub struct AssetCache<K, V>
    where K: Ord + Clone
{
    contents: BTreeMap<K, Rc<V>>,
}

impl<K, V> AssetCache<K, V>
    where K: Ord + Clone
{
    /// Creates a new `AssetCache` that loads assets
    /// when necessary with the given loader function.
    pub fn new() -> Self {
        let map = BTreeMap::new();
        AssetCache { contents: map }
    }

    /// Gets the given asset, loading it if necessary.
    // Oh my goodness getting the E type param to the
    // right place was amazingly difficult.
    pub fn get<E>(&mut self, key: &K) -> Result<Rc<V>, E>
        where V: Loadable<K, E>
    {
        if let Some(v) = self.contents.get(key) {
            return Ok(v.clone());
        };

        let v = V::load(key)?;
        let v_rc = Rc::new(v);
        self.contents.insert(key.clone(), v_rc.clone());
        Ok(v_rc)
    }

    /// Gets the given asset, loading it if necessary.
    pub fn get_state<E, S>(&mut self, key: &K, state: &mut S) -> Result<Rc<V>, E>
        where V: StateLoadable<K, E, S>
    {
        if let Some(v) = self.contents.get(key) {
            return Ok(v.clone());
        };

        let v = V::load_state(key, state)?;
        let v_rc = Rc::new(v);
        self.contents.insert(key.clone(), v_rc.clone());
        Ok(v_rc)
    }

    /// Removes all assets from the cache
    /// and frees any excess memory it uses.
    pub fn clear(&mut self) {
        let map = BTreeMap::new();
        self.contents = map;
    }

    /// Returns true if the given asset is loaded.
    pub fn loaded(&self, key: &K) -> bool {
        self.contents.contains_key(key)
    }

    /// Takes a slice containing a list of keys,
    /// and loads all the keys so that their objects
    /// are immediately accessible.
    pub fn preload<E>(&mut self, keys: &[K])
        where V: Loadable<K, E>
    {
        for k in keys {
            let _ = self.get(k);
        }
    }
}

impl<'a, K: AsRef<Path>> StateLoadable<K, GameError, ggez::Context<'a>> for ggez::graphics::Image {
    fn load_state(key: &K, ctx: &mut Context<'a>) -> Result<Self, GameError> {
        graphics::Image::new(ctx, key)
    }
}

mod tests {
    use super::*;
    #[cfg(test)]
    impl<'a> Loadable<&'a str, ()> for String {
        fn load(key: &&str) -> Result<String, ()> {
            Ok(key.to_string())
        }
    }

    // It would be nice to get rid of the double references here somehow,
    // but then AssetCache ends up with a type of <str, String>
    // and `str` is not sized so it always has to involve a reference.
    #[test]
    fn test_assetcache() {
        let mut a = AssetCache::<&str, String>::new();
        assert!(!a.loaded(&"foo"));
        let s1 = a.get(&"foo").unwrap();
        assert_eq!(*s1, "foo");
        assert!(a.loaded(&"foo"));
    }

    impl<'a> StateLoadable<&'a str, (), i32> for String {
        fn load_state(key: &&str, state: &mut i32) -> Result<String, ()> {
            *state += 1;
            Ok(key.to_string())
        }
    }

    #[test]
    fn test_stateful_assetcache() {
        let mut a = AssetCache::<&str, String>::new();
        let s = &mut 10;
        assert!(!a.loaded(&"foo"));
        let s1 = a.get_state(&"foo", s).unwrap();
        assert_eq!(*s1, "foo");
        assert_eq!(*s, 11);
        assert!(a.loaded(&"foo"));
    }

}
<commit_msg>Added preloading functions to the asset cache.<commit_after>//! This module implements a simple asset loader and cache.
//!
//! While ggez offers functions to load raw game assets such as
//! music files, images, etc, it provides no facilities for managing
//! them.  Ideally you want to load all the assets you need at once,
//! hold on to them for a time (the course of a level for instance),
//! and then potentially ditch the ones you don't need.
//! This module offers cache-like functionality to do exactly this.
//!
//! It will return an `Rc` containing the item loaded, so multiple
//! items can safely access (read-only) instances of the same asset.

// TODO: This is not thread safe; should we offer one that it?
// TODO: Check out calx-resource:
// https://github.com/rsaarelm/calx/blob/master/calx-resource/src/lib.rs
// It has a) nifty macros to build these automatically,
// and b) an asset type that will serialize to a key, and then
// deserialize the key to that asset.  Very neat!  But also
// a bit labyrenthine.
// It DOES also make thread-safety work through thread_local!().

use std::collections::BTreeMap;
use std::fmt::Debug;
use std::path::Path;
use std::rc::Rc;
use ggez;
use ggez::{Context, GameError, GameResult};
use ggez::graphics;

pub trait Loadable<K, E> {
    fn load(_key: &K) -> Result<Self, E> where Self: Sized;
}

pub trait StateLoadable<K, E, S> {
    fn load_state(_key: &K, &mut S) -> Result<Self, E> where Self: Sized;
}

#[derive(Debug)]
pub struct AssetCache<K, V>
    where K: Ord + Clone + Debug
{
    contents: BTreeMap<K, Rc<V>>,
}

impl<K, V> AssetCache<K, V>
    where K: Ord + Clone + Debug
{
    /// Creates a new `AssetCache` that loads assets
    /// when necessary with the given loader function.
    pub fn new() -> Self {
        let map = BTreeMap::new();
        AssetCache { contents: map }
    }

    /// Gets the given asset, loading it if necessary.
    // Oh my goodness getting the E type param to the
    // right place was amazingly difficult.
    pub fn get<E>(&mut self, key: &K) -> Result<Rc<V>, E>
        where V: Loadable<K, E>
    {
        if let Some(v) = self.contents.get(key) {
            return Ok(v.clone());
        };

        let v = V::load(key)?;
        let v_rc = Rc::new(v);
        self.contents.insert(key.clone(), v_rc.clone());
        Ok(v_rc)
    }

    /// Gets the given asset, loading it if necessary.
    pub fn get_state<E, S>(&mut self, key: &K, state: &mut S) -> Result<Rc<V>, E>
        where V: StateLoadable<K, E, S>
    {
        if let Some(v) = self.contents.get(key) {
            return Ok(v.clone());
        };

        let v = V::load_state(key, state)?;
        let v_rc = Rc::new(v);
        self.contents.insert(key.clone(), v_rc.clone());
        Ok(v_rc)
    }

    /// Removes all assets from the cache
    /// and frees any excess memory it uses.
    pub fn clear(&mut self) {
        let map = BTreeMap::new();
        self.contents = map;
    }

    /// Returns true if the given asset is loaded.
    pub fn loaded(&self, key: &K) -> bool {
        self.contents.contains_key(key)
    }

    /// Takes a slice containing a list of keys,
    /// and loads all the keys so that their objects
    /// are immediately accessible.
    pub fn preload<E>(&mut self, keys: &[K])
        where V: Loadable<K, E>
    {
        for k in keys {
            let _ = self.get(k);
        }
    }

    /// Preloads objects that require a state to load.
    pub fn preload_state<E, S>(&mut self, keys: &[K], state: &mut S)
        where V: StateLoadable<K, E, S>
    {
        for k in keys {
            let _ = self.get_state(k, state);
        }
    }

    /// Gets an object but only if it already exists in the
    /// wossname.
    /// Returns an error if it is not.
    pub fn get_preload(&mut self, key: &K) -> GameResult<Rc<V>> {
        if let Some(val) = self.contents.get(key) {
            Ok(val.clone())
        } else {
            let errmsg = format!("Tried to get asset {:?} but it was not preloaded!", key);
            let err = GameError::ResourceNotFound(errmsg);
            Err(err)

        }
    }
}

impl<'a, K: AsRef<Path>> StateLoadable<K, GameError, ggez::Context<'a>> for ggez::graphics::Image {
    fn load_state(key: &K, ctx: &mut Context<'a>) -> GameResult<Self> {
        graphics::Image::new(ctx, key)
    }
}

mod tests {
    use super::*;
    #[cfg(test)]
    impl<'a> Loadable<&'a str, ()> for String {
        fn load(key: &&str) -> Result<String, ()> {
            Ok(key.to_string())
        }
    }

    // It would be nice to get rid of the double references here somehow,
    // but then AssetCache ends up with a type of <str, String>
    // and `str` is not sized so it always has to involve a reference.
    #[test]
    fn test_assetcache() {
        let mut a = AssetCache::<&str, String>::new();
        assert!(!a.loaded(&"foo"));
        let s1 = a.get(&"foo").unwrap();
        assert_eq!(*s1, "foo");
        assert!(a.loaded(&"foo"));
    }

    impl<'a> StateLoadable<&'a str, (), i32> for String {
        fn load_state(key: &&str, state: &mut i32) -> Result<String, ()> {
            *state += 1;
            Ok(key.to_string())
        }
    }

    #[test]
    fn test_stateful_assetcache() {
        let mut a = AssetCache::<&str, String>::new();
        let s = &mut 10;
        assert!(!a.loaded(&"foo"));
        let s1 = a.get_state(&"foo", s).unwrap();
        assert_eq!(*s1, "foo");
        assert_eq!(*s, 11);
        assert!(a.loaded(&"foo"));
    }

}
<|endoftext|>


<commit_before>/// A TOML [1] configuration file parser
///
/// [1]: https://github.com/mojombo/toml

use std::io::mem::MemReader;
use std::io::File;
use std::hashmap::HashMap;

fn read_char(rd: &mut MemReader) -> char {
  match rd.read_byte() {
    Some(b) => b as char,
    None => fail!()
  }
}

fn read_char_opt(rd: &mut MemReader) -> Option<char> {
  match rd.read_byte() {
    Some(b) => Some(b as char),
    None => None
  }
}

#[deriving(ToStr)]
enum Value {
    True,
    False,
    Unsigned(u64),
    Integer(i64),
    Float(f64),
    String(~str),
    Array(~[Value]),
    Datetime, // XXX
    Map(HashMap<~str, Value>) // XXX: This is no value
}

trait Visitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool;
    fn pair(&mut self, key: ~str, val: Value) -> bool;
}

struct TOMLVisitor {
    root: HashMap<~str, Value>,
    current_section: ~str,
    section_is_array: bool
}

impl TOMLVisitor {
    fn new() -> TOMLVisitor {
        TOMLVisitor { root: HashMap::new(), current_section: ~"", section_is_array: false }
    }
    fn get_root<'a>(&'a self) -> &'a HashMap<~str, Value> {
        return &self.root;
    }
}

impl Visitor for TOMLVisitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool {
        debug!("Section: {} (is_array={})", name, is_array);
        self.section_is_array = is_array;
        self.current_section = name;
        return true
    }
    fn pair(&mut self, key: ~str, val: Value) -> bool {
        debug!("Pair: {} {:s}", key, val.to_str());
        let mut m = self.root.find_or_insert(self.current_section.clone(), Map(HashMap::new())); // XXX: remove clone
        match *m {
            Map(ref mut map) => {
                let ok = map.insert(key, val);
                return ok
            }
            _ => { return false }
        }
    }
}

// parse values recursivly
fn parse_value(rd: &mut MemReader, current_char: Option<char>) -> (Option<Value>, Option<char>) {
    let mut current_char = skip_whitespaces(rd, current_char);

    if current_char.is_none() { return (None, current_char) }
    let ch = current_char.unwrap();
    match ch {
        '0' .. '9' => {
            let (num, ch) = read_token(rd, current_char, |ch| {
                match ch {
                    '0' .. '9' => true,
                    _ => false
                }
            });
            match from_str(num) {
              Some(n) => return (Some(Unsigned(n)), ch),
              None => return (None, ch)
            }
        }
        't' => {
            current_char = read_char_opt(rd);
            if current_char != Some('r') { return (None, current_char) }
            current_char = read_char_opt(rd);
            if current_char != Some('u') { return (None, current_char) }
            current_char = read_char_opt(rd);
            if current_char != Some('e') { return (None, current_char) }
            current_char = read_char_opt(rd);

            return (Some(True), current_char)
        }
        'f' => {
            current_char = read_char_opt(rd);
            if current_char != Some('a') { return (None, current_char) }
            current_char = read_char_opt(rd);
            if current_char != Some('l') { return (None, current_char) }
            current_char = read_char_opt(rd);
            if current_char != Some('s') { return (None, current_char) }
            current_char = read_char_opt(rd);
            if current_char != Some('e') { return (None, current_char) }
            current_char = read_char_opt(rd);

            return (Some(False), current_char)
        }
        '"' => {
            current_char = read_char_opt(rd);
            let (str, ch) = read_token(rd, current_char, |ch| {
                match ch {
                    '"' => false,
                    _ => true
                }
            });
            current_char = ch;

            if current_char != Some('"') { return (None, current_char) }
            current_char = read_char_opt(rd);
            return (Some(String(str)), current_char)
        }
        _ => { return (None, current_char) }
    }
}

// We must be already within the '#"
fn skip_comment(rd: &mut MemReader) {
    loop {
        if rd.eof() { return }
        match read_char(rd) {
            '\n' => { return }
            _ => { }
        }
    }
}

fn read_token(rd: &mut MemReader, current_char: Option<char>, f: |char| -> bool) -> (~str, Option<char>) {
    let mut current_char = current_char;
    let mut token = ~"";
    loop {
        match current_char {
            Some(ch) => {
                if f(ch) { token.push_char(ch) }
                else { break }
            }
            None => { break }
        }
        current_char = read_char_opt(rd); // advance
    }

    return (token, current_char);
}

fn parse_section_identifier(rd: &mut MemReader, current_char: Option<char>) -> (~str, Option<char>) {
    read_token(rd, current_char, |ch| {
        match ch {
            'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_' => true,
            _ => false
        }
    })
}

fn skip_whitespaces(rd: &mut MemReader, current_char: Option<char>) -> Option<char> {
    let mut current_char = current_char;
    loop {
        match current_char {
            Some(' ') | Some('\t') | Some('\r') | Some('\n') => {
                current_char = read_char_opt(rd); // advance
            }
            _ => { break }
        }
    }
    return current_char;
}

fn parse<V: Visitor>(rd: &mut MemReader, visitor: &mut V) -> bool {
    let mut current_char: Option<char> = read_char_opt(rd);

    loop {
        if current_char.is_none() { return true }
        let ch = current_char.unwrap();
        match ch {
            // ignore whitespace
            '\r' | '\n' | ' ' | '\t' => { }

            // comment
            '#' => {
                // skip to end of line
                loop {
                    current_char = read_char_opt(rd);
                    match current_char {
                        Some('\n') => { break }
                        None => { return true }
                        _ => { /* skip */ }
                    }
                }
            }

            // section
            '[' => {
                current_char = read_char_opt(rd); // advance
                let mut double_section = false;
                match current_char {
                    Some('[') => {
                        double_section = true;
                        current_char = read_char_opt(rd); // advance
                    }
                    _ => {}
                }

                let (section_name, ch) = parse_section_identifier(rd, current_char);
                current_char = ch;

                match current_char {
                    Some(']') => { /* ok */ }
                    _ => { return false }
                }

                if double_section {
                    current_char = read_char_opt(rd); // advance
                    if current_char != Some(']') { return false }
                }

                visitor.section(section_name, double_section);
            }

            // identifier
            'a' .. 'z' | 'A' .. 'Z' | '_' => {

                let (ident, ch) = read_token(rd, current_char, |ch| {
                    match ch {
                        'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' => true,
                        _ => false
                    }
                });

                current_char = ch;
                current_char = skip_whitespaces(rd, current_char);

                // assign wanted
                if current_char != Some('=') { return false }

                current_char = read_char_opt(rd); // advance
                let (val, ch) = parse_value(rd, current_char);
                current_char = ch;
                match val {
                  Some(v) => { visitor.pair(ident, v); }
                  None => { return false; }
                }
                continue; // do not advance!
            }

            _ => { return false }
        } /* end match */
        current_char = read_char_opt(rd); // advance
    }

    assert!(false);
}

fn main() {
  let contents = File::open(&Path::new(std::os::args()[1])).read_to_end();
  let mut rd = MemReader::new(contents);
  let mut visitor = TOMLVisitor::new();
  parse(&mut rd, &mut visitor);
  println!("{:s}", visitor.get_root().to_str());
}
<commit_msg>Remove dead code<commit_after>/// A TOML [1] configuration file parser
///
/// [1]: https://github.com/mojombo/toml

use std::io::mem::MemReader;
use std::io::File;
use std::hashmap::HashMap;

fn read_char_opt(rd: &mut MemReader) -> Option<char> {
  match rd.read_byte() {
    Some(b) => Some(b as char),
    None => None
  }
}

#[deriving(ToStr)]
enum Value {
    True,
    False,
    Unsigned(u64),
    Integer(i64),
    Float(f64),
    String(~str),
    Array(~[Value]),
    Datetime, // XXX
    Map(HashMap<~str, Value>) // XXX: This is no value
}

trait Visitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool;
    fn pair(&mut self, key: ~str, val: Value) -> bool;
}

struct TOMLVisitor {
    root: HashMap<~str, Value>,
    current_section: ~str,
    section_is_array: bool
}

impl TOMLVisitor {
    fn new() -> TOMLVisitor {
        TOMLVisitor { root: HashMap::new(), current_section: ~"", section_is_array: false }
    }
    fn get_root<'a>(&'a self) -> &'a HashMap<~str, Value> {
        return &self.root;
    }
}

impl Visitor for TOMLVisitor {
    fn section(&mut self, name: ~str, is_array: bool) -> bool {
        debug!("Section: {} (is_array={})", name, is_array);
        self.section_is_array = is_array;
        self.current_section = name;
        return true
    }
    fn pair(&mut self, key: ~str, val: Value) -> bool {
        debug!("Pair: {} {:s}", key, val.to_str());
        let mut m = self.root.find_or_insert(self.current_section.clone(), Map(HashMap::new())); // XXX: remove clone
        match *m {
            Map(ref mut map) => {
                let ok = map.insert(key, val);
                return ok
            }
            _ => { return false }
        }
    }
}

// parse values recursivly
fn parse_value(rd: &mut MemReader, current_char: Option<char>) -> (Option<Value>, Option<char>) {
    let mut current_char = skip_whitespaces(rd, current_char);

    if current_char.is_none() { return (None, current_char) }
    let ch = current_char.unwrap();
    match ch {
        '0' .. '9' => {
            let (num, ch) = read_token(rd, current_char, |ch| {
                match ch {
                    '0' .. '9' => true,
                    _ => false
                }
            });
            match from_str(num) {
              Some(n) => return (Some(Unsigned(n)), ch),
              None => return (None, ch)
            }
        }
        't' => {
            current_char = read_char_opt(rd);
            if current_char != Some('r') { return (None, current_char) }
            current_char = read_char_opt(rd);
            if current_char != Some('u') { return (None, current_char) }
            current_char = read_char_opt(rd);
            if current_char != Some('e') { return (None, current_char) }
            current_char = read_char_opt(rd);

            return (Some(True), current_char)
        }
        'f' => {
            current_char = read_char_opt(rd);
            if current_char != Some('a') { return (None, current_char) }
            current_char = read_char_opt(rd);
            if current_char != Some('l') { return (None, current_char) }
            current_char = read_char_opt(rd);
            if current_char != Some('s') { return (None, current_char) }
            current_char = read_char_opt(rd);
            if current_char != Some('e') { return (None, current_char) }
            current_char = read_char_opt(rd);

            return (Some(False), current_char)
        }
        '"' => {
            current_char = read_char_opt(rd);
            let (str, ch) = read_token(rd, current_char, |ch| {
                match ch {
                    '"' => false,
                    _ => true
                }
            });
            current_char = ch;

            if current_char != Some('"') { return (None, current_char) }
            current_char = read_char_opt(rd);
            return (Some(String(str)), current_char)
        }
        _ => { return (None, current_char) }
    }
}

fn read_token(rd: &mut MemReader, current_char: Option<char>, f: |char| -> bool) -> (~str, Option<char>) {
    let mut current_char = current_char;
    let mut token = ~"";
    loop {
        match current_char {
            Some(ch) => {
                if f(ch) { token.push_char(ch) }
                else { break }
            }
            None => { break }
        }
        current_char = read_char_opt(rd); // advance
    }

    return (token, current_char);
}

fn parse_section_identifier(rd: &mut MemReader, current_char: Option<char>) -> (~str, Option<char>) {
    read_token(rd, current_char, |ch| {
        match ch {
            'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '.' | '_' => true,
            _ => false
        }
    })
}

fn skip_whitespaces(rd: &mut MemReader, current_char: Option<char>) -> Option<char> {
    let mut current_char = current_char;
    loop {
        match current_char {
            Some(' ') | Some('\t') | Some('\r') | Some('\n') => {
                current_char = read_char_opt(rd); // advance
            }
            _ => { break }
        }
    }
    return current_char;
}

fn parse<V: Visitor>(rd: &mut MemReader, visitor: &mut V) -> bool {
    let mut current_char: Option<char> = read_char_opt(rd);

    loop {
        if current_char.is_none() { return true }
        let ch = current_char.unwrap();
        match ch {
            // ignore whitespace
            '\r' | '\n' | ' ' | '\t' => { }

            // comment
            '#' => {
                // skip to end of line
                loop {
                    current_char = read_char_opt(rd);
                    match current_char {
                        Some('\n') => { break }
                        None => { return true }
                        _ => { /* skip */ }
                    }
                }
            }

            // section
            '[' => {
                current_char = read_char_opt(rd); // advance
                let mut double_section = false;
                match current_char {
                    Some('[') => {
                        double_section = true;
                        current_char = read_char_opt(rd); // advance
                    }
                    _ => {}
                }

                let (section_name, ch) = parse_section_identifier(rd, current_char);
                current_char = ch;

                match current_char {
                    Some(']') => { /* ok */ }
                    _ => { return false }
                }

                if double_section {
                    current_char = read_char_opt(rd); // advance
                    if current_char != Some(']') { return false }
                }

                visitor.section(section_name, double_section);
            }

            // identifier
            'a' .. 'z' | 'A' .. 'Z' | '_' => {

                let (ident, ch) = read_token(rd, current_char, |ch| {
                    match ch {
                        'a' .. 'z' | 'A' .. 'Z' | '0' .. '9' | '_' => true,
                        _ => false
                    }
                });

                current_char = ch;
                current_char = skip_whitespaces(rd, current_char);

                // assign wanted
                if current_char != Some('=') { return false }

                current_char = read_char_opt(rd); // advance
                let (val, ch) = parse_value(rd, current_char);
                current_char = ch;
                match val {
                  Some(v) => { visitor.pair(ident, v); }
                  None => { return false; }
                }
                continue; // do not advance!
            }

            _ => { return false }
        } /* end match */
        current_char = read_char_opt(rd); // advance
    }

    assert!(false);
}

fn main() {
  let contents = File::open(&Path::new(std::os::args()[1])).read_to_end();
  let mut rd = MemReader::new(contents);
  let mut visitor = TOMLVisitor::new();
  parse(&mut rd, &mut visitor);
  println!("{:s}", visitor.get_root().to_str());
}
<|endoftext|>


<commit_before>//! Prepared statements cache for faster execution.

use std::cell::RefCell;
use std::collections::VecDeque;
use std::ops::{Deref, DerefMut};
use {Result, Connection, Statement};

/// Prepared statements cache.
#[derive(Debug)]
pub struct StatementCache<'conn> {
    conn: &'conn Connection,
    cache: VecDeque<Statement<'conn>>, // back = LRU
}

pub struct CachedStatement<'conn> {
    stmt: Option<Statement<'conn>>,
    cache: RefCell<StatementCache<'conn>>,
    pub cacheable: bool,
}

impl<'conn> Deref for CachedStatement<'conn> {
    type Target = Statement<'conn>;

    fn deref(&self) -> &Statement<'conn> {
        self.stmt.as_ref().unwrap()
    }
}

impl<'conn> DerefMut for CachedStatement<'conn> {
    fn deref_mut(&mut self) -> &mut Statement<'conn> {
        self.stmt.as_mut().unwrap()
    }
}

impl<'conn> Drop for CachedStatement<'conn> {
    #[allow(unused_must_use)]
    fn drop(&mut self) {
        if self.cacheable {
            self.cache.borrow_mut().release(self.stmt.take().unwrap());
        } else {
            self.stmt.take().unwrap().finalize();
        }
    }
}

impl<'conn> CachedStatement<'conn> {
    fn new(stmt: Statement<'conn>,
           cache: RefCell<StatementCache<'conn>>)
           -> CachedStatement<'conn> {
        CachedStatement {
            stmt: Some(stmt),
            cache: cache,
            cacheable: true,
        }
    }
}

impl<'conn> StatementCache<'conn> {
    /// Create a statement cache.
    pub fn new(conn: &'conn Connection, capacity: usize) -> StatementCache<'conn> {
        StatementCache {
            conn: conn,
            cache: VecDeque::with_capacity(capacity),
        }
    }

    /// Search the cache for a prepared-statement object that implements `sql`.
    // If no such prepared-statement can be found, allocate and prepare a new one.
    ///
    /// # Failure
    ///
    /// Will return `Err` if no cached statement can be found and the underlying SQLite prepare call fails.
    pub fn get(&mut self, sql: &str) -> Result<CachedStatement<'conn>> {
        let stmt = match self.cache.iter().rposition(|entry| entry.eq(sql)) {
            Some(index) => Ok(self.cache.swap_remove_front(index).unwrap()), // FIXME Not LRU compliant
            _ => self.conn.prepare(sql),
        };
        stmt.map(|stmt| CachedStatement::new(stmt, RefCell::new(self)))
    }

    /// If `discard` is true, then the statement is deleted immediately.
    /// Otherwise it is added to the LRU list and may be returned
    /// by a subsequent call to `get()`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `stmt` (or the already cached statement implementing the same SQL) statement is `discard`ed
    /// and the underlying SQLite finalize call fails.
    fn release(&mut self, mut stmt: Statement<'conn>) {
        if self.cache.capacity() == self.cache.len() {
            // is full
            self.cache.pop_back(); // LRU dropped
        }
        stmt.reset_if_needed();
        stmt.clear_bindings();
        self.cache.push_front(stmt)
    }

    /// Flush the prepared statement cache
    pub fn clear(&mut self) {
        self.cache.clear();
    }

    /// Return current cache size.
    pub fn len(&self) -> usize {
        self.cache.len()
    }

    /// Return maximum cache size.
    pub fn capacity(&self) -> usize {
        self.cache.capacity()
    }
}

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

    #[test]
    fn test_cache() {
        let db = Connection::open_in_memory().unwrap();
        let mut cache = StatementCache::new(&db, 15);
        assert_eq!(0, cache.len());
        assert_eq!(15, cache.capacity());

        let sql = "PRAGMA schema_version";
        let mut stmt = cache.get(sql).unwrap();
        assert_eq!(0, cache.len());
        assert_eq!(0,
                   stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));

        // println!("NEW {:?}", stmt);
        cache.release(stmt);
        assert_eq!(1, cache.len());

        stmt = cache.get(sql).unwrap();
        assert_eq!(0, cache.len());
        assert_eq!(0,
                   stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));

        // println!("CACHED {:?}", stmt);
        cache.release(stmt);
        assert_eq!(1, cache.len());

        cache.clear();
        assert_eq!(0, cache.len());
        assert_eq!(15, cache.capacity());
    }
}
<commit_msg>Still some lifetime problem...<commit_after>//! Prepared statements cache for faster execution.

use std::cell::RefCell;
use std::collections::VecDeque;
use std::ops::{Deref, DerefMut};
use {Result, Connection, Statement};

/// Prepared statements cache.
#[derive(Debug)]
pub struct StatementCache<'conn> {
    conn: &'conn Connection,
    cache: RefCell<VecDeque<Statement<'conn>>>, // back = LRU
}

pub struct CachedStatement<'conn> {
    stmt: Option<Statement<'conn>>,
    cache: &'conn StatementCache<'conn>,
    pub cacheable: bool,
}

impl<'conn> Deref for CachedStatement<'conn> {
    type Target = Statement<'conn>;

    fn deref(&self) -> &Statement<'conn> {
        self.stmt.as_ref().unwrap()
    }
}

impl<'conn> DerefMut for CachedStatement<'conn> {
    fn deref_mut(&mut self) -> &mut Statement<'conn> {
        self.stmt.as_mut().unwrap()
    }
}

impl<'conn> Drop for CachedStatement<'conn> {
    #[allow(unused_must_use)]
    fn drop(&mut self) {
        if self.cacheable {
            self.cache.release(self.stmt.take().unwrap());
        } else {
            self.stmt.take().unwrap().finalize();
        }
    }
}

impl<'conn> CachedStatement<'conn> {
    fn new(stmt: Statement<'conn>, cache: &'conn StatementCache<'conn>) -> CachedStatement<'conn> {
        CachedStatement {
            stmt: Some(stmt),
            cache: cache,
            cacheable: true,
        }
    }
}

impl<'conn> StatementCache<'conn> {
    /// Create a statement cache.
    pub fn new(conn: &'conn Connection, capacity: usize) -> StatementCache<'conn> {
        StatementCache {
            conn: conn,
            cache: RefCell::new(VecDeque::with_capacity(capacity)),
        }
    }

    /// Search the cache for a prepared-statement object that implements `sql`.
    // If no such prepared-statement can be found, allocate and prepare a new one.
    ///
    /// # Failure
    ///
    /// Will return `Err` if no cached statement can be found and the underlying SQLite prepare call fails.
    pub fn get(&'conn self, sql: &str) -> Result<CachedStatement<'conn>> {
        let stmt = match self.cache.borrow().iter().rposition(|entry| entry.eq(sql)) {
            Some(index) => Ok(self.cache.borrow_mut().swap_remove_front(index).unwrap()), // FIXME Not LRU compliant
            _ => self.conn.prepare(sql),
        };
        stmt.map(|stmt| CachedStatement::new(stmt, self))
    }

    /// If `discard` is true, then the statement is deleted immediately.
    /// Otherwise it is added to the LRU list and may be returned
    /// by a subsequent call to `get()`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `stmt` (or the already cached statement implementing the same SQL) statement is `discard`ed
    /// and the underlying SQLite finalize call fails.
    fn release(&self, mut stmt: Statement<'conn>) {
        if self.cache.borrow().capacity() == self.cache.borrow().len() {
            // is full
            self.cache.borrow_mut().pop_back(); // LRU dropped
        }
        stmt.reset_if_needed();
        stmt.clear_bindings();
        self.cache.borrow_mut().push_front(stmt)
    }

    /// Flush the prepared statement cache
    pub fn clear(&self) {
        self.cache.borrow_mut().clear();
    }

    /// Return current cache size.
    pub fn len(&self) -> usize {
        self.cache.borrow().len()
    }

    /// Return maximum cache size.
    pub fn capacity(&self) -> usize {
        self.cache.borrow().capacity()
    }
}

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

    #[test]
    fn test_cache() {
        let db = Connection::open_in_memory().unwrap();
        let mut cache = StatementCache::new(&db, 15);
        assert_eq!(0, cache.len());
        assert_eq!(15, cache.capacity());

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = cache.get(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));
        }
        assert_eq!(1, cache.len());

        {
            let mut stmt = cache.get(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i64>(0));
        }
        assert_eq!(1, cache.len());

        cache.clear();
        assert_eq!(0, cache.len());
        assert_eq!(15, cache.capacity());
    }
}
<|endoftext|>


<commit_before>use wlroots_sys::wlr_seat_pointer_request_set_cursor_event;

use {SeatClient, SurfaceHandle};

#[derive(Debug)]
pub struct SetCursorEvent {
    event: *mut wlr_seat_pointer_request_set_cursor_event
}

impl SetCursorEvent {
    pub(crate) unsafe fn from_ptr(event: *mut wlr_seat_pointer_request_set_cursor_event) -> Self {
        SetCursorEvent { event }
    }
    /// Get the seat client associated with the seat where this
    /// event is occurring.
    pub fn seat_client<'seat>(&'seat self) -> SeatClient<'seat> {
        unsafe { SeatClient::from_ptr((*self.event).seat_client) }
    }

    /// Get the surface that is providing the cursor to the seat.
    pub fn surface(&self) -> SurfaceHandle {
        unsafe { SurfaceHandle::from_ptr((*self.event).surface) }
    }

    pub fn serial(&self) -> u32 {
        unsafe { (*self.event).serial }
    }

    pub fn location(&self) -> (i32, i32) {
        unsafe { ((*self.event).hotspot_x, (*self.event).hotspot_y) }
    }
}
<commit_msg>allow null surface for client cursors<commit_after>use wlroots_sys::wlr_seat_pointer_request_set_cursor_event;

use {SeatClient, SurfaceHandle};

#[derive(Debug)]
pub struct SetCursorEvent {
    event: *mut wlr_seat_pointer_request_set_cursor_event
}

impl SetCursorEvent {
    pub(crate) unsafe fn from_ptr(event: *mut wlr_seat_pointer_request_set_cursor_event) -> Self {
        SetCursorEvent { event }
    }
    /// Get the seat client associated with the seat where this
    /// event is occurring.
    pub fn seat_client<'seat>(&'seat self) -> SeatClient<'seat> {
        unsafe { SeatClient::from_ptr((*self.event).seat_client) }
    }

    /// Get the surface that is providing the cursor to the seat.
    pub fn surface(&self) -> Option<SurfaceHandle> {
        unsafe {
            let surface = (*self.event).surface;
            if surface.is_null() {
                None
            } else {
                SurfaceHandle::from_ptr(surface)
            }
        }
    }

    pub fn serial(&self) -> u32 {
        unsafe { (*self.event).serial }
    }

    pub fn location(&self) -> (i32, i32) {
        unsafe { ((*self.event).hotspot_x, (*self.event).hotspot_y) }
    }
}
<|endoftext|>