<commit_before>/*
 * Copyright (c) 2017-2020 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//! Core primitive types for relm.
//!
//! The primary type is `EventStream`.

#![warn(
    missing_docs,
    trivial_casts,
    trivial_numeric_casts,
    unused_extern_crates,
    unused_import_braces,
    unused_qualifications,
)]

mod source;

use std::cell::RefCell;
use std::collections::VecDeque;
use std::marker::PhantomData;
use std::rc::{Rc, Weak};
use std::sync::mpsc::{self, Receiver, SendError};

use self::source::{SourceFuncs, new_source, source_get};

use glib::{
    MainContext,
    Source,
    SourceId,
};

/// Handle to a EventStream to emit messages.
pub struct StreamHandle<MSG> {
    stream: Weak<RefCell<_EventStream<MSG>>>,
}

impl<MSG> Clone for StreamHandle<MSG> {
    fn clone(&self) -> Self {
        Self {
            stream: self.stream.clone(),
        }
    }
}

impl<MSG> StreamHandle<MSG> {
    fn new(stream: Weak<RefCell<_EventStream<MSG>>>) -> Self {
        Self {
            stream: stream,
        }
    }

    /// Same as clone(). Useful for the macro relm_observer_new.
    pub fn stream(&self) -> Self {
        self.clone()
    }

    /// Send the `event` message to the stream and the observers.
    pub fn emit(&self, msg: MSG) {
        if let Some(ref stream) = self.stream.upgrade() {
            emit(stream, msg);
        }
        else {
            panic!("Trying to call emit() on a dropped EventStream");
        }
    }

    /// Lock the stream (don't emit message) until the `Lock` goes out of scope.
    pub fn lock(&self) -> Lock<MSG> {
        if let Some(ref stream) = self.stream.upgrade() {
            stream.borrow_mut().locked = true;
            Lock {
                stream: stream.clone(),
            }
        }
        else {
            panic!("Trying to call lock() on a dropped EventStream");
        }
    }

    /// Add an observer to the event stream.
    /// This callback will be called every time a message is emmited.
    pub fn observe<CALLBACK: Fn(&MSG) + 'static>(&self, callback: CALLBACK) {
        if let Some(ref stream) = self.stream.upgrade() {
            stream.borrow_mut().observers.push(Rc::new(callback));
        }
        else {
            panic!("Trying to call observe() on a dropped EventStream");
        }
    }
}

/// A lock is used to temporarily stop emitting messages.
#[must_use]
pub struct Lock<MSG> {
    stream: Rc<RefCell<_EventStream<MSG>>>,
}

impl<MSG> Drop for Lock<MSG> {
    fn drop(&mut self) {
        self.stream.borrow_mut().locked = false;
    }
}

struct ChannelData<MSG> {
    callback: Box<dyn FnMut(MSG)>,
    peeked_value: Option<MSG>,
    receiver: Receiver<MSG>,
}

/// A wrapper over a `std::sync::mpsc::Sender` to wakeup the glib event loop when sending a
/// message.
pub struct Sender<MSG> {
    sender: mpsc::Sender<MSG>,
}

impl<MSG> Clone for Sender<MSG> {
    fn clone(&self) -> Self {
        Self {
            sender: self.sender.clone(),
        }
    }
}

impl<MSG> Sender<MSG> {
    /// Send a message and wakeup the event loop.
    pub fn send(&self, msg: MSG) -> Result<(), SendError<MSG>> {
        let result = self.sender.send(msg);
        let context = MainContext::default();
        context.wakeup();
        result
    }
}

/// A channel to send a message to a relm widget from another thread.
pub struct Channel<MSG> {
    _source: Source,
    _phantom: PhantomData<MSG>,
}

impl<MSG> Channel<MSG> {
    /// Create a new channel with a callback that will be called when a message is received.
    pub fn new<CALLBACK: FnMut(MSG) + 'static>(callback: CALLBACK) -> (Self, Sender<MSG>) {
        let (sender, receiver) = mpsc::channel();
        let source = new_source(RefCell::new(ChannelData {
            callback: Box::new(callback),
            peeked_value: None,
            receiver,
        }));
        let main_context = MainContext::default();
        source.attach(Some(&main_context));
        (Self {
            _source: source,
            _phantom: PhantomData,
        }, Sender {
            sender,
        })
    }
}

impl<MSG> SourceFuncs for RefCell<ChannelData<MSG>> {
    fn dispatch(&self) -> bool {
        // TODO: show errors.
        let msg = self.borrow_mut().peeked_value.take().or_else(|| {
            self.borrow().receiver.try_recv().ok()
        });
        if let Some(msg) = msg {
            let callback = &mut self.borrow_mut().callback;
            callback(msg);
        }
        true
    }

    fn prepare(&self) -> (bool, Option<u32>) {
        if self.borrow().peeked_value.is_some() {
            return (true, None);
        }
        let peek_val = self.borrow().receiver.try_recv().ok();
        self.borrow_mut().peeked_value = peek_val;
        (self.borrow().peeked_value.is_some(), None)
    }

}

struct _EventStream<MSG> {
    events: VecDeque<MSG>,
    locked: bool,
    observers: Vec<Rc<dyn Fn(&MSG)>>,
}

impl<MSG> SourceFuncs for SourceData<MSG> {
    fn dispatch(&self) -> bool {
        let event = self.stream.borrow_mut().events.pop_front();
        if let (Some(event), Some(callback)) = (event, self.callback.borrow_mut().as_mut()) {
            callback(event);
        }
        true
    }

    fn prepare(&self) -> (bool, Option<u32>) {
        (!self.stream.borrow().events.is_empty(), None)
    }

}

struct SourceData<MSG> {
    callback: Rc<RefCell<Option<Box<dyn FnMut(MSG)>>>>,
    stream: Rc<RefCell<_EventStream<MSG>>>,
}

fn emit<MSG>(stream: &Rc<RefCell<_EventStream<MSG>>>, msg: MSG) {
    if !stream.borrow().locked {
        let len = stream.borrow().observers.len();
        for i in 0..len {
            let observer = stream.borrow().observers[i].clone();
            observer(&msg);
        }

        stream.borrow_mut().events.push_back(msg);
    }
}

/// A stream of messages to be used for widget/signal communication and inter-widget communication.
/// EventStream cannot be send to another thread. Use a `Channel` `Sender` instead.
pub struct EventStream<MSG> {
    source: Source,
    source_id: Option<SourceId>,
    _phantom: PhantomData<*mut MSG>,
}

impl<MSG> Drop for EventStream<MSG> {
    fn drop(&mut self) {
        // Ignore error since we're in a destructor.
        let _ = Source::remove(self.source_id.take().expect("source id"));
        self.close();
    }
}

impl<MSG> EventStream<MSG> {
    fn get_callback(&self) -> Rc<RefCell<Option<Box<dyn FnMut(MSG)>>>> {
        source_get::<SourceData<MSG>>(&self.source).callback.clone()
    }

    fn get_stream(&self) -> Rc<RefCell<_EventStream<MSG>>> {
        source_get::<SourceData<MSG>>(&self.source).stream.clone()
    }
}

impl<MSG> EventStream<MSG> {
    /// Create a new event stream.
    pub fn new() -> Self {
        let event_stream: _EventStream<MSG> = _EventStream {
            events: VecDeque::new(),
            locked: false,
            observers: vec![],
        };
        let source = new_source(SourceData {
            callback: Rc::new(RefCell::new(None)),
            stream: Rc::new(RefCell::new(event_stream)),
        });
        let main_context = MainContext::default();
        let source_id = Some(source.attach(Some(&main_context)));
        EventStream {
            source,
            source_id,
            _phantom: PhantomData,
        }
    }

    /// Close the event stream, i.e. stop processing messages.
    pub fn close(&self) {
        self.source.destroy();
    }

    /// Synonym for downgrade().
    pub fn stream(&self) -> StreamHandle<MSG> {
        self.downgrade()
    }

    /// Create a Clone-able EventStream handle.
    pub fn downgrade(&self) -> StreamHandle<MSG> {
        StreamHandle::new(Rc::downgrade(&self.get_stream()))
    }

    /// Send the `event` message to the stream and the observers.
    pub fn emit(&self, event: MSG) {
        let stream = self.get_stream();
        if !stream.borrow().locked {
            let len = stream.borrow().observers.len();
            for i in 0..len {
                let observer = stream.borrow().observers[i].clone();
                observer(&event);
            }

            stream.borrow_mut().events.push_back(event);
        }
    }

    /// Lock the stream (don't emit message) until the `Lock` goes out of scope.
    pub fn lock(&self) -> Lock<MSG> {
        let stream = self.get_stream();
        stream.borrow_mut().locked = true;
        Lock {
            stream: self.get_stream().clone(),
        }
    }

    /// Add an observer to the event stream.
    /// This callback will be called every time a message is emmited.
    pub fn observe<CALLBACK: Fn(&MSG) + 'static>(&self, callback: CALLBACK) {
        let stream = self.get_stream();
        stream.borrow_mut().observers.push(Rc::new(callback));
    }

    /// Add a callback to the event stream.
    /// This is the main callback and received a owned version of the message, in contrast to
    /// observe().
    pub fn set_callback<CALLBACK: FnMut(MSG) + 'static>(&self, callback: CALLBACK) {
        let source_callback = self.get_callback();
        *source_callback.borrow_mut() = Some(Box::new(callback));
    }
}
<commit_msg>Use a StreamHandle inside the Lock<commit_after>/*
 * Copyright (c) 2017-2020 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//! Core primitive types for relm.
//!
//! The primary type is `EventStream`.

#![warn(
    missing_docs,
    trivial_casts,
    trivial_numeric_casts,
    unused_extern_crates,
    unused_import_braces,
    unused_qualifications,
)]

mod source;

use std::cell::RefCell;
use std::collections::VecDeque;
use std::marker::PhantomData;
use std::rc::{Rc, Weak};
use std::sync::mpsc::{self, Receiver, SendError};

use self::source::{SourceFuncs, new_source, source_get};

use glib::{
    MainContext,
    Source,
    SourceId,
};

/// Handle to a EventStream to emit messages.
pub struct StreamHandle<MSG> {
    stream: Weak<RefCell<_EventStream<MSG>>>,
}

impl<MSG> Clone for StreamHandle<MSG> {
    fn clone(&self) -> Self {
        Self {
            stream: self.stream.clone(),
        }
    }
}

impl<MSG> StreamHandle<MSG> {
    fn new(stream: Weak<RefCell<_EventStream<MSG>>>) -> Self {
        Self {
            stream: stream,
        }
    }

    /// Same as clone(). Useful for the macro relm_observer_new.
    pub fn stream(&self) -> Self {
        self.clone()
    }

    /// Send the `event` message to the stream and the observers.
    pub fn emit(&self, msg: MSG) {
        if let Some(ref stream) = self.stream.upgrade() {
            emit(stream, msg);
        }
        else {
            panic!("Trying to call emit() on a dropped EventStream");
        }
    }

    /// Lock the stream (don't emit message) until the `Lock` goes out of scope.
    pub fn lock(&self) -> Lock<MSG> {
        if let Some(ref stream) = self.stream.upgrade() {
            stream.borrow_mut().locked = true;
            Lock {
                stream: self.clone(),
            }
        }
        else {
            panic!("Trying to call lock() on a dropped EventStream");
        }
    }

    fn unlock(&self) {
        if let Some(ref stream) = self.stream.upgrade() {
            stream.borrow_mut().locked = false;
        }
        else {
            panic!("Trying to call unlock() on a dropped EventStream");
        }
    }

    /// Add an observer to the event stream.
    /// This callback will be called every time a message is emmited.
    pub fn observe<CALLBACK: Fn(&MSG) + 'static>(&self, callback: CALLBACK) {
        if let Some(ref stream) = self.stream.upgrade() {
            stream.borrow_mut().observers.push(Rc::new(callback));
        }
        else {
            panic!("Trying to call observe() on a dropped EventStream");
        }
    }
}

/// A lock is used to temporarily stop emitting messages.
#[must_use]
pub struct Lock<MSG> {
    stream: StreamHandle<MSG>,
}

impl<MSG> Drop for Lock<MSG> {
    fn drop(&mut self) {
        self.stream.unlock();
    }
}

struct ChannelData<MSG> {
    callback: Box<dyn FnMut(MSG)>,
    peeked_value: Option<MSG>,
    receiver: Receiver<MSG>,
}

/// A wrapper over a `std::sync::mpsc::Sender` to wakeup the glib event loop when sending a
/// message.
pub struct Sender<MSG> {
    sender: mpsc::Sender<MSG>,
}

impl<MSG> Clone for Sender<MSG> {
    fn clone(&self) -> Self {
        Self {
            sender: self.sender.clone(),
        }
    }
}

impl<MSG> Sender<MSG> {
    /// Send a message and wakeup the event loop.
    pub fn send(&self, msg: MSG) -> Result<(), SendError<MSG>> {
        let result = self.sender.send(msg);
        let context = MainContext::default();
        context.wakeup();
        result
    }
}

/// A channel to send a message to a relm widget from another thread.
pub struct Channel<MSG> {
    _source: Source,
    _phantom: PhantomData<MSG>,
}

impl<MSG> Channel<MSG> {
    /// Create a new channel with a callback that will be called when a message is received.
    pub fn new<CALLBACK: FnMut(MSG) + 'static>(callback: CALLBACK) -> (Self, Sender<MSG>) {
        let (sender, receiver) = mpsc::channel();
        let source = new_source(RefCell::new(ChannelData {
            callback: Box::new(callback),
            peeked_value: None,
            receiver,
        }));
        let main_context = MainContext::default();
        source.attach(Some(&main_context));
        (Self {
            _source: source,
            _phantom: PhantomData,
        }, Sender {
            sender,
        })
    }
}

impl<MSG> SourceFuncs for RefCell<ChannelData<MSG>> {
    fn dispatch(&self) -> bool {
        // TODO: show errors.
        let msg = self.borrow_mut().peeked_value.take().or_else(|| {
            self.borrow().receiver.try_recv().ok()
        });
        if let Some(msg) = msg {
            let callback = &mut self.borrow_mut().callback;
            callback(msg);
        }
        true
    }

    fn prepare(&self) -> (bool, Option<u32>) {
        if self.borrow().peeked_value.is_some() {
            return (true, None);
        }
        let peek_val = self.borrow().receiver.try_recv().ok();
        self.borrow_mut().peeked_value = peek_val;
        (self.borrow().peeked_value.is_some(), None)
    }

}

struct _EventStream<MSG> {
    events: VecDeque<MSG>,
    locked: bool,
    // We use an Rc here to be able to clone the function to call it so that we don't borrow the
    // stream while calling the function. Otherwise, calling an observer could trigger a
    // borrow_mut() which would result in a panic.
    observers: Vec<Rc<dyn Fn(&MSG)>>,
}

impl<MSG> SourceFuncs for SourceData<MSG> {
    fn dispatch(&self) -> bool {
        let event = self.stream.borrow_mut().events.pop_front();
        if let (Some(event), Some(callback)) = (event, self.callback.borrow_mut().as_mut()) {
            callback(event);
        }
        true
    }

    fn prepare(&self) -> (bool, Option<u32>) {
        (!self.stream.borrow().events.is_empty(), None)
    }

}

struct SourceData<MSG> {
    callback: Rc<RefCell<Option<Box<dyn FnMut(MSG)>>>>,
    stream: Rc<RefCell<_EventStream<MSG>>>,
}

fn emit<MSG>(stream: &Rc<RefCell<_EventStream<MSG>>>, msg: MSG) {
    if !stream.borrow().locked {
        let len = stream.borrow().observers.len();
        for i in 0..len {
            let observer = stream.borrow().observers[i].clone();
            observer(&msg);
        }

        stream.borrow_mut().events.push_back(msg);
    }
}

/// A stream of messages to be used for widget/signal communication and inter-widget communication.
/// EventStream cannot be send to another thread. Use a `Channel` `Sender` instead.
pub struct EventStream<MSG> {
    source: Source,
    source_id: Option<SourceId>,
    _phantom: PhantomData<*mut MSG>,
}

impl<MSG> Drop for EventStream<MSG> {
    fn drop(&mut self) {
        // Ignore error since we're in a destructor.
        let _ = Source::remove(self.source_id.take().expect("source id"));
        self.close();
    }
}

impl<MSG> EventStream<MSG> {
    fn get_callback(&self) -> Rc<RefCell<Option<Box<dyn FnMut(MSG)>>>> {
        source_get::<SourceData<MSG>>(&self.source).callback.clone()
    }

    fn get_stream(&self) -> &Rc<RefCell<_EventStream<MSG>>> {
        &source_get::<SourceData<MSG>>(&self.source).stream
    }
}

impl<MSG> EventStream<MSG> {
    /// Create a new event stream.
    pub fn new() -> Self {
        let event_stream: _EventStream<MSG> = _EventStream {
            events: VecDeque::new(),
            locked: false,
            observers: vec![],
        };
        let source = new_source(SourceData {
            callback: Rc::new(RefCell::new(None)),
            stream: Rc::new(RefCell::new(event_stream)),
        });
        let main_context = MainContext::default();
        let source_id = Some(source.attach(Some(&main_context)));
        EventStream {
            source,
            source_id,
            _phantom: PhantomData,
        }
    }

    /// Close the event stream, i.e. stop processing messages.
    pub fn close(&self) {
        self.source.destroy();
    }

    /// Synonym for downgrade().
    pub fn stream(&self) -> StreamHandle<MSG> {
        self.downgrade()
    }

    /// Create a Clone-able EventStream handle.
    pub fn downgrade(&self) -> StreamHandle<MSG> {
        StreamHandle::new(Rc::downgrade(self.get_stream()))
    }

    /// Send the `event` message to the stream and the observers.
    pub fn emit(&self, event: MSG) {
        let stream = self.get_stream();
        emit(stream, event)
    }

    /// Lock the stream (don't emit message) until the `Lock` goes out of scope.
    pub fn lock(&self) -> Lock<MSG> {
        let stream = self.get_stream();
        stream.borrow_mut().locked = true;
        Lock {
            stream: self.stream(),
        }
    }

    /// Add an observer to the event stream.
    /// This callback will be called every time a message is emmited.
    pub fn observe<CALLBACK: Fn(&MSG) + 'static>(&self, callback: CALLBACK) {
        let stream = self.get_stream();
        stream.borrow_mut().observers.push(Rc::new(callback));
    }

    /// Add a callback to the event stream.
    /// This is the main callback and received a owned version of the message, in contrast to
    /// observe().
    pub fn set_callback<CALLBACK: FnMut(MSG) + 'static>(&self, callback: CALLBACK) {
        let source_callback = self.get_callback();
        *source_callback.borrow_mut() = Some(Box::new(callback));
    }
}
<|endoftext|>


<commit_before>//! Implements Project 25's data packet specification.

mod coder;
mod fragment;
mod header;
mod params;
mod payload;

pub mod crc;
pub mod interleave;
pub mod packet;
pub mod values;

pub use self::fragment::{ConfirmedFragments, UnconfirmedFragments};

pub use self::header::{
    ConfirmedHeader,
    ConfirmedFields,
    ConfirmedPreamble,
    UnconfirmedHeader,
    UnconfirmedFields,
    UnconfirmedPreamble,
    ServiceAccessPoint,
    Manufacturer,
    LogicalLink,
    BlockCount,
    PadCount,
    Sequencing,
    DataOffset,
};

pub use self::payload::{
    ConfirmedPayload,
    UnconfirmedPayload,
};
<commit_msg>Make all data modules public<commit_after>//! Implements Project 25's data packet specification.

pub mod coder;
pub mod crc;
pub mod fragment;
pub mod header;
pub mod interleave;
pub mod packet;
pub mod params;
pub mod payload;
pub mod values;

pub use self::fragment::{ConfirmedFragments, UnconfirmedFragments};

pub use self::header::{
    ConfirmedHeader,
    ConfirmedFields,
    ConfirmedPreamble,
    UnconfirmedHeader,
    UnconfirmedFields,
    UnconfirmedPreamble,
    ServiceAccessPoint,
    Manufacturer,
    LogicalLink,
    BlockCount,
    PadCount,
    Sequencing,
    DataOffset,
};

pub use self::payload::{
    ConfirmedPayload,
    UnconfirmedPayload,
};
<|endoftext|>


<commit_before>// Copyright (c) 2020 DDN. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

#![recursion_limit = "256"]

#[cfg(feature = "postgres-interop")]
#[macro_use]
extern crate diesel;

pub mod models;
#[cfg(feature = "postgres-interop")]
pub mod schema;

#[cfg(feature = "postgres-interop")]
pub mod alerts;

#[cfg(feature = "postgres-interop")]
pub mod command;

#[cfg(feature = "postgres-interop")]
pub mod fidtaskqueue;

#[cfg(feature = "postgres-interop")]
pub mod hosts;

#[cfg(feature = "postgres-interop")]
pub mod job;

#[cfg(feature = "postgres-interop")]
pub mod lustrefid;

#[cfg(feature = "postgres-interop")]
pub mod profile;

#[cfg(feature = "postgres-interop")]
pub mod repo;

#[cfg(feature = "postgres-interop")]
pub mod step;

#[cfg(feature = "postgres-interop")]
pub mod task;

use futures::channel::oneshot;
use thiserror::Error;

#[cfg(feature = "warp-filters")]
use futures::{channel::mpsc, future, Future, StreamExt, TryFutureExt};
#[cfg(feature = "warp-filters")]
use warp::Filter;

#[cfg(feature = "postgres-interop")]
use diesel::{
    prelude::RunQueryDsl,
    query_builder::{QueryFragment, QueryId},
    r2d2::{ConnectionManager, Pool},
    PgConnection,
};
#[cfg(feature = "postgres-interop")]
use iml_manager_env::get_db_conn_string;

#[cfg(feature = "postgres-interop")]
/// Allows for a generic return type for Insert statements, that can be used in either a sync or async
/// context.
pub trait Executable:
    RunQueryDsl<diesel::PgConnection> + QueryFragment<diesel::pg::Pg> + QueryId
{
}

#[cfg(feature = "postgres-interop")]
impl<T> Executable for T where
    T: RunQueryDsl<diesel::PgConnection> + QueryFragment<diesel::pg::Pg> + QueryId
{
}

#[cfg(feature = "postgres-interop")]
pub type DbPool = Pool<ConnectionManager<diesel::PgConnection>>;

#[cfg(feature = "postgres-interop")]
pub use tokio_diesel;

#[cfg(feature = "postgres-interop")]
pub use r2d2;

#[derive(Debug, Error)]
pub enum ImlOrmError {
    #[error(transparent)]
    R2D2Error(#[from] r2d2::Error),
    #[error(transparent)]
    OneshotCanceled(#[from] oneshot::Canceled),
    #[error(transparent)]
    AsyncError(#[from] tokio_diesel::AsyncError),
}

#[cfg(feature = "warp-filters")]
impl warp::reject::Reject for ImlOrmError {}

#[cfg(feature = "postgres-interop")]
/// Get a new connection pool based on the envs connection string.
pub fn pool() -> Result<DbPool, ImlOrmError> {
    let manager = ConnectionManager::<PgConnection>::new(get_db_conn_string());

    Pool::builder()
        .build(manager)
        .map_err(ImlOrmError::R2D2Error)
}

#[cfg(feature = "warp-filters")]
type PoolSender = oneshot::Sender<DbPool>;

#[cfg(feature = "warp-filters")]
pub fn get_cloned_pool(
    pool: DbPool,
) -> (mpsc::UnboundedSender<PoolSender>, impl Future<Output = ()>) {
    let (tx, rx) = mpsc::unbounded();

    let fut = rx.for_each(move |sender: PoolSender| {
        let _ = sender
            .send(pool.clone())
            .map_err(|_| tracing::info!("channel recv dropped before we could hand out a pool"));

        future::ready(())
    });

    (tx, fut)
}

/// Creates a warp `Filter` that will hand out
/// a cloned `DbPool` handle for each request.
#[cfg(feature = "warp-filters")]
pub async fn create_pool_filter() -> Result<
    (
        impl Future<Output = ()>,
        impl Filter<Extract = (DbPool,), Error = warp::Rejection> + Clone,
    ),
    ImlOrmError,
> {
    let conn = pool()?;

    let (tx, fut) = get_cloned_pool(conn);

    let filter = warp::any().and_then(move || {
        let (tx2, rx2) = oneshot::channel();

        tx.unbounded_send(tx2).unwrap();

        rx2.map_err(ImlOrmError::OneshotCanceled)
            .map_err(warp::reject::custom)
    });

    Ok((fut, filter))
}
<commit_msg>Add trait for determining changes between old and new collections (#1918)<commit_after>// Copyright (c) 2020 DDN. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

#![recursion_limit = "256"]

#[cfg(feature = "postgres-interop")]
#[macro_use]
extern crate diesel;

pub mod models;
#[cfg(feature = "postgres-interop")]
pub mod schema;

#[cfg(feature = "postgres-interop")]
pub mod alerts;

#[cfg(feature = "postgres-interop")]
pub mod command;

#[cfg(feature = "postgres-interop")]
pub mod fidtaskqueue;

#[cfg(feature = "postgres-interop")]
pub mod hosts;

#[cfg(feature = "postgres-interop")]
pub mod job;

#[cfg(feature = "postgres-interop")]
pub mod lustrefid;

#[cfg(feature = "postgres-interop")]
pub mod profile;

#[cfg(feature = "postgres-interop")]
pub mod repo;

#[cfg(feature = "postgres-interop")]
pub mod step;

#[cfg(feature = "postgres-interop")]
pub mod task;

use futures::channel::oneshot;
use thiserror::Error;

#[cfg(feature = "warp-filters")]
use futures::{channel::mpsc, future, Future, StreamExt, TryFutureExt};
#[cfg(feature = "warp-filters")]
use warp::Filter;

#[cfg(feature = "postgres-interop")]
use diesel::{
    prelude::RunQueryDsl,
    query_builder::{QueryFragment, QueryId},
    r2d2::{ConnectionManager, Pool},
    PgConnection,
};
#[cfg(feature = "postgres-interop")]
use iml_manager_env::get_db_conn_string;

#[cfg(feature = "postgres-interop")]
/// Allows for a generic return type for Insert statements, that can be used in either a sync or async
/// context.
pub trait Executable:
    RunQueryDsl<diesel::PgConnection> + QueryFragment<diesel::pg::Pg> + QueryId
{
}

#[cfg(feature = "postgres-interop")]
impl<T> Executable for T where
    T: RunQueryDsl<diesel::PgConnection> + QueryFragment<diesel::pg::Pg> + QueryId
{
}

#[cfg(feature = "postgres-interop")]
pub type DbPool = Pool<ConnectionManager<diesel::PgConnection>>;

#[cfg(feature = "postgres-interop")]
pub use tokio_diesel;

#[cfg(feature = "postgres-interop")]
pub use r2d2;

#[derive(Debug, Error)]
pub enum ImlOrmError {
    #[error(transparent)]
    R2D2Error(#[from] r2d2::Error),
    #[error(transparent)]
    OneshotCanceled(#[from] oneshot::Canceled),
    #[error(transparent)]
    AsyncError(#[from] tokio_diesel::AsyncError),
}

#[cfg(feature = "warp-filters")]
impl warp::reject::Reject for ImlOrmError {}

#[cfg(feature = "postgres-interop")]
/// Get a new connection pool based on the envs connection string.
pub fn pool() -> Result<DbPool, ImlOrmError> {
    let manager = ConnectionManager::<PgConnection>::new(get_db_conn_string());

    Pool::builder()
        .build(manager)
        .map_err(ImlOrmError::R2D2Error)
}

#[cfg(feature = "warp-filters")]
type PoolSender = oneshot::Sender<DbPool>;

#[cfg(feature = "warp-filters")]
pub fn get_cloned_pool(
    pool: DbPool,
) -> (mpsc::UnboundedSender<PoolSender>, impl Future<Output = ()>) {
    let (tx, rx) = mpsc::unbounded();

    let fut = rx.for_each(move |sender: PoolSender| {
        let _ = sender
            .send(pool.clone())
            .map_err(|_| tracing::info!("channel recv dropped before we could hand out a pool"));

        future::ready(())
    });

    (tx, fut)
}

/// Creates a warp `Filter` that will hand out
/// a cloned `DbPool` handle for each request.
#[cfg(feature = "warp-filters")]
pub async fn create_pool_filter() -> Result<
    (
        impl Future<Output = ()>,
        impl Filter<Extract = (DbPool,), Error = warp::Rejection> + Clone,
    ),
    ImlOrmError,
> {
    let conn = pool()?;

    let (tx, fut) = get_cloned_pool(conn);

    let filter = warp::any().and_then(move || {
        let (tx2, rx2) = oneshot::channel();

        tx.unbounded_send(tx2).unwrap();

        rx2.map_err(ImlOrmError::OneshotCanceled)
            .map_err(warp::reject::custom)
    });

    Ok((fut, filter))
}

mod change {
    use std::{
        cmp::{Eq, Ord},
        collections::BTreeSet,
        fmt::Debug,
        iter::FromIterator,
    };

    pub trait Changeable: Eq + Ord + Debug {}

    impl<T> Changeable for T where T: Eq + Ord + Debug {}

    #[derive(Debug)]
    pub struct Additions<T: Changeable>(pub Vec<T>);

    #[derive(Debug)]
    pub struct Updates<T: Changeable>(pub Vec<T>);

    #[derive(Debug)]
    pub struct Deletions<T: Changeable>(pub Vec<T>);

    pub trait GetChanges<T: Changeable> {
        /// Given new and old items, this method compares them and
        /// returns a tuple of `Additions`, `Updates`, and `Deletions`.
        fn get_changes<'a>(
            &'a self,
            old: &'a Self,
        ) -> (
            Option<Additions<&'a T>>,
            Option<Updates<&'a T>>,
            Option<Deletions<&'a T>>,
        );
    }

    impl<T: Changeable> GetChanges<T> for Vec<T> {
        fn get_changes<'a>(
            &'a self,
            old: &'a Self,
        ) -> (
            Option<Additions<&'a T>>,
            Option<Updates<&'a T>>,
            Option<Deletions<&'a T>>,
        ) {
            let new = BTreeSet::from_iter(self);
            let old = BTreeSet::from_iter(old);

            let to_add: Vec<_> = new.difference(&old).map(|x| *x).collect();

            let to_add = if to_add.is_empty() {
                None
            } else {
                Some(Additions(to_add))
            };

            let to_change: Vec<_> = new.intersection(&old).map(|x| *x).collect();

            let to_change = if to_change.is_empty() {
                None
            } else {
                Some(Updates(to_change))
            };

            let to_remove: Vec<_> = old.difference(&new).map(|x| *x).collect();

            let to_remove = if to_remove.is_empty() {
                None
            } else {
                Some(Deletions(to_remove))
            };

            (to_add, to_change, to_remove)
        }
    }
}

pub use change::*;
<|endoftext|>


<commit_before>//! The Metal framework defines data types that are used in multiple places throughout the framework.
//!
//! Taken from https://developer.apple.com/library/ios/documentation/Metal/Reference/MetalDataTypes_Ref/index.html

use cocoa::foundation::NSUInteger;
use libc::uint32_t;

/// An RGBA value used for a color pixel.
#[repr(C)]
#[derive(Clone, Copy, PartialEq)]
pub struct MTLClearColor {
    /// The red color channel.
    pub red: f64,

    /// The green color channel.
    pub blue: f64,

    /// The blue color channel.
    pub green: f64,

    /// The alpha color channel.
    pub alpha: f64
}

/// A location of a pixel in an image or texture, relative to the upper-left corner which is (0,0).
#[repr(C)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct MTLOrigin {
    /// The x coordinate of the location.
    pub x: NSUInteger,

    /// The y coordinate of the location.
    pub y: NSUInteger,

    /// The z coordinate of the location.
    pub z: NSUInteger
}

/// A rectangular block of pixels in an image or texture, defined by its upper-left corner and its size.
#[repr(C)]
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
pub struct MTLRegion {
    /// The location of the upper-left corner of the block.
    pub origin: MTLOrigin,

    /// The size of the block.
    pub size: MTLSize
}

/// A rectangle for the scissor fragment test.
#[repr(C)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct MTLScissorRect {
    /// The x window coordinate of the upper-left corner of the scissor rectangle.
    pub x: NSUInteger,

    /// The y window coordinate of the upper-left corner of the scissor rectangle.
    pub y: NSUInteger,

    /// The width of the scissor rectangle, in pixels.
    pub width: NSUInteger,

    /// The height of the scissor rectangle, in pixels.
    pub height: NSUInteger
}

/// A set of dimensions to declare the size of an object, such as an image, texture, threadgroup, or grid.
#[repr(C)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct MTLSize {
    /// The x dimension of the object size.
    pub width: NSUInteger,

    /// The y dimension of the object size.
    pub height: NSUInteger,

    /// The z dimension of the object size.
    pub depth: NSUInteger
}

/// A 3D rectangular region for the viewport clipping.
#[repr(C)]
#[derive(Clone, Copy, PartialEq)]
pub struct MTLViewport {
    /// The x coordinate of the upper-left corner of the viewport.
    pub originX: f64,

    /// The y coordinate of the upper-left corner of the viewport.
    pub originY: f64,

    /// The width of the viewport, in pixels.
    pub width: f64,

    /// The height of the viewport, in pixels.
    pub height: f64,

    /// The z coordinate of the near clipping plane of the viewport.
    pub znear: f64,

    /// The z coordinate of the far clipping plane of the viewport.
    pub zfar: f64
}

/// The data layout required for drawing primitives via indirect buffer calls.
#[repr(C)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct MTLDrawPrimitivesIndirectArguments {
    /// The number of indices to draw.
    pub vertexCount: uint32_t,

    /// The number of instances to draw.
    pub instanceCount: uint32_t,

    /// The first index to draw.
    pub vertexStart: uint32_t,

    /// The first instance to draw.
    pub baseInstance: uint32_t
}

/// The data layout required for drawing indexed primitives via indirect buffer calls.
#[repr(C)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct MTLDrawIndexedPrimitivesIndirectArguments {
    /// For each instance, the number of indices to read from the index buffer.
    pub indexCount: uint32_t,

    /// The number of instances to draw.
    pub instanceCount: uint32_t,

    /// The first index to draw.
    pub indexStart: uint32_t,

    /// The first vertex to draw.
    pub baseVertex: uint32_t,

    /// The first instance to draw.
    pub baseInstance: uint32_t
}

/// The data layout required for dispatching threadgroups via indirect buffer calls.
#[repr(C)]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct MTLDispatchThreadgroupsIndirectArguments {
    /// The number of threadgroups for the grid, in each dimension.
    threadgroupsPerGrid: [uint32_t; 3]
}
<commit_msg>Derive `Debug` for all value types<commit_after>//! The Metal framework defines data types that are used in multiple places throughout the framework.
//!
//! Taken from https://developer.apple.com/library/ios/documentation/Metal/Reference/MetalDataTypes_Ref/index.html

use cocoa::foundation::NSUInteger;
use libc::uint32_t;

/// An RGBA value used for a color pixel.
#[repr(C)]
#[derive(Clone, Copy, PartialEq)]
pub struct MTLClearColor {
    /// The red color channel.
    pub red: f64,

    /// The green color channel.
    pub blue: f64,

    /// The blue color channel.
    pub green: f64,

    /// The alpha color channel.
    pub alpha: f64
}

/// A location of a pixel in an image or texture, relative to the upper-left corner which is (0,0).
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLOrigin {
    /// The x coordinate of the location.
    pub x: NSUInteger,

    /// The y coordinate of the location.
    pub y: NSUInteger,

    /// The z coordinate of the location.
    pub z: NSUInteger
}

/// A rectangular block of pixels in an image or texture, defined by its upper-left corner and its size.
#[repr(C)]
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
pub struct MTLRegion {
    /// The location of the upper-left corner of the block.
    pub origin: MTLOrigin,

    /// The size of the block.
    pub size: MTLSize
}

/// A rectangle for the scissor fragment test.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLScissorRect {
    /// The x window coordinate of the upper-left corner of the scissor rectangle.
    pub x: NSUInteger,

    /// The y window coordinate of the upper-left corner of the scissor rectangle.
    pub y: NSUInteger,

    /// The width of the scissor rectangle, in pixels.
    pub width: NSUInteger,

    /// The height of the scissor rectangle, in pixels.
    pub height: NSUInteger
}

/// A set of dimensions to declare the size of an object, such as an image, texture, threadgroup, or grid.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLSize {
    /// The x dimension of the object size.
    pub width: NSUInteger,

    /// The y dimension of the object size.
    pub height: NSUInteger,

    /// The z dimension of the object size.
    pub depth: NSUInteger
}

/// A 3D rectangular region for the viewport clipping.
#[repr(C)]
#[derive(Clone, Copy, PartialEq)]
pub struct MTLViewport {
    /// The x coordinate of the upper-left corner of the viewport.
    pub originX: f64,

    /// The y coordinate of the upper-left corner of the viewport.
    pub originY: f64,

    /// The width of the viewport, in pixels.
    pub width: f64,

    /// The height of the viewport, in pixels.
    pub height: f64,

    /// The z coordinate of the near clipping plane of the viewport.
    pub znear: f64,

    /// The z coordinate of the far clipping plane of the viewport.
    pub zfar: f64
}

/// The data layout required for drawing primitives via indirect buffer calls.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLDrawPrimitivesIndirectArguments {
    /// The number of indices to draw.
    pub vertexCount: uint32_t,

    /// The number of instances to draw.
    pub instanceCount: uint32_t,

    /// The first index to draw.
    pub vertexStart: uint32_t,

    /// The first instance to draw.
    pub baseInstance: uint32_t
}

/// The data layout required for drawing indexed primitives via indirect buffer calls.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLDrawIndexedPrimitivesIndirectArguments {
    /// For each instance, the number of indices to read from the index buffer.
    pub indexCount: uint32_t,

    /// The number of instances to draw.
    pub instanceCount: uint32_t,

    /// The first index to draw.
    pub indexStart: uint32_t,

    /// The first vertex to draw.
    pub baseVertex: uint32_t,

    /// The first instance to draw.
    pub baseInstance: uint32_t
}

/// The data layout required for dispatching threadgroups via indirect buffer calls.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct MTLDispatchThreadgroupsIndirectArguments {
    /// The number of threadgroups for the grid, in each dimension.
    threadgroupsPerGrid: [uint32_t; 3]
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

mod crypto_kv_storage;
mod crypto_storage;
mod error;
mod github;
mod in_memory;
mod kv_storage;
mod namespaced_storage;
mod on_disk;
mod policy;
mod storage;
mod vault;

pub use crate::{
    crypto_kv_storage::CryptoKVStorage,
    crypto_storage::{CryptoStorage, PublicKeyResponse},
    error::Error,
    github::GitHubStorage,
    in_memory::{InMemoryStorage, InMemoryStorageInternal},
    kv_storage::{GetResponse, KVStorage},
    namespaced_storage::NamespacedStorage,
    on_disk::{OnDiskStorage, OnDiskStorageInternal},
    policy::{Capability, Identity, Permission, Policy},
    storage::Storage,
    vault::VaultStorage,
};

#[cfg(test)]
mod tests;
<commit_msg>[secure-storage] Add bytes <-> base64 string adapter<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

mod crypto_kv_storage;
mod crypto_storage;
mod error;
mod github;
mod in_memory;
mod kv_storage;
mod namespaced_storage;
mod on_disk;
mod policy;
mod storage;
mod vault;

pub use crate::{
    crypto_kv_storage::CryptoKVStorage,
    crypto_storage::{CryptoStorage, PublicKeyResponse},
    error::Error,
    github::GitHubStorage,
    in_memory::{InMemoryStorage, InMemoryStorageInternal},
    kv_storage::{GetResponse, KVStorage},
    namespaced_storage::NamespacedStorage,
    on_disk::{OnDiskStorage, OnDiskStorageInternal},
    policy::{Capability, Identity, Permission, Policy},
    storage::Storage,
    vault::VaultStorage,
};

// Some common serializations for interacting with bytes these must be manually added to types via:
// #[serde(serialize_with = "to_base64", deserialize_with = "from_base64")]
// some_value: Vec<u8>

pub fn to_base64<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
where
    S: serde::Serializer,
{
    serializer.serialize_str(&base64::encode(bytes))
}

pub fn from_base64<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
    D: serde::Deserializer<'de>,
{
    let s: String = serde::Deserialize::deserialize(deserializer)?;
    base64::decode(s).map_err(serde::de::Error::custom)
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>//! data structures for the mastodon api
//!
//!
use std::fmt;
use std::error;

#[doc(hidden)]
mod nullbool {
    /// sometimes an instance returns null instead of false for boolean values
    /// which breaks the default deserializer
    use serde::Deserializer;
    use serde::de::Visitor;
    use std::fmt;
    use std::error::Error;

    struct NullBoolVisitor {}

    impl Visitor for NullBoolVisitor {
        type Value = bool;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("true or null")
        }

        fn visit_bool<E>(self, visitor: bool) -> Result<Self::Value, E>
            where E: Error
        {
            Ok(visitor)
        }

        fn visit_unit<E>(self) -> Result<Self::Value, E>
            where E: Error
        {
            Ok(false)
        }
    }

    pub fn de<D>(deserializer: D) -> Result<bool, D::Error>
        where D: Deserializer
    {
        deserializer.deserialize(NullBoolVisitor {})
    }
}

#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize)]
pub struct StatusId(u64);

impl fmt::Display for StatusId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize)]
pub struct UserId(u64);

impl fmt::Display for UserId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize)]
pub struct NotificationId(u64);

impl fmt::Display for NotificationId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
/// a mastodon status
pub struct Status {
    pub id: StatusId,
    uri: String,
    url: String,
    account: Account,
    in_reply_to_id: Option<StatusId>,
    in_reply_to_account_id: Option<UserId>,
    reblog: Option<Box<Status>>,
    pub content: String,
    created_at: String,
    pub reblogs_count: u64,
    pub favourites_count: u64,
    #[serde(deserialize_with = "nullbool::de")]
    reblogged: bool,
    #[serde(deserialize_with = "nullbool::de")]
    favourited: bool,
    sensitive: bool,
    spoiler_text: Option<String>,
    visibility: Visibility,
    media_attachments: Vec<MediaAttachment>,
    mentions: Vec<Mention>,
    tags: Vec<Tag>,
    application: Option<Application>,
}

impl Status {
    /// returns the original status if status is a reblog
    pub fn reblog(&self) -> Option<Self> {
        if self.reblog.is_some() {
            let r = self.reblog.clone().unwrap();
            Some(*r)
        } else {
            None
        }
    }
}

#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
/// Status Visibility
pub enum Visibility {
    Public,
    Unlisted,
    Private,
    Direct,
}

#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum MediaAttachment {
    #[serde(rename = "image")]
    Image {
        url: String,
        preview_url: String,
    },
    #[serde(rename = "video")]
    Video {
        url: String,
        preview_url: String,
    },
    #[serde(rename = "gifv")]
    GifV {
        url: String,
        preview_url: String,
    }
}

#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
/// a #hashtag
pub struct Tag {
    name: String,
    url: String,
}

impl fmt::Display for Tag {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "#{}", self.name)
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Mention {
    pub id: UserId,
    url: String,
    username: String,
    acct: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
/// Mastodon Account
pub struct Account {
    pub id: UserId,
    pub username: String,
    pub acct: String,
    pub display_name: String,
    pub note: String,
    url: String,
    avatar: String,
    header: String,
    locked: bool,
    created_at: String,
    pub followers_count: u64,
    pub following_count: u64,
    pub statuses_count: u64,
}

#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
/// the app from which the status was posted
pub struct Application {
    name: String,
    website: Option<String>,
}

#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
/// a masodon server
pub struct Instance {
    uri: String,
    pub title: String,
    pub description: String,
    email: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct RawNotification {
    #[serde(rename = "type")]
    tag: String,
    id: NotificationId,
    created_at: String,
    account: Account,
    status: Option<Status>,
}

#[derive(Debug)]
pub enum Notification {
    Mention {
        id: NotificationId,
        created_at: String,
        account: Account,
    },
    Follow {
        id: NotificationId,
        created_at: String,
        account: Account,
    },
    Favourite {
        id: NotificationId,
        created_at: String,
        account: Account,
        status: Status,
    },
    Reblog {
        id: NotificationId,
        created_at: String,
        account: Account,
        status: Status,
    },
    Unknown {
        id: NotificationId,
        created_at: String,
    }
}

impl From<RawNotification> for Notification {
    fn from(rn: RawNotification) -> Self {
        match rn.tag.as_str() {
            "mention" => Notification::Mention {
                id: rn.id,
                created_at: rn.created_at,
                account: rn.account,
            },
            "follow" => Notification::Follow {
                id: rn.id,
                created_at: rn.created_at,
                account: rn.account,
            },
            "favourite" => Notification::Favourite {
                id: rn.id,
                created_at: rn.created_at,
                account: rn.account,
                status: rn.status.unwrap(),
            },
            "reblog" => Notification::Reblog {
                id: rn.id,
                created_at: rn.created_at,
                account: rn.account,
                status: rn.status.unwrap(),
            },
            _ => Notification::Unknown {
                id: rn.id,
                created_at: rn.created_at,
            }
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
/// a server sent error
/// in most cases these will be translated into results
pub struct ServerError {
    error: String
}

impl fmt::Display for ServerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "server error: {}", self.error)
    }
}

impl error::Error for ServerError {
    fn description(&self) -> &str {
        "server error"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}<commit_msg>more docs<commit_after>//! data structures for the mastodon api
//!
//!
use std::fmt;
use std::error;

#[doc(hidden)]
mod nullbool {
    /// sometimes an instance returns null instead of false for boolean values
    /// which breaks the default deserializer
    use serde::Deserializer;
    use serde::de::Visitor;
    use std::fmt;
    use std::error::Error;

    struct NullBoolVisitor {}

    impl Visitor for NullBoolVisitor {
        type Value = bool;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("true or null")
        }

        fn visit_bool<E>(self, visitor: bool) -> Result<Self::Value, E>
            where E: Error
        {
            Ok(visitor)
        }

        fn visit_unit<E>(self) -> Result<Self::Value, E>
            where E: Error
        {
            Ok(false)
        }
    }

    pub fn de<D>(deserializer: D) -> Result<bool, D::Error>
        where D: Deserializer
    {
        deserializer.deserialize(NullBoolVisitor {})
    }
}

#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize)]
pub struct StatusId(u64);

impl fmt::Display for StatusId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize)]
pub struct UserId(u64);

impl fmt::Display for UserId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize)]
pub struct NotificationId(u64);

impl fmt::Display for NotificationId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
/// a mastodon status
pub struct Status {
    pub id: StatusId,
    uri: String,
    url: String,
    account: Account,
    in_reply_to_id: Option<StatusId>,
    in_reply_to_account_id: Option<UserId>,
    reblog: Option<Box<Status>>,
    pub content: String,
    created_at: String,
    pub reblogs_count: u64,
    pub favourites_count: u64,
    #[serde(deserialize_with = "nullbool::de")]
    reblogged: bool,
    #[serde(deserialize_with = "nullbool::de")]
    favourited: bool,
    sensitive: bool,
    spoiler_text: Option<String>,
    visibility: Visibility,
    media_attachments: Vec<MediaAttachment>,
    mentions: Vec<Mention>,
    tags: Vec<Tag>,
    application: Option<Application>,
}

impl Status {
    /// returns the original status if status is a reblog
    pub fn reblog(&self) -> Option<Self> {
        if self.reblog.is_some() {
            let r = self.reblog.clone().unwrap();
            Some(*r)
        } else {
            None
        }
    }
}

#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
/// Status Visibility
pub enum Visibility {
    Public,
    Unlisted,
    Private,
    Direct,
}

#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum MediaAttachment {
    #[serde(rename = "image")]
    Image {
        url: String,
        preview_url: String,
    },
    #[serde(rename = "video")]
    Video {
        url: String,
        preview_url: String,
    },
    #[serde(rename = "gifv")]
    GifV {
        url: String,
        preview_url: String,
    }
}

#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
/// a #hashtag
///
pub struct Tag {
    name: String,
    url: String,
}

impl fmt::Display for Tag {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "#{}", self.name)
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Mention {
    pub id: UserId,
    url: String,
    username: String,
    acct: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
/// Mastodon Account
pub struct Account {
    /// the numeric id of the user
    pub id: UserId,
    /// the accounts username
    pub username: String,
    /// equal to username for local users, includes `@domain` for remote ones
    pub acct: String,
    /// display name of account
    pub display_name: String,
    /// bio displayed on user profile
    pub note: String,
    url: String,
    avatar: String,
    header: String,
    locked: bool,
    created_at: String,
    pub followers_count: u64,
    pub following_count: u64,
    pub statuses_count: u64,
}

#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
/// the app from which the status was posted
pub struct Application {
    name: String,
    website: Option<String>,
}

#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
/// a masodon server
pub struct Instance {
    uri: String,
    pub title: String,
    pub description: String,
    email: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct RawNotification {
    #[serde(rename = "type")]
    tag: String,
    id: NotificationId,
    created_at: String,
    account: Account,
    status: Option<Status>,
}

#[derive(Debug)]
pub enum Notification {
    Mention {
        id: NotificationId,
        created_at: String,
        account: Account,
    },
    Follow {
        id: NotificationId,
        created_at: String,
        account: Account,
    },
    Favourite {
        id: NotificationId,
        created_at: String,
        account: Account,
        status: Status,
    },
    Reblog {
        id: NotificationId,
        created_at: String,
        account: Account,
        status: Status,
    },
    Unknown {
        id: NotificationId,
        created_at: String,
    }
}

impl From<RawNotification> for Notification {
    fn from(rn: RawNotification) -> Self {
        match rn.tag.as_str() {
            "mention" => Notification::Mention {
                id: rn.id,
                created_at: rn.created_at,
                account: rn.account,
            },
            "follow" => Notification::Follow {
                id: rn.id,
                created_at: rn.created_at,
                account: rn.account,
            },
            "favourite" => Notification::Favourite {
                id: rn.id,
                created_at: rn.created_at,
                account: rn.account,
                status: rn.status.unwrap(),
            },
            "reblog" => Notification::Reblog {
                id: rn.id,
                created_at: rn.created_at,
                account: rn.account,
                status: rn.status.unwrap(),
            },
            _ => Notification::Unknown {
                id: rn.id,
                created_at: rn.created_at,
            }
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
/// a server sent error
/// in most cases these will be translated into results
pub struct ServerError {
    error: String
}

impl fmt::Display for ServerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "server error: {}", self.error)
    }
}

impl error::Error for ServerError {
    fn description(&self) -> &str {
        "server error"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{Read, BufRead, BufReader, Write};
use std::path::Path;
use std::env;
use std::borrow::Cow;

pub mod snowball;

use snowball::SnowballEnv;

fn usage(name: &str) {
    println!("{} -l <language> [-i <input file>] [-o <output file>]
The input file consists of a list of words to be stemmed, one per
line. Words should be in lower case, but (for English) A-Z letters
are mapped to their a-z equivalents anyway. If omitted, stdin is
used.", name);
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() < 3 {
        usage(&args[0]);
    } else {
        let mut language = None;
        let mut input_arg = None;
        let mut output_arg = None;
        let mut i = 1;
        while i < args.len() {
            match args[i].as_str() {
                "-l" => {
                    language = Some(args[i+1].clone());
                    i += 2;
                },
                "-i" => {
                    input_arg = Some(args[i+1].clone());
                    i += 2;
                },
                "-o" => {
                    output_arg = Some(args[i+1].clone());
                    i += 2;
                },
                x => {
                    println!("Unrecognized option '{}'", x);
                    usage(&args[0]);
                    return
                }
            }
        }
        if language.is_none() {
            println!("Please specify a language!");
            usage(&args[0]);
            return;
        }
        let stemmer = Stemmer::create(language.unwrap());

        let mut output = if let Some(output_file) = output_arg {
            Box::new(File::create(Path::new(&output_file)).unwrap()) as Box<Write>
        } else {
            Box::new(std::io::stdout()) as Box<Write>
        };

        if let Some(input_file) = input_arg {
            for line in BufReader::new(File::open(Path::new(&input_file)).unwrap()).lines() {
                writeln!(&mut output, "{}", stemmer.stem(&line.unwrap())).unwrap();
            }
        } else {
            let stdin = std::io::stdin();
            for line in stdin.lock().lines() {
                writeln!(&mut output, "{}", stemmer.stem(&line.unwrap())).unwrap();
            }
        }
    }
}

/// Wrapps a usable interface around the actual stemmer implementation
pub struct Stemmer {
    stemmer: Box<Fn(&mut SnowballEnv) -> bool>,
}

impl Stemmer {
    /// Create a new stemmer from an algorithm
    pub fn create(lang: String) -> Self {
        use snowball::algorithms;
        match lang.as_str() {
            "arabic" => Stemmer { stemmer: Box::new(algorithms::arabic_stemmer::stem) },
            "danish" => Stemmer { stemmer: Box::new(algorithms::danish_stemmer::stem) },
            "dutch" => Stemmer { stemmer: Box::new(algorithms::dutch_stemmer::stem) },
            "english" => Stemmer { stemmer: Box::new(algorithms::english_stemmer::stem) },
            "finnish" => Stemmer { stemmer: Box::new(algorithms::finnish_stemmer::stem) },
            "french" => Stemmer { stemmer: Box::new(algorithms::french_stemmer::stem) },
            "german" => Stemmer { stemmer: Box::new(algorithms::german_stemmer::stem) },
            "hungarian" => Stemmer { stemmer: Box::new(algorithms::hungarian_stemmer::stem) },
            "italian" => Stemmer { stemmer: Box::new(algorithms::italian_stemmer::stem) },
            "norwegian" => Stemmer { stemmer: Box::new(algorithms::norwegian_stemmer::stem) },
            "porter" => Stemmer { stemmer: Box::new(algorithms::porter_stemmer::stem) },
            "portuguese" => Stemmer { stemmer: Box::new(algorithms::portuguese_stemmer::stem) },
            "romanian" => Stemmer { stemmer: Box::new(algorithms::romanian_stemmer::stem) },
            "russian" => Stemmer { stemmer: Box::new(algorithms::russian_stemmer::stem) },
            "spanish" => Stemmer { stemmer: Box::new(algorithms::spanish_stemmer::stem) },
            "swedish" => Stemmer { stemmer: Box::new(algorithms::swedish_stemmer::stem) },
            "tamil" => Stemmer { stemmer: Box::new(algorithms::tamil_stemmer::stem) },
            "turkish" => Stemmer { stemmer: Box::new(algorithms::turkish_stemmer::stem) },
            x => panic!("Unkown algorithm '{}'", x)
        }
    }

    /// Stem a single word
    /// Please note, that the input is expected to be all lowercase (if that is applicable).
    pub fn stem<'a>(&self, input: &'a str) -> Cow<'a, str> {
        let mut env = SnowballEnv::create(input);
        (self.stemmer)(&mut env);
        env.get_current()
    }
}
<commit_msg>fixed typo<commit_after>use std::fs::File;
use std::io::{Read, BufRead, BufReader, Write};
use std::path::Path;
use std::env;
use std::borrow::Cow;

pub mod snowball;

use snowball::SnowballEnv;

fn usage(name: &str) {
    println!("{} -l <language> [-i <input file>] [-o <output file>]
The input file consists of a list of words to be stemmed, one per
line. Words should be in lower case, but (for English) A-Z letters
are mapped to their a-z equivalents anyway. If omitted, stdin is
used.", name);
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() < 3 {
        usage(&args[0]);
    } else {
        let mut language = None;
        let mut input_arg = None;
        let mut output_arg = None;
        let mut i = 1;
        while i < args.len() {
            match args[i].as_str() {
                "-l" => {
                    language = Some(args[i+1].clone());
                    i += 2;
                },
                "-i" => {
                    input_arg = Some(args[i+1].clone());
                    i += 2;
                },
                "-o" => {
                    output_arg = Some(args[i+1].clone());
                    i += 2;
                },
                x => {
                    println!("Unrecognized option '{}'", x);
                    usage(&args[0]);
                    return
                }
            }
        }
        if language.is_none() {
            println!("Please specify a language!");
            usage(&args[0]);
            return;
        }
        let stemmer = Stemmer::create(language.unwrap());

        let mut output = if let Some(output_file) = output_arg {
            Box::new(File::create(Path::new(&output_file)).unwrap()) as Box<Write>
        } else {
            Box::new(std::io::stdout()) as Box<Write>
        };

        if let Some(input_file) = input_arg {
            for line in BufReader::new(File::open(Path::new(&input_file)).unwrap()).lines() {
                writeln!(&mut output, "{}", stemmer.stem(&line.unwrap())).unwrap();
            }
        } else {
            let stdin = std::io::stdin();
            for line in stdin.lock().lines() {
                writeln!(&mut output, "{}", stemmer.stem(&line.unwrap())).unwrap();
            }
        }
    }
}

/// Wrapps a usable interface around the actual stemmer implementation
pub struct Stemmer {
    stemmer: Box<Fn(&mut SnowballEnv) -> bool>,
}

impl Stemmer {
    /// Create a new stemmer from an algorithm
    pub fn create(lang: String) -> Self {
        use snowball::algorithms;
        match lang.as_str() {
            "arabic" => Stemmer { stemmer: Box::new(algorithms::arabic_stemmer::stem) },
            "danish" => Stemmer { stemmer: Box::new(algorithms::danish_stemmer::stem) },
            "dutch" => Stemmer { stemmer: Box::new(algorithms::dutch_stemmer::stem) },
            "english" => Stemmer { stemmer: Box::new(algorithms::english_stemmer::stem) },
            "finnish" => Stemmer { stemmer: Box::new(algorithms::finnish_stemmer::stem) },
            "french" => Stemmer { stemmer: Box::new(algorithms::french_stemmer::stem) },
            "german" => Stemmer { stemmer: Box::new(algorithms::german_stemmer::stem) },
            "hungarian" => Stemmer { stemmer: Box::new(algorithms::hungarian_stemmer::stem) },
            "italian" => Stemmer { stemmer: Box::new(algorithms::italian_stemmer::stem) },
            "norwegian" => Stemmer { stemmer: Box::new(algorithms::norwegian_stemmer::stem) },
            "porter" => Stemmer { stemmer: Box::new(algorithms::porter_stemmer::stem) },
            "portuguese" => Stemmer { stemmer: Box::new(algorithms::portuguese_stemmer::stem) },
            "romanian" => Stemmer { stemmer: Box::new(algorithms::romanian_stemmer::stem) },
            "russian" => Stemmer { stemmer: Box::new(algorithms::russian_stemmer::stem) },
            "spanish" => Stemmer { stemmer: Box::new(algorithms::spanish_stemmer::stem) },
            "swedish" => Stemmer { stemmer: Box::new(algorithms::swedish_stemmer::stem) },
            "tamil" => Stemmer { stemmer: Box::new(algorithms::tamil_stemmer::stem) },
            "turkish" => Stemmer { stemmer: Box::new(algorithms::turkish_stemmer::stem) },
            x => panic!("Unknown algorithm '{}'", x)
        }
    }

    /// Stem a single word
    /// Please note, that the input is expected to be all lowercase (if that is applicable).
    pub fn stem<'a>(&self, input: &'a str) -> Cow<'a, str> {
        let mut env = SnowballEnv::create(input);
        (self.stemmer)(&mut env);
        env.get_current()
    }
}
<|endoftext|>


<commit_before>#[link(name = "fuse",
uuid = "d37c5c30-fdcd-459d-bfca-ebb8da04b2a0",
url = "https://github.com/MicahChalmer/rust-fuse")];

#[comment = "FUSE bindings"];
#[license = "MIT"];
#[crate_type = "lib"];

use std::libc::{
    c_char,
    c_int,
    c_uint,
    c_ulong,
    c_void,
    mode_t,
    off_t,
    pid_t,
    size_t,
    stat,
    uid_t,
    gid_t
};

use std::ptr;
use std::str;
use std::vec;

// A cfuncptr is used here to stand in for a C function pointer.
// For this struct, see fuse.h
type cfuncptr = *u8;
struct c_fuse_operations {
    getattr: cfuncptr,
    readlink: cfuncptr,
    getdir: cfuncptr,
    mknod: cfuncptr,
    mkdir: cfuncptr,
    unlink: cfuncptr,
    rmdir: cfuncptr,
    symlink: cfuncptr,
    rename: cfuncptr,
    link: cfuncptr,
    chmod: cfuncptr,
    chown: cfuncptr,
    truncate: cfuncptr,
    utime: cfuncptr,
    open: cfuncptr,
    read: cfuncptr,
    write: cfuncptr,
    statfs: cfuncptr,
    flush: cfuncptr,
    release: cfuncptr,
    fsync: cfuncptr,
    setxattr: cfuncptr,
    getxattr: cfuncptr,
    listxattr: cfuncptr,
    removexattr: cfuncptr,
    opendir: cfuncptr,
    readdir: cfuncptr,
    releasedir: cfuncptr,
    fsyncdir: cfuncptr,
    init: cfuncptr,
    destroy: cfuncptr,
    access: cfuncptr,
    create: cfuncptr,
    ftruncate: cfuncptr,
    fgetattr: cfuncptr,
    lock: cfuncptr,
    utimens: cfuncptr,
    bmap: cfuncptr,

    flag_nullpath_ok: uint,
    flag_nopath: uint,
    flag_utime_omit_ok: uint,
    flag_reserved: uint,

    ioctl: cfuncptr,
    poll: cfuncptr,
    write_buf: cfuncptr,
    read_buf: cfuncptr,
    flock: cfuncptr
}

// TODO: this should not be public
pub struct fuse_file_info {
    flags: c_int,
    fh_old: c_ulong, // Old file handle, don't use
    writepage: c_int,
    direct_io: c_uint,
    keep_cache: c_uint,
    flush: c_uint,
    nonseekable: c_uint,
    flock_release: c_uint,
    padding: c_uint, // Padding.  Do not use
    fh: u64,
    lock_owner: u64
}

struct c_fuse_context {
    fuse: *c_void,
    uid: uid_t,
    gid: gid_t,
    pid: pid_t,
    private_data: *rust_fuse_data,  // we use this to know what object to call
    umask: mode_t
}

struct rust_fuse_data {
    ops: ~FuseOperations
}

extern {
    fn fuse_main_real(argc:c_int, argv:**c_char,
                      op:*c_fuse_operations, op_size: size_t,
                      user_data: *c_void);

    fn fuse_get_context() -> *c_fuse_context;

    // Workaround for the fact that we can't call into c via a function ptr right
    // from rust
    fn call_filler_function(filler: cfuncptr, buf: *c_void, name: *c_char, stbuf: *stat,
                           off: off_t) -> c_int;
}

// Used for return values from FS operations
pub type errno = c_int;

pub type fuse_fill_dir_func<'self> = &'self fn (&str, Option<stat>, off_t) -> c_int;

pub type filehandle = u64;

pub struct dir_entry {
    name: ~str,
    stat: Option<stat>,
    off: off_t
}

#[deriving(Clone, Eq, ToStr)]
pub enum ErrorOrResult<E, T> {
    Error(E),
    Result(T)
}

pub trait FuseOperations {
    fn getattr(&self, path:&str) -> ErrorOrResult<errno, stat>;
    fn readdir(&self, path:&str, filler: fuse_fill_dir_func,
               offset: off_t, info: &fuse_file_info) -> ErrorOrResult<errno, ()>;
    fn open(&self, path:&str, info: &mut fuse_file_info) -> ErrorOrResult<errno, filehandle>;
    fn read(&self, path:&str, buf:&mut [u8], size: size_t, offset: off_t,
            info: &fuse_file_info) -> ErrorOrResult<errno, c_int>;
}

unsafe fn get_context_ops() -> &~FuseOperations {
    &((*(*fuse_get_context()).private_data).ops)
}

extern fn c_getattr(path: *c_char, stbuf: *mut stat) -> errno {
    unsafe {
        let ops = get_context_ops();
        ptr::zero_memory(stbuf, 1);
        match ops.getattr(str::raw::from_c_str(path)) {
            Error(e) => -e,
            Result(st) => { ptr::copy_memory(stbuf, &st, 1); 0 }
        }
    }
}

unsafe fn option_to_ptr<T>(opt: Option<T>) -> *T {
    match opt {
        Some(ref t) => ptr::to_unsafe_ptr(t),
        None => ptr::null()
    }
}

extern fn c_readdir(path: *c_char, buf: *c_void, filler: cfuncptr,
                    offset: off_t, fi: *fuse_file_info) -> c_int {
    unsafe {
        let ops = get_context_ops();
        let fill_func: fuse_fill_dir_func = |name, st, ofs| -> c_int {
            do name.as_c_str |c_name| {
                call_filler_function(filler, buf, c_name, option_to_ptr(st), ofs)
            }
        };
        match ops.readdir(str::raw::from_c_str(path), fill_func, offset, &*fi) {
            Error(e) => -e,
            Result(_) => 0
        }
    }
}

extern fn c_read(path: *c_char, buf: *mut u8, size: size_t, offset: off_t,
                 fi: *fuse_file_info) -> c_int {
    unsafe {
        let ops = get_context_ops();
        do vec::raw::mut_buf_as_slice(buf, size as uint) |slice| {
            match ops.read(str::raw::from_c_str(path), slice, size, offset, &*fi) {
                Error(e) => -e,
                Result(sz) => sz
            }
        }
    }
}

pub fn fuse_main<T: FuseOperations>(args: ~[~str], ops: ~T) {

}
<commit_msg>Compiles with fuse_main implemented<commit_after>#[link(name = "fuse",
uuid = "d37c5c30-fdcd-459d-bfca-ebb8da04b2a0",
url = "https://github.com/MicahChalmer/rust-fuse")];

#[comment = "FUSE bindings"];
#[license = "MIT"];
#[crate_type = "lib"];

use std::libc::{
    c_char,
    c_int,
    c_uint,
    c_ulong,
    c_void,
    mode_t,
    off_t,
    pid_t,
    size_t,
    stat,
    uid_t,
    gid_t
};

use std::ptr;
use std::str;
use std::vec;
use std::sys::size_of;

// A cfuncptr is used here to stand in for a C function pointer.
// For this struct, see fuse.h
type cfuncptr = *u8;
struct c_fuse_operations {
    getattr: cfuncptr,
    readlink: cfuncptr,
    getdir: cfuncptr,
    mknod: cfuncptr,
    mkdir: cfuncptr,
    unlink: cfuncptr,
    rmdir: cfuncptr,
    symlink: cfuncptr,
    rename: cfuncptr,
    link: cfuncptr,
    chmod: cfuncptr,
    chown: cfuncptr,
    truncate: cfuncptr,
    utime: cfuncptr,
    open: cfuncptr,
    read: cfuncptr,
    write: cfuncptr,
    statfs: cfuncptr,
    flush: cfuncptr,
    release: cfuncptr,
    fsync: cfuncptr,
    setxattr: cfuncptr,
    getxattr: cfuncptr,
    listxattr: cfuncptr,
    removexattr: cfuncptr,
    opendir: cfuncptr,
    readdir: cfuncptr,
    releasedir: cfuncptr,
    fsyncdir: cfuncptr,
    init: cfuncptr,
    destroy: cfuncptr,
    access: cfuncptr,
    create: cfuncptr,
    ftruncate: cfuncptr,
    fgetattr: cfuncptr,
    lock: cfuncptr,
    utimens: cfuncptr,
    bmap: cfuncptr,

    flag_nullpath_ok: uint,
    flag_nopath: uint,
    flag_utime_omit_ok: uint,
    flag_reserved: uint,

    ioctl: cfuncptr,
    poll: cfuncptr,
    write_buf: cfuncptr,
    read_buf: cfuncptr,
    flock: cfuncptr
}

// TODO: this should not be public
pub struct fuse_file_info {
    flags: c_int,
    fh_old: c_ulong, // Old file handle, don't use
    writepage: c_int,
    direct_io: c_uint,
    keep_cache: c_uint,
    flush: c_uint,
    nonseekable: c_uint,
    flock_release: c_uint,
    padding: c_uint, // Padding.  Do not use
    fh: u64,
    lock_owner: u64
}

struct c_fuse_context {
    fuse: *c_void,
    uid: uid_t,
    gid: gid_t,
    pid: pid_t,
    private_data: *rust_fuse_data,  // we use this to know what object to call
    umask: mode_t
}

struct rust_fuse_data {
    ops: ~FuseOperations
}

extern {
    fn fuse_main_real(argc:c_int, argv:**c_char,
                      op:*c_fuse_operations, op_size: size_t,
                      user_data: *c_void) -> c_int;

    fn fuse_get_context() -> *c_fuse_context;

    // Workaround for the fact that we can't call into c via a function ptr right
    // from rust
    fn call_filler_function(filler: cfuncptr, buf: *c_void, name: *c_char, stbuf: *stat,
                           off: off_t) -> c_int;
}

// Used for return values from FS operations
pub type errno = c_int;

pub type fuse_fill_dir_func<'self> = &'self fn (&str, Option<stat>, off_t) -> c_int;

pub type filehandle = u64;

pub struct dir_entry {
    name: ~str,
    stat: Option<stat>,
    off: off_t
}

#[deriving(Clone, Eq, ToStr)]
pub enum ErrorOrResult<E, T> {
    Error(E),
    Result(T)
}

pub trait FuseOperations {
    fn getattr(&self, path:&str) -> ErrorOrResult<errno, stat>;
    fn readdir(&self, path:&str, filler: fuse_fill_dir_func,
               offset: off_t, info: &fuse_file_info) -> ErrorOrResult<errno, ()>;
    fn open(&self, path:&str, info: &fuse_file_info) -> ErrorOrResult<errno, filehandle>;
    fn read(&self, path:&str, buf:&mut [u8], size: size_t, offset: off_t,
            info: &fuse_file_info) -> ErrorOrResult<errno, c_int>;
}

unsafe fn get_context_ops() -> &~FuseOperations {
    &((*(*fuse_get_context()).private_data).ops)
}

extern fn c_getattr(path: *c_char, stbuf: *mut stat) -> errno {
    unsafe {
        let ops = get_context_ops();
        ptr::zero_memory(stbuf, 1);
        match ops.getattr(str::raw::from_c_str(path)) {
            Error(e) => -e,
            Result(st) => { ptr::copy_memory(stbuf, &st, 1); 0 }
        }
    }
}

unsafe fn option_to_ptr<T>(opt: Option<T>) -> *T {
    match opt {
        Some(ref t) => ptr::to_unsafe_ptr(t),
        None => ptr::null()
    }
}

extern fn c_readdir(path: *c_char, buf: *c_void, filler: cfuncptr,
                    offset: off_t, fi: *fuse_file_info) -> c_int {
    unsafe {
        let ops = get_context_ops();
        let fill_func: fuse_fill_dir_func = |name, st, ofs| -> c_int {
            do name.as_c_str |c_name| {
                call_filler_function(filler, buf, c_name, option_to_ptr(st), ofs)
            }
        };
        match ops.readdir(str::raw::from_c_str(path), fill_func, offset, &*fi) {
            Error(e) => -e,
            Result(_) => 0
        }
    }
}

extern fn c_open(path: *c_char, info: *mut fuse_file_info) -> c_int {
    unsafe {
        let ops = get_context_ops();
        match ops.open(str::raw::from_c_str(path), &*info) {
            Error(e) => -e,
            Result(fh) => { (*info).fh = fh; 0 }
        }
    }
}

extern fn c_read(path: *c_char, buf: *mut u8, size: size_t, offset: off_t,
                 fi: *fuse_file_info) -> c_int {
    unsafe {
        let ops = get_context_ops();
        do vec::raw::mut_buf_as_slice(buf, size as uint) |slice| {
            match ops.read(str::raw::from_c_str(path), slice, size, offset, &*fi) {
                Error(e) => -e,
                Result(sz) => sz
            }
        }
    }
}

pub fn fuse_main<T: FuseOperations>(args: ~[~str], ops: ~T) -> c_int {
    let cfo = c_fuse_operations {
        getattr: c_getattr,
        readdir: c_readdir,
        open: c_open,
        read: c_read,

        readlink: ptr::null(),
        getdir: ptr::null(),
        mknod: ptr::null(),
        mkdir: ptr::null(),
        unlink: ptr::null(),
        rmdir: ptr::null(),
        symlink: ptr::null(),
        rename: ptr::null(),
        link: ptr::null(),
        chmod: ptr::null(),
        chown: ptr::null(),
        truncate: ptr::null(),
        utime: ptr::null(),
        write: ptr::null(),
        statfs: ptr::null(),
        flush: ptr::null(),
        release: ptr::null(),
        fsync: ptr::null(),
        setxattr: ptr::null(),
        getxattr: ptr::null(),
        listxattr: ptr::null(),
        removexattr: ptr::null(),
        opendir: ptr::null(),
        releasedir: ptr::null(),
        fsyncdir: ptr::null(),
        init: ptr::null(),
        destroy: ptr::null(),
        access: ptr::null(),
        create: ptr::null(),
        ftruncate: ptr::null(),
        fgetattr: ptr::null(),
        lock: ptr::null(),
        utimens: ptr::null(),
        bmap: ptr::null(),

        flag_nullpath_ok: 0,
        flag_nopath: 0,
        flag_utime_omit_ok: 0,
        flag_reserved: 29,

        ioctl: ptr::null(),
        poll: ptr::null(),
        write_buf: ptr::null(),
        read_buf: ptr::null(),
        flock: ptr::null()
    };
    unsafe {
        let arg_c_strs = vec::raw::to_ptr(args.map(|s| vec::raw::to_ptr(s.as_bytes_with_null())));
        fuse_main_real(args.len() as c_int, std::cast::transmute(arg_c_strs),
                       &cfo, size_of::<c_fuse_operations>() as size_t,
                       std::cast::transmute(&ops))
    }
}
<|endoftext|>