<commit_before>//! HTTP Server
//!
//! A `Server` is created to listen on a port, parse HTTP requests, and hand
//! them off to a `Handler`.
use std::fmt;
use std::net::SocketAddr;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;

use rotor::mio::{EventSet, PollOpt};
use rotor::{self, Scope};

pub use self::request::Request;
pub use self::response::Response;

use http::{self, Next};
use net::{Accept, HttpListener, HttpsListener, SslServer, Transport};

mod request;
mod response;
mod message;

/// A configured `Server` ready to run.
pub struct ServerLoop<A, H> where A: Accept, H: HandlerFactory<A::Output> {
    inner: Option<(rotor::Loop<ServerFsm<A, H>>, Context<H>)>,
}

impl<A: Accept, H: HandlerFactory<A::Output>> fmt::Debug for ServerLoop<A, H> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("ServerLoop")
    }
}

/// A Server that can accept incoming network requests.
#[derive(Debug)]
pub struct Server<T: Accept> {
    listener: T,
    keep_alive: bool,
    idle_timeout: Duration,
    max_sockets: usize,
}

impl<T> Server<T> where T: Accept, T::Output: Transport {
    /// Creates a new server with the provided Listener.
    #[inline]
    pub fn new(listener: T) -> Server<T> {
        Server {
            listener: listener,
            keep_alive: true,
            idle_timeout: Duration::from_secs(10),
            max_sockets: 4096,
        }
    }

    /// Enables or disables HTTP keep-alive.
    ///
    /// Default is true.
    pub fn keep_alive(mut self, val: bool) -> Server<T> {
        self.keep_alive = val;
        self
    }

    /// Sets how long an idle connection will be kept before closing.
    ///
    /// Default is 10 seconds.
    pub fn idle_timeout(mut self, val: Duration) -> Server<T> {
        self.idle_timeout = val;
        self
    }

    /// Sets the maximum open sockets for this Server.
    ///
    /// Default is 4096, but most servers can handle much more than this.
    pub fn max_sockets(mut self, val: usize) -> Server<T> {
        self.max_sockets = val;
        self
    }
}

impl Server<HttpListener> { //<H: HandlerFactory<<HttpListener as Accept>::Output>> Server<HttpListener, H> {
    /// Creates a new HTTP server config listening on the provided address.
    pub fn http(addr: &SocketAddr) -> ::Result<Server<HttpListener>> {
        use ::rotor::mio::tcp::TcpListener;
        TcpListener::bind(addr)
            .map(HttpListener)
            .map(Server::new)
            .map_err(From::from)
    }
}

impl<S: SslServer> Server<HttpsListener<S>> {
    /// Creates a new server config that will handle `HttpStream`s over SSL.
    ///
    /// You can use any SSL implementation, as long as implements `hyper::net::Ssl`.
    pub fn https(addr: &SocketAddr, ssl: S) -> ::Result<Server<HttpsListener<S>>> {
        HttpsListener::new(addr, ssl)
            .map(Server::new)
            .map_err(From::from)
    }
}

impl<A: Accept> Server<A> where A::Output: Transport  {
    /// Binds to a socket and starts handling connections.
    pub fn handle<H>(self, factory: H) -> ::Result<(Listening, ServerLoop<A, H>)>
    where H: HandlerFactory<A::Output> {
        let addr = try!(self.listener.local_addr());
        let shutdown = Arc::new(AtomicBool::new(false));
        let shutdown_rx = shutdown.clone();

        let mut config = rotor::Config::new();
        config.slab_capacity(self.max_sockets);
        config.mio().notify_capacity(self.max_sockets);
        let keep_alive = self.keep_alive;
        let mut loop_ = rotor::Loop::new(&config).unwrap();
        let mut notifier = None;
        {
            let notifier = &mut notifier;
            loop_.add_machine_with(move |scope| {
                *notifier = Some(scope.notifier());
                rotor_try!(scope.register(&self.listener, EventSet::readable(), PollOpt::level()));
                rotor::Response::ok(ServerFsm::Listener::<A, H>(self.listener, shutdown_rx))
            }).unwrap();
        }
        let notifier = notifier.expect("loop.add_machine failed");

        let listening = Listening {
            addr: addr,
            shutdown: (shutdown, notifier),
        };
        let server = ServerLoop {
            inner: Some((loop_, Context {
                keep_alive: keep_alive,
                factory: factory
            }))
        };
        Ok((listening, server))
    }
}

impl<A: Accept, H: HandlerFactory<A::Output>> ServerLoop<A, H> {
    /// Runs the server forever in this loop.
    ///
    /// This will block the current thread.
    pub fn run(self) {
        // drop will take care of it.
    }
}

impl<A: Accept, H: HandlerFactory<A::Output>> Drop for ServerLoop<A, H> {
    fn drop(&mut self) {
        self.inner.take().map(|(loop_, ctx)| {
            let _ = loop_.run(ctx);
        });
    }
}

struct Context<F> {
    keep_alive: bool,
    factory: F,
}

impl<F: HandlerFactory<T>, T: Transport> http::MessageHandlerFactory<(), T> for Context<F> {
    type Output = message::Message<F::Output, T>;

    fn create(&mut self, seed: http::Seed<()>) -> Self::Output {
        message::Message::new(self.factory.create(seed.control()))
    }
}

enum ServerFsm<A, H>
where A: Accept,
      A::Output: Transport,
      H: HandlerFactory<A::Output> {
    Listener(A, Arc<AtomicBool>),
    Conn(http::Conn<(), A::Output, message::Message<H::Output, A::Output>>)
}

impl<A, H> rotor::Machine for ServerFsm<A, H>
where A: Accept,
      A::Output: Transport,
      H: HandlerFactory<A::Output> {
    type Context = Context<H>;
    type Seed = A::Output;

    fn create(seed: Self::Seed, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, rotor::Void> {
        rotor_try!(scope.register(&seed, EventSet::readable(), PollOpt::level()));
        rotor::Response::ok(
            ServerFsm::Conn(
                http::Conn::new((), seed, scope.notifier())
                    .keep_alive(scope.keep_alive)
            )
        )
    }

    fn ready(self, events: EventSet, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        match self {
            ServerFsm::Listener(listener, rx) => {
                match listener.accept() {
                    Ok(Some(conn)) => {
                        rotor::Response::spawn(ServerFsm::Listener(listener, rx), conn)
                    },
                    Ok(None) => rotor::Response::ok(ServerFsm::Listener(listener, rx)),
                    Err(e) => {
                        error!("listener accept error {}", e);
                        // usually fine, just keep listening
                        rotor::Response::ok(ServerFsm::Listener(listener, rx))
                    }
                }
            },
            ServerFsm::Conn(conn) => {
                match conn.ready(events, scope) {
                    Some((conn, None)) => rotor::Response::ok(ServerFsm::Conn(conn)),
                    Some((conn, Some(dur))) => {
                        rotor::Response::ok(ServerFsm::Conn(conn))
                            .deadline(scope.now() + dur)
                    }
                    None => rotor::Response::done()
                }
            }
        }
    }

    fn spawned(self, _scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        match self {
            ServerFsm::Listener(listener, rx) => {
                match listener.accept() {
                    Ok(Some(conn)) => {
                        rotor::Response::spawn(ServerFsm::Listener(listener, rx), conn)
                    },
                    Ok(None) => rotor::Response::ok(ServerFsm::Listener(listener, rx)),
                    Err(e) => {
                        error!("listener accept error {}", e);
                        // usually fine, just keep listening
                        rotor::Response::ok(ServerFsm::Listener(listener, rx))
                    }
                }
            },
            sock => rotor::Response::ok(sock)
        }

    }

    fn timeout(self, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        match self {
            ServerFsm::Listener(..) => unreachable!("Listener cannot timeout"),
            ServerFsm::Conn(conn) => {
                match conn.timeout(scope) {
                    Some((conn, None)) => rotor::Response::ok(ServerFsm::Conn(conn)),
                    Some((conn, Some(dur))) => {
                        rotor::Response::ok(ServerFsm::Conn(conn))
                            .deadline(scope.now() + dur)
                    }
                    None => rotor::Response::done()
                }
            }
        }
    }

    fn wakeup(self, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        match self {
            ServerFsm::Listener(lst, shutdown) => {
                if shutdown.load(Ordering::Acquire) {
                    let _ = scope.deregister(&lst);
                    scope.shutdown_loop();
                    rotor::Response::done()
                } else {
                    rotor::Response::ok(ServerFsm::Listener(lst, shutdown))
                }
            },
            ServerFsm::Conn(conn) => match conn.wakeup(scope) {
                Some((conn, None)) => rotor::Response::ok(ServerFsm::Conn(conn)),
                Some((conn, Some(dur))) => {
                    rotor::Response::ok(ServerFsm::Conn(conn))
                        .deadline(scope.now() + dur)
                }
                None => rotor::Response::done()
            }
        }
    }
}

/// A handle of the running server.
pub struct Listening {
    addr: SocketAddr,
    shutdown: (Arc<AtomicBool>, rotor::Notifier),
}

impl fmt::Debug for Listening {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Listening")
            .field("addr", &self.addr)
            .field("closed", &self.shutdown.0.load(Ordering::Relaxed))
            .finish()
    }
}

impl fmt::Display for Listening {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.addr, f)
    }
}

impl Listening {
    /// The address this server is listening on.
    pub fn addr(&self) -> &SocketAddr {
        &self.addr
    }

    /// Stop the server from listening to its socket address.
    pub fn close(self) {
        debug!("closing server {}", self);
        self.shutdown.0.store(true, Ordering::Release);
        self.shutdown.1.wakeup().unwrap();
    }
}

/// A trait to react to server events that happen for each message.
///
/// Each event handler returns it's desired `Next` action.
pub trait Handler<T: Transport> {
    /// This event occurs first, triggering when a `Request` has been parsed.
    fn on_request(&mut self, request: Request<T>) -> Next;
    /// This event occurs each time the `Request` is ready to be read from.
    fn on_request_readable(&mut self, request: &mut http::Decoder<T>) -> Next;
    /// This event occurs after the first time this handled signals `Next::write()`.
    fn on_response(&mut self, response: &mut Response) -> Next;
    /// This event occurs each time the `Response` is ready to be written to.
    fn on_response_writable(&mut self, response: &mut http::Encoder<T>) -> Next;

    /// This event occurs whenever an `Error` occurs outside of the other events.
    ///
    /// This could IO errors while waiting for events, or a timeout, etc.
    fn on_error(&mut self, err: ::Error) -> Next where Self: Sized {
        debug!("default Handler.on_error({:?})", err);
        http::Next::remove()
    }

    /// This event occurs when this Handler has requested to remove the Transport.
    fn on_remove(self, _transport: T) where Self: Sized {
        debug!("default Handler.on_remove");
    }
}

/// Used to create a `Handler` when a new message is received by the server.
pub trait HandlerFactory<T: Transport> {
    /// The `Handler` to use for the incoming message.
    type Output: Handler<T>;
    /// Creates the associated `Handler`.
    fn create(&mut self, ctrl: http::Control) -> Self::Output;
}

impl<F, H, T> HandlerFactory<T> for F
where F: FnMut(http::Control) -> H, H: Handler<T>, T: Transport {
    type Output = H;
    fn create(&mut self, ctrl: http::Control) -> H {
        self(ctrl)
    }
}

#[cfg(test)]
mod tests {

}
<commit_msg>docs(server): Fix some typos in server module<commit_after>//! HTTP Server
//!
//! A `Server` is created to listen on a port, parse HTTP requests, and hand
//! them off to a `Handler`.
use std::fmt;
use std::net::SocketAddr;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;

use rotor::mio::{EventSet, PollOpt};
use rotor::{self, Scope};

pub use self::request::Request;
pub use self::response::Response;

use http::{self, Next};
use net::{Accept, HttpListener, HttpsListener, SslServer, Transport};

mod request;
mod response;
mod message;

/// A configured `Server` ready to run.
pub struct ServerLoop<A, H> where A: Accept, H: HandlerFactory<A::Output> {
    inner: Option<(rotor::Loop<ServerFsm<A, H>>, Context<H>)>,
}

impl<A: Accept, H: HandlerFactory<A::Output>> fmt::Debug for ServerLoop<A, H> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("ServerLoop")
    }
}

/// A Server that can accept incoming network requests.
#[derive(Debug)]
pub struct Server<T: Accept> {
    listener: T,
    keep_alive: bool,
    idle_timeout: Duration,
    max_sockets: usize,
}

impl<T> Server<T> where T: Accept, T::Output: Transport {
    /// Creates a new server with the provided Listener.
    #[inline]
    pub fn new(listener: T) -> Server<T> {
        Server {
            listener: listener,
            keep_alive: true,
            idle_timeout: Duration::from_secs(10),
            max_sockets: 4096,
        }
    }

    /// Enables or disables HTTP keep-alive.
    ///
    /// Default is true.
    pub fn keep_alive(mut self, val: bool) -> Server<T> {
        self.keep_alive = val;
        self
    }

    /// Sets how long an idle connection will be kept before closing.
    ///
    /// Default is 10 seconds.
    pub fn idle_timeout(mut self, val: Duration) -> Server<T> {
        self.idle_timeout = val;
        self
    }

    /// Sets the maximum open sockets for this Server.
    ///
    /// Default is 4096, but most servers can handle much more than this.
    pub fn max_sockets(mut self, val: usize) -> Server<T> {
        self.max_sockets = val;
        self
    }
}

impl Server<HttpListener> { //<H: HandlerFactory<<HttpListener as Accept>::Output>> Server<HttpListener, H> {
    /// Creates a new HTTP server config listening on the provided address.
    pub fn http(addr: &SocketAddr) -> ::Result<Server<HttpListener>> {
        use ::rotor::mio::tcp::TcpListener;
        TcpListener::bind(addr)
            .map(HttpListener)
            .map(Server::new)
            .map_err(From::from)
    }
}

impl<S: SslServer> Server<HttpsListener<S>> {
    /// Creates a new server config that will handle `HttpStream`s over SSL.
    ///
    /// You can use any SSL implementation, as long as it implements `hyper::net::Ssl`.
    pub fn https(addr: &SocketAddr, ssl: S) -> ::Result<Server<HttpsListener<S>>> {
        HttpsListener::new(addr, ssl)
            .map(Server::new)
            .map_err(From::from)
    }
}

impl<A: Accept> Server<A> where A::Output: Transport  {
    /// Binds to a socket and starts handling connections.
    pub fn handle<H>(self, factory: H) -> ::Result<(Listening, ServerLoop<A, H>)>
    where H: HandlerFactory<A::Output> {
        let addr = try!(self.listener.local_addr());
        let shutdown = Arc::new(AtomicBool::new(false));
        let shutdown_rx = shutdown.clone();

        let mut config = rotor::Config::new();
        config.slab_capacity(self.max_sockets);
        config.mio().notify_capacity(self.max_sockets);
        let keep_alive = self.keep_alive;
        let mut loop_ = rotor::Loop::new(&config).unwrap();
        let mut notifier = None;
        {
            let notifier = &mut notifier;
            loop_.add_machine_with(move |scope| {
                *notifier = Some(scope.notifier());
                rotor_try!(scope.register(&self.listener, EventSet::readable(), PollOpt::level()));
                rotor::Response::ok(ServerFsm::Listener::<A, H>(self.listener, shutdown_rx))
            }).unwrap();
        }
        let notifier = notifier.expect("loop.add_machine failed");

        let listening = Listening {
            addr: addr,
            shutdown: (shutdown, notifier),
        };
        let server = ServerLoop {
            inner: Some((loop_, Context {
                keep_alive: keep_alive,
                factory: factory
            }))
        };
        Ok((listening, server))
    }
}

impl<A: Accept, H: HandlerFactory<A::Output>> ServerLoop<A, H> {
    /// Runs the server forever in this loop.
    ///
    /// This will block the current thread.
    pub fn run(self) {
        // drop will take care of it.
    }
}

impl<A: Accept, H: HandlerFactory<A::Output>> Drop for ServerLoop<A, H> {
    fn drop(&mut self) {
        self.inner.take().map(|(loop_, ctx)| {
            let _ = loop_.run(ctx);
        });
    }
}

struct Context<F> {
    keep_alive: bool,
    factory: F,
}

impl<F: HandlerFactory<T>, T: Transport> http::MessageHandlerFactory<(), T> for Context<F> {
    type Output = message::Message<F::Output, T>;

    fn create(&mut self, seed: http::Seed<()>) -> Self::Output {
        message::Message::new(self.factory.create(seed.control()))
    }
}

enum ServerFsm<A, H>
where A: Accept,
      A::Output: Transport,
      H: HandlerFactory<A::Output> {
    Listener(A, Arc<AtomicBool>),
    Conn(http::Conn<(), A::Output, message::Message<H::Output, A::Output>>)
}

impl<A, H> rotor::Machine for ServerFsm<A, H>
where A: Accept,
      A::Output: Transport,
      H: HandlerFactory<A::Output> {
    type Context = Context<H>;
    type Seed = A::Output;

    fn create(seed: Self::Seed, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, rotor::Void> {
        rotor_try!(scope.register(&seed, EventSet::readable(), PollOpt::level()));
        rotor::Response::ok(
            ServerFsm::Conn(
                http::Conn::new((), seed, scope.notifier())
                    .keep_alive(scope.keep_alive)
            )
        )
    }

    fn ready(self, events: EventSet, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        match self {
            ServerFsm::Listener(listener, rx) => {
                match listener.accept() {
                    Ok(Some(conn)) => {
                        rotor::Response::spawn(ServerFsm::Listener(listener, rx), conn)
                    },
                    Ok(None) => rotor::Response::ok(ServerFsm::Listener(listener, rx)),
                    Err(e) => {
                        error!("listener accept error {}", e);
                        // usually fine, just keep listening
                        rotor::Response::ok(ServerFsm::Listener(listener, rx))
                    }
                }
            },
            ServerFsm::Conn(conn) => {
                match conn.ready(events, scope) {
                    Some((conn, None)) => rotor::Response::ok(ServerFsm::Conn(conn)),
                    Some((conn, Some(dur))) => {
                        rotor::Response::ok(ServerFsm::Conn(conn))
                            .deadline(scope.now() + dur)
                    }
                    None => rotor::Response::done()
                }
            }
        }
    }

    fn spawned(self, _scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        match self {
            ServerFsm::Listener(listener, rx) => {
                match listener.accept() {
                    Ok(Some(conn)) => {
                        rotor::Response::spawn(ServerFsm::Listener(listener, rx), conn)
                    },
                    Ok(None) => rotor::Response::ok(ServerFsm::Listener(listener, rx)),
                    Err(e) => {
                        error!("listener accept error {}", e);
                        // usually fine, just keep listening
                        rotor::Response::ok(ServerFsm::Listener(listener, rx))
                    }
                }
            },
            sock => rotor::Response::ok(sock)
        }

    }

    fn timeout(self, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        match self {
            ServerFsm::Listener(..) => unreachable!("Listener cannot timeout"),
            ServerFsm::Conn(conn) => {
                match conn.timeout(scope) {
                    Some((conn, None)) => rotor::Response::ok(ServerFsm::Conn(conn)),
                    Some((conn, Some(dur))) => {
                        rotor::Response::ok(ServerFsm::Conn(conn))
                            .deadline(scope.now() + dur)
                    }
                    None => rotor::Response::done()
                }
            }
        }
    }

    fn wakeup(self, scope: &mut Scope<Self::Context>) -> rotor::Response<Self, Self::Seed> {
        match self {
            ServerFsm::Listener(lst, shutdown) => {
                if shutdown.load(Ordering::Acquire) {
                    let _ = scope.deregister(&lst);
                    scope.shutdown_loop();
                    rotor::Response::done()
                } else {
                    rotor::Response::ok(ServerFsm::Listener(lst, shutdown))
                }
            },
            ServerFsm::Conn(conn) => match conn.wakeup(scope) {
                Some((conn, None)) => rotor::Response::ok(ServerFsm::Conn(conn)),
                Some((conn, Some(dur))) => {
                    rotor::Response::ok(ServerFsm::Conn(conn))
                        .deadline(scope.now() + dur)
                }
                None => rotor::Response::done()
            }
        }
    }
}

/// A handle of the running server.
pub struct Listening {
    addr: SocketAddr,
    shutdown: (Arc<AtomicBool>, rotor::Notifier),
}

impl fmt::Debug for Listening {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Listening")
            .field("addr", &self.addr)
            .field("closed", &self.shutdown.0.load(Ordering::Relaxed))
            .finish()
    }
}

impl fmt::Display for Listening {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.addr, f)
    }
}

impl Listening {
    /// The address this server is listening on.
    pub fn addr(&self) -> &SocketAddr {
        &self.addr
    }

    /// Stop the server from listening to its socket address.
    pub fn close(self) {
        debug!("closing server {}", self);
        self.shutdown.0.store(true, Ordering::Release);
        self.shutdown.1.wakeup().unwrap();
    }
}

/// A trait to react to server events that happen for each message.
///
/// Each event handler returns its desired `Next` action.
pub trait Handler<T: Transport> {
    /// This event occurs first, triggering when a `Request` has been parsed.
    fn on_request(&mut self, request: Request<T>) -> Next;
    /// This event occurs each time the `Request` is ready to be read from.
    fn on_request_readable(&mut self, request: &mut http::Decoder<T>) -> Next;
    /// This event occurs after the first time this handled signals `Next::write()`.
    fn on_response(&mut self, response: &mut Response) -> Next;
    /// This event occurs each time the `Response` is ready to be written to.
    fn on_response_writable(&mut self, response: &mut http::Encoder<T>) -> Next;

    /// This event occurs whenever an `Error` occurs outside of the other events.
    ///
    /// This could IO errors while waiting for events, or a timeout, etc.
    fn on_error(&mut self, err: ::Error) -> Next where Self: Sized {
        debug!("default Handler.on_error({:?})", err);
        http::Next::remove()
    }

    /// This event occurs when this Handler has requested to remove the Transport.
    fn on_remove(self, _transport: T) where Self: Sized {
        debug!("default Handler.on_remove");
    }
}

/// Used to create a `Handler` when a new message is received by the server.
pub trait HandlerFactory<T: Transport> {
    /// The `Handler` to use for the incoming message.
    type Output: Handler<T>;
    /// Creates the associated `Handler`.
    fn create(&mut self, ctrl: http::Control) -> Self::Output;
}

impl<F, H, T> HandlerFactory<T> for F
where F: FnMut(http::Control) -> H, H: Handler<T>, T: Transport {
    type Output = H;
    fn create(&mut self, ctrl: http::Control) -> H {
        self(ctrl)
    }
}

#[cfg(test)]
mod tests {

}
<|endoftext|>


<commit_before>use std::io::{self, Read};
use std::iter::Iterator;
use std::path::{Component, Path, PathBuf};
use std::slice;

use flate2::read::GzDecoder;
use tar;
use time::Timespec;

use backend::Backend;
use collections::{CollectionsStatus, SignatureFile};

pub struct BackupFiles {
    chains: Vec<Chain>
}

pub struct Snapshot<'a> {
    index: u8,
    chain: &'a Chain
}

#[derive(Debug)]
pub struct File<'a> {
    pub name: &'a str,
    pub last_modified: Timespec
}

/// Iterator over a list of backup snapshots.
pub struct Snapshots<'a> {
    chain_iter: slice::Iter<'a, Chain>,
    chain: Option<&'a Chain>,
    snapshot_id: u8
}

pub struct SnapshotFiles<'a> {
    index: u8,
    iter: slice::Iter<'a, PathSnapshots>
}

enum DiffType {
    Signature,
    Snapshot,
    Deleted
}

/// Store separately informations about the signatures and informations about the paths in the
/// signatures. This allows to reuse informations between snapshots and avoid duplicating them.
struct Chain {
    timestamps: Vec<Timespec>,
    files: Vec<PathSnapshots>
}

struct PathSnapshots {
    // the directory or file path
    path: PathBuf,
    // all the snapshots for this path
    snapshots: Vec<PathSnapshot>
}

struct PathSnapshot {
    // info are None if the snapshot has deleted this path
    info: Option<PathInfo>,
    // the index of the snapshot in the chain
    index: u8
}

/// Informations about a path inside a snapshot.
struct PathInfo {
    mtime: Timespec
}

impl BackupFiles {
    pub fn new<B: Backend>(backend: &B) -> io::Result<BackupFiles> {
        let collection = {
            let filenames = try!(backend.get_file_names());
            CollectionsStatus::from_filenames(&filenames)
        };
        let mut chains: Vec<Chain> = Vec::new();
        let coll_chains = collection.signature_chains();
        for coll_chain in coll_chains {
            // translate collections::SignatureChain into a Chain
            let mut chain = Chain{ timestamps: Vec::new(), files: Vec::new() };
            // add to the chain the full signature and all the incremental signatures
            // if an error occurs in the full signature exit
            let file = try!(backend.open_file(coll_chain.fullsig.file_name.as_ref()));
            try!(add_sigfile_to_chain(&mut chain, file, &coll_chain.fullsig));
            for inc in coll_chain.inclist.iter() {
                // TODO: if an error occurs here, do not exit with an error, instead
                // break the iteration and store the error inside the chain
                let file = try!(backend.open_file(inc.file_name.as_ref()));
                try!(add_sigfile_to_chain(&mut chain, file, &inc));
            }
            chains.push(chain);
        }
        Ok(BackupFiles{ chains: chains })
    }

    pub fn snapshots(&self) -> Snapshots {
        let mut iter = self.chains.iter();
        let first_chain = iter.next();
        Snapshots{ chain_iter: iter, chain: first_chain, snapshot_id: 0 }
    }
}

impl<'a> Iterator for Snapshots<'a> {
    type Item = Snapshot<'a>;

    fn next(&mut self) -> Option<Snapshot<'a>> {
        loop {
            if let Some(chain) = self.chain {
                if let Some(_) = chain.timestamps.get(self.snapshot_id as usize) {
                    let result = Some(Snapshot{ index: self.snapshot_id, chain: chain });
                    self.snapshot_id += 1;
                    return result;
                }
                else {
                    // this chain is completed
                    // go to next chain
                    self.chain = self.chain_iter.next();
                    self.snapshot_id = 0;
                }
            }
            else {
                // no other chains are present
                return None
            }
        }
    }
}

impl<'a> Snapshot<'a> {
    pub fn time(&self) -> Timespec {
        self.chain.timestamps[self.index as usize]
    }

    pub fn files(&self) -> SnapshotFiles<'a> {
        SnapshotFiles{ index: self.index, iter: self.chain.files.iter() }
    }
}

impl<'a> Iterator for SnapshotFiles<'a> {
    type Item = File<'a>;

    fn next(&mut self) -> Option<File<'a>> {
        while let Some(path_snapshots) = self.iter.next() {
            if let Some(s) = path_snapshots.snapshots.iter().rev().find(|s| s.index <= self.index) {
                // now we have a path info present in this snapshot
                // if it is not deleted return it
                if let Some(ref info) = s.info {
                    return Some(File{ name: path_snapshots.path.to_str().unwrap(), last_modified: info.mtime })
                }
            }
        }
        None
    }
}

fn add_sigfile_to_chain<R: Read>(chain: &mut Chain,
                                 file: R,
                                 sigfile: &SignatureFile) -> io::Result<()>
{
    let result = {
        let snapshot_id = chain.files.len() as u8;
        if sigfile.compressed {
            let gz_decoder = try!(GzDecoder::new(file));
            add_sigtar_to_snapshots(&mut chain.files, tar::Archive::new(gz_decoder), snapshot_id)
        }
        else {
            add_sigtar_to_snapshots(&mut chain.files, tar::Archive::new(file), snapshot_id)
        }
    };
    if result.is_ok() {
        // add to the list of signatures only if everything is ok
        // we do not need to cleanup the chain if someting went wrong, because if the list of
        // signatures is not updated, the change is not observable
        chain.timestamps.push(sigfile.time);
    }
    result
}

fn add_sigtar_to_snapshots<R: Read>(snapshots: &mut Vec<PathSnapshots>,
                                    mut tar: tar::Archive<R>,
                                    snapshot_id: u8) -> io::Result<()>
{
    let mut new_files: Vec<PathSnapshots> = Vec::new();
    {
        let mut old_snapshots = snapshots.iter_mut();
        for tarfile in try!(tar.files_mut()) {
            // we can ignore paths with errors
            // the only problem here is that we miss some change in the chain, but it is better
            // than abort the whole signature
            let tarfile = unwrap_or_continue!(tarfile);
            let header = tarfile.header();
            let path = unwrap_or_continue!(header.path());
            let (difftype, path) = unwrap_opt_or_continue!(parse_snapshot_path(&path));
            let info = match difftype {
                DiffType::Signature | DiffType::Snapshot => {
                    let time = Timespec::new(header.mtime().unwrap_or(0 as u64) as i64, 0);
                    Some(PathInfo{ mtime: time })
                }
                _ => None
            };
            let new_snapshot = PathSnapshot{ info: info, index: snapshot_id };
            // find the current path in the old snapshots
            // note: they are ordered
            let position = {
                let mut position: Option<&mut PathSnapshots> = None;
                while let Some(path_snapshots) = old_snapshots.next() {
                    if path_snapshots.path.as_path() < path {
                        continue;
                    }
                    if path_snapshots.path.as_path() == path {
                        // this path is already present in old snapshots: update them
                        position = Some(path_snapshots);
                    }
                    else {
                        // we've already reached the first item next to the current path
                        // so, the path is not present in old snapshots
                        position = None;
                    }
                    break;
                };
                position
            };
            if let Some(path_snapshots) = position {
                path_snapshots.snapshots.push(new_snapshot);
            }
            else {
                // the path is not present in the old snapshots: add to new list
                new_files.push(PathSnapshots{
                    path: path.to_path_buf(),
                    snapshots: vec![new_snapshot]
                });
            }
        }
    }
    // merge the new files with old snapshots
    if !new_files.is_empty() {
        // TODO: Performance hurt here: we have two sorted arrays to merge,
        // better to use this algorithm: http://stackoverflow.com/a/4553321/1667955
        snapshots.extend(new_files.into_iter());
        snapshots.sort_by(|a, b| a.path.cmp(&b.path));
    }
    Ok(())
}

fn parse_snapshot_path(path: &Path) -> Option<(DiffType, &Path)> {
    // split the path in (first directory, the remaining path)
    // the first is the type, the remaining is the real path
    let mut pcomps = path.components();
    let pfirst = try_opt!(pcomps.next());
    if let Component::Normal(strfirst) = pfirst {
        let difftype = match strfirst.to_str() {
            Some("signature") => DiffType::Signature,
            Some("snapshot")  => DiffType::Snapshot,
            Some("deleted")   => DiffType::Deleted,
            _                 => { return None; }
        };
        let realpath = pcomps.as_path();
        Some((difftype, realpath))
    }
    else {
        None
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use backend::local::LocalBackend;
    use time_utils::to_pretty_local;

    #[test]
    fn open_from_local() {
        let backend = LocalBackend::new("tests/backups/single_vol").unwrap();
        let files = BackupFiles::new(&backend).unwrap();
        println!("Backup snapshots:");
        for snapshot in files.snapshots() {
            println!("Snapshot {}", to_pretty_local(snapshot.time()));
            for file in snapshot.files() {
                println!("    {:?}", file);
            }
        }
    }
}
<commit_msg>Fixed panic with unicode paths<commit_after>use std::io::{self, Read};
use std::iter::Iterator;
use std::path::{Component, Path, PathBuf};
use std::slice;

use flate2::read::GzDecoder;
use tar;
use time::Timespec;

use backend::Backend;
use collections::{CollectionsStatus, SignatureFile};

pub struct BackupFiles {
    chains: Vec<Chain>
}

pub struct Snapshot<'a> {
    index: u8,
    chain: &'a Chain
}

#[derive(Debug)]
pub struct File<'a> {
    pub path: &'a Path,
    pub last_modified: Timespec
}

/// Iterator over a list of backup snapshots.
pub struct Snapshots<'a> {
    chain_iter: slice::Iter<'a, Chain>,
    chain: Option<&'a Chain>,
    snapshot_id: u8
}

pub struct SnapshotFiles<'a> {
    index: u8,
    iter: slice::Iter<'a, PathSnapshots>
}

enum DiffType {
    Signature,
    Snapshot,
    Deleted
}

/// Store separately informations about the signatures and informations about the paths in the
/// signatures. This allows to reuse informations between snapshots and avoid duplicating them.
struct Chain {
    timestamps: Vec<Timespec>,
    files: Vec<PathSnapshots>
}

struct PathSnapshots {
    // the directory or file path
    path: PathBuf,
    // all the snapshots for this path
    snapshots: Vec<PathSnapshot>
}

struct PathSnapshot {
    // info are None if the snapshot has deleted this path
    info: Option<PathInfo>,
    // the index of the snapshot in the chain
    index: u8
}

/// Informations about a path inside a snapshot.
struct PathInfo {
    mtime: Timespec
}

impl BackupFiles {
    pub fn new<B: Backend>(backend: &B) -> io::Result<BackupFiles> {
        let collection = {
            let filenames = try!(backend.get_file_names());
            CollectionsStatus::from_filenames(&filenames)
        };
        let mut chains: Vec<Chain> = Vec::new();
        let coll_chains = collection.signature_chains();
        for coll_chain in coll_chains {
            // translate collections::SignatureChain into a Chain
            let mut chain = Chain{ timestamps: Vec::new(), files: Vec::new() };
            // add to the chain the full signature and all the incremental signatures
            // if an error occurs in the full signature exit
            let file = try!(backend.open_file(coll_chain.fullsig.file_name.as_ref()));
            try!(add_sigfile_to_chain(&mut chain, file, &coll_chain.fullsig));
            for inc in coll_chain.inclist.iter() {
                // TODO: if an error occurs here, do not exit with an error, instead
                // break the iteration and store the error inside the chain
                let file = try!(backend.open_file(inc.file_name.as_ref()));
                try!(add_sigfile_to_chain(&mut chain, file, &inc));
            }
            chains.push(chain);
        }
        Ok(BackupFiles{ chains: chains })
    }

    pub fn snapshots(&self) -> Snapshots {
        let mut iter = self.chains.iter();
        let first_chain = iter.next();
        Snapshots{ chain_iter: iter, chain: first_chain, snapshot_id: 0 }
    }
}

impl<'a> Iterator for Snapshots<'a> {
    type Item = Snapshot<'a>;

    fn next(&mut self) -> Option<Snapshot<'a>> {
        loop {
            if let Some(chain) = self.chain {
                if let Some(_) = chain.timestamps.get(self.snapshot_id as usize) {
                    let result = Some(Snapshot{ index: self.snapshot_id, chain: chain });
                    self.snapshot_id += 1;
                    return result;
                }
                else {
                    // this chain is completed
                    // go to next chain
                    self.chain = self.chain_iter.next();
                    self.snapshot_id = 0;
                }
            }
            else {
                // no other chains are present
                return None
            }
        }
    }
}

impl<'a> Snapshot<'a> {
    pub fn time(&self) -> Timespec {
        self.chain.timestamps[self.index as usize]
    }

    pub fn files(&self) -> SnapshotFiles<'a> {
        SnapshotFiles{ index: self.index, iter: self.chain.files.iter() }
    }
}

impl<'a> Iterator for SnapshotFiles<'a> {
    type Item = File<'a>;

    fn next(&mut self) -> Option<File<'a>> {
        while let Some(path_snapshots) = self.iter.next() {
            if let Some(s) = path_snapshots.snapshots.iter().rev().find(|s| s.index <= self.index) {
                // now we have a path info present in this snapshot
                // if it is not deleted return it
                if let Some(ref info) = s.info {
                    return Some(File{
                        path: path_snapshots.path.as_ref(),
                        last_modified: info.mtime
                    });
                }
            }
        }
        None
    }
}

fn add_sigfile_to_chain<R: Read>(chain: &mut Chain,
                                 file: R,
                                 sigfile: &SignatureFile) -> io::Result<()>
{
    let result = {
        let snapshot_id = chain.files.len() as u8;
        if sigfile.compressed {
            let gz_decoder = try!(GzDecoder::new(file));
            add_sigtar_to_snapshots(&mut chain.files, tar::Archive::new(gz_decoder), snapshot_id)
        }
        else {
            add_sigtar_to_snapshots(&mut chain.files, tar::Archive::new(file), snapshot_id)
        }
    };
    if result.is_ok() {
        // add to the list of signatures only if everything is ok
        // we do not need to cleanup the chain if someting went wrong, because if the list of
        // signatures is not updated, the change is not observable
        chain.timestamps.push(sigfile.time);
    }
    result
}

fn add_sigtar_to_snapshots<R: Read>(snapshots: &mut Vec<PathSnapshots>,
                                    mut tar: tar::Archive<R>,
                                    snapshot_id: u8) -> io::Result<()>
{
    let mut new_files: Vec<PathSnapshots> = Vec::new();
    {
        let mut old_snapshots = snapshots.iter_mut();
        for tarfile in try!(tar.files_mut()) {
            // we can ignore paths with errors
            // the only problem here is that we miss some change in the chain, but it is better
            // than abort the whole signature
            let tarfile = unwrap_or_continue!(tarfile);
            let header = tarfile.header();
            let path = unwrap_or_continue!(header.path());
            let (difftype, path) = unwrap_opt_or_continue!(parse_snapshot_path(&path));
            let info = match difftype {
                DiffType::Signature | DiffType::Snapshot => {
                    let time = Timespec::new(header.mtime().unwrap_or(0 as u64) as i64, 0);
                    Some(PathInfo{ mtime: time })
                }
                _ => None
            };
            let new_snapshot = PathSnapshot{ info: info, index: snapshot_id };
            // find the current path in the old snapshots
            // note: they are ordered
            let position = {
                let mut position: Option<&mut PathSnapshots> = None;
                while let Some(path_snapshots) = old_snapshots.next() {
                    if path_snapshots.path.as_path() < path {
                        continue;
                    }
                    if path_snapshots.path.as_path() == path {
                        // this path is already present in old snapshots: update them
                        position = Some(path_snapshots);
                    }
                    else {
                        // we've already reached the first item next to the current path
                        // so, the path is not present in old snapshots
                        position = None;
                    }
                    break;
                };
                position
            };
            if let Some(path_snapshots) = position {
                path_snapshots.snapshots.push(new_snapshot);
            }
            else {
                // the path is not present in the old snapshots: add to new list
                new_files.push(PathSnapshots{
                    path: path.to_path_buf(),
                    snapshots: vec![new_snapshot]
                });
            }
        }
    }
    // merge the new files with old snapshots
    if !new_files.is_empty() {
        // TODO: Performance hurt here: we have two sorted arrays to merge,
        // better to use this algorithm: http://stackoverflow.com/a/4553321/1667955
        snapshots.extend(new_files.into_iter());
        snapshots.sort_by(|a, b| a.path.cmp(&b.path));
    }
    Ok(())
}

fn parse_snapshot_path(path: &Path) -> Option<(DiffType, &Path)> {
    // split the path in (first directory, the remaining path)
    // the first is the type, the remaining is the real path
    let mut pcomps = path.components();
    let pfirst = try_opt!(pcomps.next());
    if let Component::Normal(strfirst) = pfirst {
        let difftype = match strfirst.to_str() {
            Some("signature") => DiffType::Signature,
            Some("snapshot")  => DiffType::Snapshot,
            Some("deleted")   => DiffType::Deleted,
            _                 => { return None; }
        };
        let realpath = pcomps.as_path();
        Some((difftype, realpath))
    }
    else {
        None
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use backend::local::LocalBackend;
    use time_utils::to_pretty_local;

    #[test]
    fn open_from_local() {
        let backend = LocalBackend::new("tests/backups/single_vol").unwrap();
        let files = BackupFiles::new(&backend).unwrap();
        println!("Backup snapshots:");
        for snapshot in files.snapshots() {
            println!("Snapshot {}", to_pretty_local(snapshot.time()));
            for file in snapshot.files() {
                println!("    {:?}", file);
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <https://opensource.org/licenses/MIT>

use futures_core::future::Future;
use futures_core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
use futures_task::{FutureObj, LocalFutureObj, LocalSpawn, Spawn, SpawnError};
use futures_util::future::FutureExt;
use glib_sys;
use std::mem;
use std::pin;
use std::ptr;
use translate::{from_glib_borrow, from_glib_full, mut_override, Borrowed, ToGlib};
use ThreadGuard;

use MainContext;
use MainLoop;
use Priority;
use Source;

// Wrapper around Send Futures and non-Send Futures that will panic
// if the non-Send Future is polled/dropped from a different thread
// than where this was created.
enum FutureWrapper {
    Send(FutureObj<'static, ()>),
    NonSend(ThreadGuard<LocalFutureObj<'static, ()>>),
}

impl Future for FutureWrapper {
    type Output = ();

    fn poll(self: pin::Pin<&mut Self>, ctx: &mut Context) -> Poll<()> {
        match self.get_mut() {
            FutureWrapper::Send(fut) => fut.poll_unpin(ctx),
            FutureWrapper::NonSend(fut) => fut.get_mut().poll_unpin(ctx),
        }
    }
}

// The TaskSource and WakerSource are split up as the TaskSource
// must only be finalized on the thread that owns the main context
// but the WakerSource is passed around to arbitrary threads for
// being able to wake up the TaskSource.
//
// The WakerSource is set up as a child source of the TaskSource, i.e.
// whenever it is ready also the TaskSource is ready.
#[allow(clippy::type_complexity)]
#[repr(C)]
struct TaskSource {
    source: glib_sys::GSource,
    future: FutureWrapper,
    waker: Waker,
}

#[allow(clippy::type_complexity)]
#[repr(C)]
struct WakerSource {
    source: glib_sys::GSource,
}

impl TaskSource {
    unsafe extern "C" fn dispatch(
        source: *mut glib_sys::GSource,
        callback: glib_sys::GSourceFunc,
        _user_data: glib_sys::gpointer,
    ) -> glib_sys::gboolean {
        let source = &mut *(source as *mut TaskSource);
        assert!(callback.is_none());

        // Poll the TaskSource and ensure we're never called again if the
        // contained Future resolved now.
        if let Poll::Ready(()) = source.poll() {
            glib_sys::G_SOURCE_REMOVE
        } else {
            glib_sys::G_SOURCE_CONTINUE
        }
    }

    unsafe extern "C" fn finalize(source: *mut glib_sys::GSource) {
        let source = source as *mut TaskSource;

        // This will panic if the future was a local future and is dropped from
        // a different thread than where it was created.
        ptr::drop_in_place(&mut (*source).future);

        // Drop the waker to unref the underlying GSource
        ptr::drop_in_place(&mut (*source).waker);
    }
}

impl WakerSource {
    unsafe fn clone_raw(waker: *const ()) -> RawWaker {
        static VTABLE: RawWakerVTable = RawWakerVTable::new(
            WakerSource::clone_raw,
            WakerSource::wake_raw,
            WakerSource::wake_by_ref_raw,
            WakerSource::drop_raw,
        );

        let waker = waker as *const glib_sys::GSource;
        glib_sys::g_source_ref(mut_override(waker));
        RawWaker::new(waker as *const (), &VTABLE)
    }

    unsafe fn wake_raw(waker: *const ()) {
        Self::wake_by_ref_raw(waker);
        Self::drop_raw(waker);
    }

    unsafe fn wake_by_ref_raw(waker: *const ()) {
        let waker = waker as *const glib_sys::GSource;
        glib_sys::g_source_set_ready_time(mut_override(waker), 0);
    }

    unsafe fn drop_raw(waker: *const ()) {
        let waker = waker as *const glib_sys::GSource;
        glib_sys::g_source_unref(mut_override(waker));
    }

    unsafe extern "C" fn dispatch(
        source: *mut glib_sys::GSource,
        _callback: glib_sys::GSourceFunc,
        _user_data: glib_sys::gpointer,
    ) -> glib_sys::gboolean {
        // Set ready-time to -1 so that we're not called again before
        // being woken up another time.
        glib_sys::g_source_set_ready_time(mut_override(source), -1);
        glib_sys::G_SOURCE_CONTINUE
    }
}

unsafe impl Send for TaskSource {}
unsafe impl Sync for TaskSource {}

unsafe impl Send for WakerSource {}
unsafe impl Sync for WakerSource {}

impl TaskSource {
    #[allow(clippy::new_ret_no_self)]
    fn new(priority: Priority, future: FutureWrapper) -> Source {
        unsafe {
            static TASK_SOURCE_FUNCS: glib_sys::GSourceFuncs = glib_sys::GSourceFuncs {
                check: None,
                prepare: None,
                dispatch: Some(TaskSource::dispatch),
                finalize: Some(TaskSource::finalize),
                closure_callback: None,
                closure_marshal: None,
            };

            static WAKER_SOURCE_FUNCS: glib_sys::GSourceFuncs = glib_sys::GSourceFuncs {
                check: None,
                prepare: None,
                dispatch: Some(WakerSource::dispatch),
                finalize: None,
                closure_callback: None,
                closure_marshal: None,
            };

            let source = glib_sys::g_source_new(
                mut_override(&TASK_SOURCE_FUNCS),
                mem::size_of::<TaskSource>() as u32,
            );

            let waker_source = glib_sys::g_source_new(
                mut_override(&WAKER_SOURCE_FUNCS),
                mem::size_of::<WakerSource>() as u32,
            );

            glib_sys::g_source_set_priority(source, priority.to_glib());
            glib_sys::g_source_add_child_source(source, waker_source);

            {
                let source = &mut *(source as *mut TaskSource);
                ptr::write(&mut source.future, future);

                // This creates a new reference to the waker source.
                let waker = Waker::from_raw(WakerSource::clone_raw(waker_source as *const ()));
                ptr::write(&mut source.waker, waker);
            }

            // Set ready time to 0 so that the source is immediately dispatched
            // for doing the initial polling. This will then either resolve the
            // future or register the waker wherever necessary.
            glib_sys::g_source_set_ready_time(waker_source, 0);

            // Unref the waker source, a strong reference to it is stored inside
            // the task source directly and inside the task source as child source.
            glib_sys::g_source_unref(waker_source);

            from_glib_full(source)
        }
    }

    fn poll(&mut self) -> Poll<()> {
        let source = &self.source as *const _;
        let executor: Borrowed<MainContext> =
            unsafe { from_glib_borrow(glib_sys::g_source_get_context(mut_override(source))) };

        assert!(
            executor.is_owner(),
            "Polling futures only allowed if the thread is owning the MainContext"
        );

        executor.with_thread_default(|| {
            let _enter = futures_executor::enter().unwrap();
            let mut context = Context::from_waker(&self.waker);

            // This will panic if the future was a local future and is called from
            // a different thread than where it was created.
            self.future.poll_unpin(&mut context)
        })
    }
}

impl MainContext {
    /// Spawn a new infallible `Future` on the main context.
    ///
    /// This can be called from any thread and will execute the future from the thread
    /// where main context is running, e.g. via a `MainLoop`.
    pub fn spawn<F: Future<Output = ()> + Send + 'static>(&self, f: F) {
        self.spawn_with_priority(::PRIORITY_DEFAULT, f);
    }

    /// Spawn a new infallible `Future` on the main context.
    ///
    /// The given `Future` does not have to be `Send`.
    ///
    /// This can be called only from the thread where the main context is running, e.g.
    /// from any other `Future` that is executed on this main context, or after calling
    /// `push_thread_default` or `acquire` on the main context.
    pub fn spawn_local<F: Future<Output = ()> + 'static>(&self, f: F) {
        self.spawn_local_with_priority(::PRIORITY_DEFAULT, f);
    }

    /// Spawn a new infallible `Future` on the main context, with a non-default priority.
    ///
    /// This can be called from any thread and will execute the future from the thread
    /// where main context is running, e.g. via a `MainLoop`.
    pub fn spawn_with_priority<F: Future<Output = ()> + Send + 'static>(
        &self,
        priority: Priority,
        f: F,
    ) {
        let f = FutureObj::new(Box::new(f));
        let source = TaskSource::new(priority, FutureWrapper::Send(f));
        source.attach(Some(&*self));
    }

    /// Spawn a new infallible `Future` on the main context, with a non-default priority.
    ///
    /// The given `Future` does not have to be `Send`.
    ///
    /// This can be called only from the thread where the main context is running, e.g.
    /// from any other `Future` that is executed on this main context, or after calling
    /// `push_thread_default` or `acquire` on the main context.
    pub fn spawn_local_with_priority<F: Future<Output = ()> + 'static>(
        &self,
        priority: Priority,
        f: F,
    ) {
        assert!(
            self.is_owner(),
            "Spawning local futures only allowed on the thread owning the MainContext"
        );
        let f = LocalFutureObj::new(Box::new(f));
        let source = TaskSource::new(priority, FutureWrapper::NonSend(ThreadGuard::new(f)));
        source.attach(Some(&*self));
    }

    /// Runs a new, infallible `Future` on the main context and block until it finished, returning
    /// the result of the `Future`.
    ///
    /// The given `Future` does not have to be `Send` or `'static`.
    ///
    /// This must only be called if no `MainLoop` or anything else is running on this specific main
    /// context.
    #[allow(clippy::transmute_ptr_to_ptr)]
    pub fn block_on<F: Future>(&self, f: F) -> F::Output {
        let mut res = None;
        let l = MainLoop::new(Some(&*self), false);
        let l_clone = l.clone();

        unsafe {
            let f = f.then(|r| {
                res = Some(r);
                l_clone.quit();
                futures_util::future::ready(())
            });

            // Super-unsafe: We transmute here to get rid of the 'static lifetime
            let f = LocalFutureObj::new(Box::new(f));
            let f: LocalFutureObj<'static, ()> = mem::transmute(f);

            let source = TaskSource::new(
                ::PRIORITY_DEFAULT,
                FutureWrapper::NonSend(ThreadGuard::new(f)),
            );
            source.attach(Some(&*self));
        }

        l.run();

        res.unwrap()
    }
}

impl Spawn for MainContext {
    fn spawn_obj(&self, f: FutureObj<'static, ()>) -> Result<(), SpawnError> {
        let source = TaskSource::new(::PRIORITY_DEFAULT, FutureWrapper::Send(f));
        source.attach(Some(&*self));
        Ok(())
    }
}

impl LocalSpawn for MainContext {
    fn spawn_local_obj(&self, f: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
        let source = TaskSource::new(
            ::PRIORITY_DEFAULT,
            FutureWrapper::NonSend(ThreadGuard::new(f)),
        );
        source.attach(Some(&*self));
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use futures_channel::oneshot;
    use futures_util::future::TryFutureExt;
    use std::sync::mpsc;
    use std::thread;

    #[test]
    fn test_spawn() {
        let c = MainContext::new();
        let l = ::MainLoop::new(Some(&c), false);

        let (sender, receiver) = mpsc::channel();
        let (o_sender, o_receiver) = oneshot::channel();

        let l_clone = l.clone();
        c.spawn(
            o_receiver
                .and_then(move |()| {
                    sender.send(()).unwrap();
                    l_clone.quit();

                    futures_util::future::ok(())
                })
                .then(|res| {
                    assert!(res.is_ok());
                    futures_util::future::ready(())
                }),
        );

        thread::spawn(move || {
            l.run();
        });

        o_sender.send(()).unwrap();

        receiver.recv().unwrap();
    }

    #[test]
    fn test_spawn_local() {
        let c = MainContext::new();
        let l = ::MainLoop::new(Some(&c), false);

        c.push_thread_default();
        let l_clone = l.clone();
        c.spawn_local(futures_util::future::lazy(move |_ctx| {
            l_clone.quit();
        }));

        l.run();

        c.pop_thread_default();
    }

    #[test]
    fn test_block_on() {
        let c = MainContext::new();

        let mut v = None;
        {
            let v = &mut v;

            let future = futures_util::future::lazy(|_ctx| {
                *v = Some(123);
                Ok::<i32, ()>(123)
            });

            let res = c.block_on(future);
            assert_eq!(res, Ok(123));
        }

        assert_eq!(v, Some(123));
    }
}
<commit_msg>Remove unneeded #[allow(clippy::type_complexity)]<commit_after>// Copyright 2018, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <https://opensource.org/licenses/MIT>

use futures_core::future::Future;
use futures_core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
use futures_task::{FutureObj, LocalFutureObj, LocalSpawn, Spawn, SpawnError};
use futures_util::future::FutureExt;
use glib_sys;
use std::mem;
use std::pin;
use std::ptr;
use translate::{from_glib_borrow, from_glib_full, mut_override, Borrowed, ToGlib};
use ThreadGuard;

use MainContext;
use MainLoop;
use Priority;
use Source;

// Wrapper around Send Futures and non-Send Futures that will panic
// if the non-Send Future is polled/dropped from a different thread
// than where this was created.
enum FutureWrapper {
    Send(FutureObj<'static, ()>),
    NonSend(ThreadGuard<LocalFutureObj<'static, ()>>),
}

impl Future for FutureWrapper {
    type Output = ();

    fn poll(self: pin::Pin<&mut Self>, ctx: &mut Context) -> Poll<()> {
        match self.get_mut() {
            FutureWrapper::Send(fut) => fut.poll_unpin(ctx),
            FutureWrapper::NonSend(fut) => fut.get_mut().poll_unpin(ctx),
        }
    }
}

// The TaskSource and WakerSource are split up as the TaskSource
// must only be finalized on the thread that owns the main context
// but the WakerSource is passed around to arbitrary threads for
// being able to wake up the TaskSource.
//
// The WakerSource is set up as a child source of the TaskSource, i.e.
// whenever it is ready also the TaskSource is ready.
#[repr(C)]
struct TaskSource {
    source: glib_sys::GSource,
    future: FutureWrapper,
    waker: Waker,
}

#[repr(C)]
struct WakerSource {
    source: glib_sys::GSource,
}

impl TaskSource {
    unsafe extern "C" fn dispatch(
        source: *mut glib_sys::GSource,
        callback: glib_sys::GSourceFunc,
        _user_data: glib_sys::gpointer,
    ) -> glib_sys::gboolean {
        let source = &mut *(source as *mut TaskSource);
        assert!(callback.is_none());

        // Poll the TaskSource and ensure we're never called again if the
        // contained Future resolved now.
        if let Poll::Ready(()) = source.poll() {
            glib_sys::G_SOURCE_REMOVE
        } else {
            glib_sys::G_SOURCE_CONTINUE
        }
    }

    unsafe extern "C" fn finalize(source: *mut glib_sys::GSource) {
        let source = source as *mut TaskSource;

        // This will panic if the future was a local future and is dropped from
        // a different thread than where it was created.
        ptr::drop_in_place(&mut (*source).future);

        // Drop the waker to unref the underlying GSource
        ptr::drop_in_place(&mut (*source).waker);
    }
}

impl WakerSource {
    unsafe fn clone_raw(waker: *const ()) -> RawWaker {
        static VTABLE: RawWakerVTable = RawWakerVTable::new(
            WakerSource::clone_raw,
            WakerSource::wake_raw,
            WakerSource::wake_by_ref_raw,
            WakerSource::drop_raw,
        );

        let waker = waker as *const glib_sys::GSource;
        glib_sys::g_source_ref(mut_override(waker));
        RawWaker::new(waker as *const (), &VTABLE)
    }

    unsafe fn wake_raw(waker: *const ()) {
        Self::wake_by_ref_raw(waker);
        Self::drop_raw(waker);
    }

    unsafe fn wake_by_ref_raw(waker: *const ()) {
        let waker = waker as *const glib_sys::GSource;
        glib_sys::g_source_set_ready_time(mut_override(waker), 0);
    }

    unsafe fn drop_raw(waker: *const ()) {
        let waker = waker as *const glib_sys::GSource;
        glib_sys::g_source_unref(mut_override(waker));
    }

    unsafe extern "C" fn dispatch(
        source: *mut glib_sys::GSource,
        _callback: glib_sys::GSourceFunc,
        _user_data: glib_sys::gpointer,
    ) -> glib_sys::gboolean {
        // Set ready-time to -1 so that we're not called again before
        // being woken up another time.
        glib_sys::g_source_set_ready_time(mut_override(source), -1);
        glib_sys::G_SOURCE_CONTINUE
    }
}

unsafe impl Send for TaskSource {}
unsafe impl Sync for TaskSource {}

unsafe impl Send for WakerSource {}
unsafe impl Sync for WakerSource {}

impl TaskSource {
    #[allow(clippy::new_ret_no_self)]
    fn new(priority: Priority, future: FutureWrapper) -> Source {
        unsafe {
            static TASK_SOURCE_FUNCS: glib_sys::GSourceFuncs = glib_sys::GSourceFuncs {
                check: None,
                prepare: None,
                dispatch: Some(TaskSource::dispatch),
                finalize: Some(TaskSource::finalize),
                closure_callback: None,
                closure_marshal: None,
            };

            static WAKER_SOURCE_FUNCS: glib_sys::GSourceFuncs = glib_sys::GSourceFuncs {
                check: None,
                prepare: None,
                dispatch: Some(WakerSource::dispatch),
                finalize: None,
                closure_callback: None,
                closure_marshal: None,
            };

            let source = glib_sys::g_source_new(
                mut_override(&TASK_SOURCE_FUNCS),
                mem::size_of::<TaskSource>() as u32,
            );

            let waker_source = glib_sys::g_source_new(
                mut_override(&WAKER_SOURCE_FUNCS),
                mem::size_of::<WakerSource>() as u32,
            );

            glib_sys::g_source_set_priority(source, priority.to_glib());
            glib_sys::g_source_add_child_source(source, waker_source);

            {
                let source = &mut *(source as *mut TaskSource);
                ptr::write(&mut source.future, future);

                // This creates a new reference to the waker source.
                let waker = Waker::from_raw(WakerSource::clone_raw(waker_source as *const ()));
                ptr::write(&mut source.waker, waker);
            }

            // Set ready time to 0 so that the source is immediately dispatched
            // for doing the initial polling. This will then either resolve the
            // future or register the waker wherever necessary.
            glib_sys::g_source_set_ready_time(waker_source, 0);

            // Unref the waker source, a strong reference to it is stored inside
            // the task source directly and inside the task source as child source.
            glib_sys::g_source_unref(waker_source);

            from_glib_full(source)
        }
    }

    fn poll(&mut self) -> Poll<()> {
        let source = &self.source as *const _;
        let executor: Borrowed<MainContext> =
            unsafe { from_glib_borrow(glib_sys::g_source_get_context(mut_override(source))) };

        assert!(
            executor.is_owner(),
            "Polling futures only allowed if the thread is owning the MainContext"
        );

        executor.with_thread_default(|| {
            let _enter = futures_executor::enter().unwrap();
            let mut context = Context::from_waker(&self.waker);

            // This will panic if the future was a local future and is called from
            // a different thread than where it was created.
            self.future.poll_unpin(&mut context)
        })
    }
}

impl MainContext {
    /// Spawn a new infallible `Future` on the main context.
    ///
    /// This can be called from any thread and will execute the future from the thread
    /// where main context is running, e.g. via a `MainLoop`.
    pub fn spawn<F: Future<Output = ()> + Send + 'static>(&self, f: F) {
        self.spawn_with_priority(::PRIORITY_DEFAULT, f);
    }

    /// Spawn a new infallible `Future` on the main context.
    ///
    /// The given `Future` does not have to be `Send`.
    ///
    /// This can be called only from the thread where the main context is running, e.g.
    /// from any other `Future` that is executed on this main context, or after calling
    /// `push_thread_default` or `acquire` on the main context.
    pub fn spawn_local<F: Future<Output = ()> + 'static>(&self, f: F) {
        self.spawn_local_with_priority(::PRIORITY_DEFAULT, f);
    }

    /// Spawn a new infallible `Future` on the main context, with a non-default priority.
    ///
    /// This can be called from any thread and will execute the future from the thread
    /// where main context is running, e.g. via a `MainLoop`.
    pub fn spawn_with_priority<F: Future<Output = ()> + Send + 'static>(
        &self,
        priority: Priority,
        f: F,
    ) {
        let f = FutureObj::new(Box::new(f));
        let source = TaskSource::new(priority, FutureWrapper::Send(f));
        source.attach(Some(&*self));
    }

    /// Spawn a new infallible `Future` on the main context, with a non-default priority.
    ///
    /// The given `Future` does not have to be `Send`.
    ///
    /// This can be called only from the thread where the main context is running, e.g.
    /// from any other `Future` that is executed on this main context, or after calling
    /// `push_thread_default` or `acquire` on the main context.
    pub fn spawn_local_with_priority<F: Future<Output = ()> + 'static>(
        &self,
        priority: Priority,
        f: F,
    ) {
        assert!(
            self.is_owner(),
            "Spawning local futures only allowed on the thread owning the MainContext"
        );
        let f = LocalFutureObj::new(Box::new(f));
        let source = TaskSource::new(priority, FutureWrapper::NonSend(ThreadGuard::new(f)));
        source.attach(Some(&*self));
    }

    /// Runs a new, infallible `Future` on the main context and block until it finished, returning
    /// the result of the `Future`.
    ///
    /// The given `Future` does not have to be `Send` or `'static`.
    ///
    /// This must only be called if no `MainLoop` or anything else is running on this specific main
    /// context.
    #[allow(clippy::transmute_ptr_to_ptr)]
    pub fn block_on<F: Future>(&self, f: F) -> F::Output {
        let mut res = None;
        let l = MainLoop::new(Some(&*self), false);
        let l_clone = l.clone();

        unsafe {
            let f = f.then(|r| {
                res = Some(r);
                l_clone.quit();
                futures_util::future::ready(())
            });

            // Super-unsafe: We transmute here to get rid of the 'static lifetime
            let f = LocalFutureObj::new(Box::new(f));
            let f: LocalFutureObj<'static, ()> = mem::transmute(f);

            let source = TaskSource::new(
                ::PRIORITY_DEFAULT,
                FutureWrapper::NonSend(ThreadGuard::new(f)),
            );
            source.attach(Some(&*self));
        }

        l.run();

        res.unwrap()
    }
}

impl Spawn for MainContext {
    fn spawn_obj(&self, f: FutureObj<'static, ()>) -> Result<(), SpawnError> {
        let source = TaskSource::new(::PRIORITY_DEFAULT, FutureWrapper::Send(f));
        source.attach(Some(&*self));
        Ok(())
    }
}

impl LocalSpawn for MainContext {
    fn spawn_local_obj(&self, f: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
        let source = TaskSource::new(
            ::PRIORITY_DEFAULT,
            FutureWrapper::NonSend(ThreadGuard::new(f)),
        );
        source.attach(Some(&*self));
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use futures_channel::oneshot;
    use futures_util::future::TryFutureExt;
    use std::sync::mpsc;
    use std::thread;

    #[test]
    fn test_spawn() {
        let c = MainContext::new();
        let l = ::MainLoop::new(Some(&c), false);

        let (sender, receiver) = mpsc::channel();
        let (o_sender, o_receiver) = oneshot::channel();

        let l_clone = l.clone();
        c.spawn(
            o_receiver
                .and_then(move |()| {
                    sender.send(()).unwrap();
                    l_clone.quit();

                    futures_util::future::ok(())
                })
                .then(|res| {
                    assert!(res.is_ok());
                    futures_util::future::ready(())
                }),
        );

        thread::spawn(move || {
            l.run();
        });

        o_sender.send(()).unwrap();

        receiver.recv().unwrap();
    }

    #[test]
    fn test_spawn_local() {
        let c = MainContext::new();
        let l = ::MainLoop::new(Some(&c), false);

        c.push_thread_default();
        let l_clone = l.clone();
        c.spawn_local(futures_util::future::lazy(move |_ctx| {
            l_clone.quit();
        }));

        l.run();

        c.pop_thread_default();
    }

    #[test]
    fn test_block_on() {
        let c = MainContext::new();

        let mut v = None;
        {
            let v = &mut v;

            let future = futures_util::future::lazy(|_ctx| {
                *v = Some(123);
                Ok::<i32, ()>(123)
            });

            let res = c.block_on(future);
            assert_eq!(res, Ok(123));
        }

        assert_eq!(v, Some(123));
    }
}
<|endoftext|>


<commit_before>use std;
use crate::for_other_imageflow_crates::preludes::external_without_std::*;
use crate::ffi;
use crate::{Context, CError, Result, JsonResponse, ErrorKind};
use crate::ffi::ImageflowJobIo;
use imageflow_types::collections::AddRemoveSet;
use uuid::Uuid;
use std::rc::Rc;

/// Codecs own their IoProxy, but sometimes Imageflow needs access (like when it needs to read a buffer).
/// This enum can be extended as needed.
pub enum IoProxyRef<'a>{
   Borrow(&'a IoProxy),
    BoxedAsRef(Box<dyn AsRef<IoProxy>>),
    Ref(Ref<'a, IoProxy>)
}
impl<'a> IoProxyRef<'a> {
    pub fn map<B, F>(self, mut f: F) -> B
        where
            F: FnMut(&IoProxy) -> B{

        match self {
            IoProxyRef::Borrow(r) => f(r),
            IoProxyRef::BoxedAsRef(r) => f((*r).as_ref()),
            IoProxyRef::Ref(r) => f(&*r)
        }

    }
}

/// A safer proxy over the C IO object.
/// Implements Read/Write
pub struct IoProxy{
    c: &'static Context,
    classic: *mut ImageflowJobIo,
    io_id: i32,
    path: Option<PathBuf>,
    c_path: Option<CString>,
    drop_with_job: bool
}

impl io::Read for IoProxy{

    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize>{
        self.read_to_buffer(self.c, buf).and_then(|read_bytes|
            if read_bytes.leading_zeros() < 1 {
                Err(nerror!(ErrorKind::InvalidArgument, "read_bytes likely came from a negative integer. Imageflow prohibits having the leading bit set on unsigned integers (this reduces the maximum value to 2^31 or 2^63)."))

            }else{
                Ok(read_bytes as usize)
            }).map_err(|e| std::io::Error::new(io::ErrorKind::Other, e))
    }
}
impl io::Write for IoProxy{

    fn write(&mut self, buf: &[u8]) -> io::Result<usize>{
        self.write_from_buffer(self.c, buf).and_then(|written_bytes|
            if written_bytes.leading_zeros() < 1 {
                Err(nerror!(ErrorKind::InvalidArgument, "written_bytes likely came from a negative integer. Imageflow prohibits having the leading bit set on unsigned integers (this reduces the maximum value to 2^31 or 2^63)."))
            }else{
                Ok(written_bytes as usize)
            }).map_err(|e| std::io::Error::new(io::ErrorKind::Other, e))
    }
    fn flush(&mut self) -> io::Result<()>{
        Ok(())
    }

}

/// Allows access to Write trait through an Rc<RefCell<>>
pub struct IoProxyProxy(pub Rc<RefCell<IoProxy>>);
impl Write for IoProxyProxy{
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
        self.0.borrow_mut().write(buf)
    }

    fn flush(&mut self) -> ::std::io::Result<()> {
        self.0.borrow_mut().flush()
    }
}

//
//context: *mut ImageflowContext,
//mode: IoMode,// Call nothing, dereference nothing, if this is 0
//read_fn: Option<IoReadFn>,// Optional for write modes
//write_fn: Option<IoWriteFn>,// Optional for read modes
//position_fn: Option<IoPositionFn>, // Optional for sequential modes
//seek_fn: Option<IoSeekFn>, // Optional for sequential modes
//dispose_fn: Option<DestructorFn>,// Optional
//user_data: *mut c_void,
///// Whoever sets up this structure can populate this value - or set it to -1 - as they
///// wish. useful for resource estimation.
//optional_file_length: i64

impl IoProxy {
    pub fn io_id(&self) -> i32{
        self.io_id
    }

    pub fn create(context: &Context, io_id: i32) -> IoProxy {
        IoProxy {
            //This ugly breaking of lifetimes means that
            //NOTHING is preventing use-after-free
            //if someone finds a way to access an owned Codec that isn't borrowed from the Context
            //TODO: Consider replacing with Weak<T>
            c: unsafe { &*(context as *const Context) },
            //io_id: io_id,
            classic: ptr::null_mut(),
            path: None,
            c_path: None,
            drop_with_job: false,
            io_id
        }
    }
    pub fn wrap_classic(context: &Context, classic_io: *mut crate::ffi::ImageflowJobIo, io_id: i32) -> Result<IoProxy> {
        if classic_io.is_null() {
            Err(cerror!(context, "Failed to create ImageflowJobIo *"))
        } else {
            let mut proxy = IoProxy::create(context, io_id);
            proxy.classic = classic_io;
            Ok(proxy)
        }
    }

    pub fn get_io_ptr(&self) -> *mut crate::ffi::ImageflowJobIo {
        self.classic
    }

    fn classic_io(&self) -> Option<&ImageflowJobIo>{
        if self.classic.is_null(){
            None
        }else{
            Some(unsafe{ &*self.classic})
        }

    }

    pub fn read_to_buffer(&self, context: &Context, buffer: &mut [u8]) -> Result<i64> {
        if let Some(classic) = self.classic_io() {
            if let Some(read_fn) = classic.read_fn {
                let read = read_fn(context.flow_c(), self.classic, buffer.as_mut_ptr(), buffer.len());
                if read < buffer.len() as i64 {
                    if context.c_error().has_error() {
                        Err(cerror!(context, "Read failed"))
                    } else {
                        Ok(read)
                    }
                } else {
                    Ok(read)
                }
            }else {
                Err(unimpl!())
            }
        }else{
            Err(unimpl!())
        }

    }
    pub fn write_from_buffer(&self, context: &Context, buffer: &[u8]) -> Result<i64> {
        if let Some(classic) = self.classic_io() {
            if let Some(write_fn) = classic.write_fn {
                let write =write_fn(context.flow_c(), self.classic, buffer.as_ptr(), buffer.len());
                if write < buffer.len() as i64 {
                    if context.c_error().has_error() {
                        Err(cerror!(context, "Write failed"))
                    } else {
                        Ok(write)
                    }
                } else {
                    Ok(write)
                }
            } else {
                Err(unimpl!())
            }
        } else {
            Err(unimpl!())
        }
    }

    pub fn seek(&self, context: &Context, position: i64) -> Result<bool> {
        if let Some(classic) = self.classic_io() {
            if let Some(seek_fn) = classic.seek_fn {
                Ok(seek_fn(context.flow_c(), self.classic, position))
            } else {
                Err(unimpl!())
            }
        } else {
            Err(unimpl!())
        }
    }

    fn check_io_id(context: &Context, io_id: i32) -> Result<()>{
        if context.io_id_present(io_id){
            Err(nerror!(ErrorKind::DuplicateIoId, "io_id {} is already in use on this context", io_id))
        }else{
            Ok(())
        }
    }

    pub fn read_slice<'a>(context: &'a Context, io_id: i32,  bytes: &'a [u8]) -> Result<IoProxy> {
        IoProxy::check_io_id(context,io_id)?;
        unsafe {
            // Owner parameter is only for io_struct, not buffer.
            let p = crate::ffi::flow_io_create_from_memory(context.flow_c(),
                                                      crate::ffi::IoMode::ReadSeekable,
                                                      bytes.as_ptr(),
                                                      bytes.len(),
                                                      context.flow_c() as *const libc::c_void,
                                                      ptr::null());
            IoProxy::wrap_classic(context, p, io_id).map_err(|e| e.at(here!()))
        }
    }

    // This could actually live as long as the context, but this isn't on the context....
    // but if a constraint, we could add context as an input parameter
    pub fn get_output_buffer_bytes<'b>(&self, c: &'b Context) -> Result<&'b[u8]> {
        unsafe {
            let mut buf_start: *const u8 = ptr::null();
            let mut buf_len: usize = 0;
            let flow_c = self.c.flow_c();
            let classic = self.classic;

            let worked = crate::ffi::flow_io_get_output_buffer(flow_c    ,
                                                          classic,
                                                          &mut buf_start as *mut *const u8,
                                                          &mut buf_len as *mut usize);
            if !worked {
                Err(cerror!(self.c))
            } else if buf_start.is_null() {
                // Not sure how output buffer is null... no writes yet?
                Err(unimpl!())
            } else {
                Ok(std::slice::from_raw_parts(buf_start, buf_len))
            }
        }
    }

    pub fn create_output_buffer(context: &Context, io_id: i32) -> Result<IoProxy> {
        IoProxy::check_io_id(context,io_id)?;
        unsafe {
            let p =
                crate::ffi::flow_io_create_for_output_buffer(context.flow_c(),
                                                        context.flow_c() as *const libc::c_void);
            IoProxy::wrap_classic(context, p, io_id).map_err(|e| e.at(here!()))
        }
    }

    pub fn copy_slice(context: &Context, io_id: i32, bytes: & [u8]) -> Result<IoProxy> {
        IoProxy::check_io_id(context,io_id)?;
        unsafe {
            let buf: *mut u8 =
                crate::ffi::flow_context_calloc(context.flow_c(),
                                           1,
                                           bytes.len(),
                                           ptr::null(),
                                           context.flow_c() as *const libc::c_void,
                                           ptr::null(),
                                           0) as *mut u8;

            if buf.is_null() {
                return Err(err_oom!());
            }
            ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());

            let io_ptr = crate::ffi::flow_io_create_from_memory(context.flow_c(),
                                                           crate::ffi::IoMode::ReadSeekable,
                                                           buf,
                                                           bytes.len(),
                                                           context.flow_c() as *const libc::c_void,
                                                           ptr::null());
            if io_ptr.is_null(){
                let _ = crate::ffi::flow_destroy(context.flow_c(), buf as *mut libc::c_void, ptr::null(), 0);
            }
            IoProxy::wrap_classic(context, io_ptr, io_id).map_err(|e| e.at(here!()))
        }
    }

    pub fn file_with_mode<T: AsRef<Path>>(context: &Context, io_id: i32, path: T, mode: crate::IoMode) -> Result<IoProxy> {
        IoProxy::check_io_id(context,io_id)?;
        unsafe {
            // TODO: add support for a wider variety of character sets
            // Winows fopen needs ansii
            let path_buf = path.as_ref().to_path_buf();

            let c_path = {
                let path_str = path_buf.to_str().ok_or_else(||nerror!(ErrorKind::InvalidArgument, "The argument 'path' is invalid UTF-8."))?;
                CString::new(path_str).map_err(|e| nerror!(ErrorKind::InvalidArgument, "The argument 'path' contains a null byte.") )?
            };

            let p = crate::ffi::flow_io_create_for_file(context.flow_c(),
                                                   mode,
                                                   c_path.as_ptr(),
                                                   context.flow_c() as *const libc::c_void);

            let mut proxy = IoProxy::wrap_classic(context, p, io_id).map_err(|e| e.at(here!()))?;
            proxy.c_path = Some(c_path);
            proxy.path = Some(path_buf);
            Ok(proxy)
        }
    }

}
<commit_msg>spelling: windows<commit_after>use std;
use crate::for_other_imageflow_crates::preludes::external_without_std::*;
use crate::ffi;
use crate::{Context, CError, Result, JsonResponse, ErrorKind};
use crate::ffi::ImageflowJobIo;
use imageflow_types::collections::AddRemoveSet;
use uuid::Uuid;
use std::rc::Rc;

/// Codecs own their IoProxy, but sometimes Imageflow needs access (like when it needs to read a buffer).
/// This enum can be extended as needed.
pub enum IoProxyRef<'a>{
   Borrow(&'a IoProxy),
    BoxedAsRef(Box<dyn AsRef<IoProxy>>),
    Ref(Ref<'a, IoProxy>)
}
impl<'a> IoProxyRef<'a> {
    pub fn map<B, F>(self, mut f: F) -> B
        where
            F: FnMut(&IoProxy) -> B{

        match self {
            IoProxyRef::Borrow(r) => f(r),
            IoProxyRef::BoxedAsRef(r) => f((*r).as_ref()),
            IoProxyRef::Ref(r) => f(&*r)
        }

    }
}

/// A safer proxy over the C IO object.
/// Implements Read/Write
pub struct IoProxy{
    c: &'static Context,
    classic: *mut ImageflowJobIo,
    io_id: i32,
    path: Option<PathBuf>,
    c_path: Option<CString>,
    drop_with_job: bool
}

impl io::Read for IoProxy{

    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize>{
        self.read_to_buffer(self.c, buf).and_then(|read_bytes|
            if read_bytes.leading_zeros() < 1 {
                Err(nerror!(ErrorKind::InvalidArgument, "read_bytes likely came from a negative integer. Imageflow prohibits having the leading bit set on unsigned integers (this reduces the maximum value to 2^31 or 2^63)."))

            }else{
                Ok(read_bytes as usize)
            }).map_err(|e| std::io::Error::new(io::ErrorKind::Other, e))
    }
}
impl io::Write for IoProxy{

    fn write(&mut self, buf: &[u8]) -> io::Result<usize>{
        self.write_from_buffer(self.c, buf).and_then(|written_bytes|
            if written_bytes.leading_zeros() < 1 {
                Err(nerror!(ErrorKind::InvalidArgument, "written_bytes likely came from a negative integer. Imageflow prohibits having the leading bit set on unsigned integers (this reduces the maximum value to 2^31 or 2^63)."))
            }else{
                Ok(written_bytes as usize)
            }).map_err(|e| std::io::Error::new(io::ErrorKind::Other, e))
    }
    fn flush(&mut self) -> io::Result<()>{
        Ok(())
    }

}

/// Allows access to Write trait through an Rc<RefCell<>>
pub struct IoProxyProxy(pub Rc<RefCell<IoProxy>>);
impl Write for IoProxyProxy{
    fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
        self.0.borrow_mut().write(buf)
    }

    fn flush(&mut self) -> ::std::io::Result<()> {
        self.0.borrow_mut().flush()
    }
}

//
//context: *mut ImageflowContext,
//mode: IoMode,// Call nothing, dereference nothing, if this is 0
//read_fn: Option<IoReadFn>,// Optional for write modes
//write_fn: Option<IoWriteFn>,// Optional for read modes
//position_fn: Option<IoPositionFn>, // Optional for sequential modes
//seek_fn: Option<IoSeekFn>, // Optional for sequential modes
//dispose_fn: Option<DestructorFn>,// Optional
//user_data: *mut c_void,
///// Whoever sets up this structure can populate this value - or set it to -1 - as they
///// wish. useful for resource estimation.
//optional_file_length: i64

impl IoProxy {
    pub fn io_id(&self) -> i32{
        self.io_id
    }

    pub fn create(context: &Context, io_id: i32) -> IoProxy {
        IoProxy {
            //This ugly breaking of lifetimes means that
            //NOTHING is preventing use-after-free
            //if someone finds a way to access an owned Codec that isn't borrowed from the Context
            //TODO: Consider replacing with Weak<T>
            c: unsafe { &*(context as *const Context) },
            //io_id: io_id,
            classic: ptr::null_mut(),
            path: None,
            c_path: None,
            drop_with_job: false,
            io_id
        }
    }
    pub fn wrap_classic(context: &Context, classic_io: *mut crate::ffi::ImageflowJobIo, io_id: i32) -> Result<IoProxy> {
        if classic_io.is_null() {
            Err(cerror!(context, "Failed to create ImageflowJobIo *"))
        } else {
            let mut proxy = IoProxy::create(context, io_id);
            proxy.classic = classic_io;
            Ok(proxy)
        }
    }

    pub fn get_io_ptr(&self) -> *mut crate::ffi::ImageflowJobIo {
        self.classic
    }

    fn classic_io(&self) -> Option<&ImageflowJobIo>{
        if self.classic.is_null(){
            None
        }else{
            Some(unsafe{ &*self.classic})
        }

    }

    pub fn read_to_buffer(&self, context: &Context, buffer: &mut [u8]) -> Result<i64> {
        if let Some(classic) = self.classic_io() {
            if let Some(read_fn) = classic.read_fn {
                let read = read_fn(context.flow_c(), self.classic, buffer.as_mut_ptr(), buffer.len());
                if read < buffer.len() as i64 {
                    if context.c_error().has_error() {
                        Err(cerror!(context, "Read failed"))
                    } else {
                        Ok(read)
                    }
                } else {
                    Ok(read)
                }
            }else {
                Err(unimpl!())
            }
        }else{
            Err(unimpl!())
        }

    }
    pub fn write_from_buffer(&self, context: &Context, buffer: &[u8]) -> Result<i64> {
        if let Some(classic) = self.classic_io() {
            if let Some(write_fn) = classic.write_fn {
                let write =write_fn(context.flow_c(), self.classic, buffer.as_ptr(), buffer.len());
                if write < buffer.len() as i64 {
                    if context.c_error().has_error() {
                        Err(cerror!(context, "Write failed"))
                    } else {
                        Ok(write)
                    }
                } else {
                    Ok(write)
                }
            } else {
                Err(unimpl!())
            }
        } else {
            Err(unimpl!())
        }
    }

    pub fn seek(&self, context: &Context, position: i64) -> Result<bool> {
        if let Some(classic) = self.classic_io() {
            if let Some(seek_fn) = classic.seek_fn {
                Ok(seek_fn(context.flow_c(), self.classic, position))
            } else {
                Err(unimpl!())
            }
        } else {
            Err(unimpl!())
        }
    }

    fn check_io_id(context: &Context, io_id: i32) -> Result<()>{
        if context.io_id_present(io_id){
            Err(nerror!(ErrorKind::DuplicateIoId, "io_id {} is already in use on this context", io_id))
        }else{
            Ok(())
        }
    }

    pub fn read_slice<'a>(context: &'a Context, io_id: i32,  bytes: &'a [u8]) -> Result<IoProxy> {
        IoProxy::check_io_id(context,io_id)?;
        unsafe {
            // Owner parameter is only for io_struct, not buffer.
            let p = crate::ffi::flow_io_create_from_memory(context.flow_c(),
                                                      crate::ffi::IoMode::ReadSeekable,
                                                      bytes.as_ptr(),
                                                      bytes.len(),
                                                      context.flow_c() as *const libc::c_void,
                                                      ptr::null());
            IoProxy::wrap_classic(context, p, io_id).map_err(|e| e.at(here!()))
        }
    }

    // This could actually live as long as the context, but this isn't on the context....
    // but if a constraint, we could add context as an input parameter
    pub fn get_output_buffer_bytes<'b>(&self, c: &'b Context) -> Result<&'b[u8]> {
        unsafe {
            let mut buf_start: *const u8 = ptr::null();
            let mut buf_len: usize = 0;
            let flow_c = self.c.flow_c();
            let classic = self.classic;

            let worked = crate::ffi::flow_io_get_output_buffer(flow_c    ,
                                                          classic,
                                                          &mut buf_start as *mut *const u8,
                                                          &mut buf_len as *mut usize);
            if !worked {
                Err(cerror!(self.c))
            } else if buf_start.is_null() {
                // Not sure how output buffer is null... no writes yet?
                Err(unimpl!())
            } else {
                Ok(std::slice::from_raw_parts(buf_start, buf_len))
            }
        }
    }

    pub fn create_output_buffer(context: &Context, io_id: i32) -> Result<IoProxy> {
        IoProxy::check_io_id(context,io_id)?;
        unsafe {
            let p =
                crate::ffi::flow_io_create_for_output_buffer(context.flow_c(),
                                                        context.flow_c() as *const libc::c_void);
            IoProxy::wrap_classic(context, p, io_id).map_err(|e| e.at(here!()))
        }
    }

    pub fn copy_slice(context: &Context, io_id: i32, bytes: & [u8]) -> Result<IoProxy> {
        IoProxy::check_io_id(context,io_id)?;
        unsafe {
            let buf: *mut u8 =
                crate::ffi::flow_context_calloc(context.flow_c(),
                                           1,
                                           bytes.len(),
                                           ptr::null(),
                                           context.flow_c() as *const libc::c_void,
                                           ptr::null(),
                                           0) as *mut u8;

            if buf.is_null() {
                return Err(err_oom!());
            }
            ptr::copy_nonoverlapping(bytes.as_ptr(), buf, bytes.len());

            let io_ptr = crate::ffi::flow_io_create_from_memory(context.flow_c(),
                                                           crate::ffi::IoMode::ReadSeekable,
                                                           buf,
                                                           bytes.len(),
                                                           context.flow_c() as *const libc::c_void,
                                                           ptr::null());
            if io_ptr.is_null(){
                let _ = crate::ffi::flow_destroy(context.flow_c(), buf as *mut libc::c_void, ptr::null(), 0);
            }
            IoProxy::wrap_classic(context, io_ptr, io_id).map_err(|e| e.at(here!()))
        }
    }

    pub fn file_with_mode<T: AsRef<Path>>(context: &Context, io_id: i32, path: T, mode: crate::IoMode) -> Result<IoProxy> {
        IoProxy::check_io_id(context,io_id)?;
        unsafe {
            // TODO: add support for a wider variety of character sets
            // Windows fopen needs ansii
            let path_buf = path.as_ref().to_path_buf();

            let c_path = {
                let path_str = path_buf.to_str().ok_or_else(||nerror!(ErrorKind::InvalidArgument, "The argument 'path' is invalid UTF-8."))?;
                CString::new(path_str).map_err(|e| nerror!(ErrorKind::InvalidArgument, "The argument 'path' contains a null byte.") )?
            };

            let p = crate::ffi::flow_io_create_for_file(context.flow_c(),
                                                   mode,
                                                   c_path.as_ptr(),
                                                   context.flow_c() as *const libc::c_void);

            let mut proxy = IoProxy::wrap_classic(context, p, io_id).map_err(|e| e.at(here!()))?;
            proxy.c_path = Some(c_path);
            proxy.path = Some(path_buf);
            Ok(proxy)
        }
    }

}
<|endoftext|>