<commit_before>// Copyright 2013-2017, 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 <http://opensource.org/licenses/MIT>

// TODO: support marshaller.

use std::mem;
use std::ptr;
use std::slice;

use libc::{c_uint, c_void};

use ffi as glib_ffi;
use gobject_ffi;
use translate::{ToGlibPtr, ToGlibPtrMut, FromGlibPtrFull, Uninitialized, Stash, mut_override, from_glib_none};
use types::Type;
use Value;
use ToValue;

glib_wrapper! {
    pub struct Closure(Shared<gobject_ffi::GClosure>);

    match fn {
        ref => |ptr| {
            gobject_ffi::g_closure_ref(ptr);
            gobject_ffi::g_closure_sink(ptr);
        },
        unref => |ptr| gobject_ffi::g_closure_unref(ptr),
        get_type => || gobject_ffi::g_closure_get_type(),
    }
}

impl Closure {
    pub fn new<F: Fn(&[Value]) -> Option<Value> + Send + Sync + 'static>(callback: F) -> Self {
        unsafe extern "C" fn marshal<F>(_closure: *mut gobject_ffi::GClosure, return_value: *mut gobject_ffi::GValue,
            n_param_values: c_uint, param_values: *mut gobject_ffi::GValue, _invocation_hint: *mut c_void,
            marshal_data: *mut c_void)
            where F: Fn(&[Value]) -> Option<Value> + Send + Sync + 'static
        {
            let values = slice::from_raw_parts(param_values as *const _, n_param_values as usize);
            let callback: Box<F> = Box::from_raw(marshal_data as *mut _);
            let result = callback(values);
            if !return_value.is_null() {
                match result {
                    Some(result) => *return_value = result.into_raw(),
                    None => {
                        let result = Value::uninitialized();
                        *return_value = result.into_raw();
                    },
                }
            }
            mem::forget(callback);
        }

        unsafe extern "C" fn finalize<F>(notify_data: *mut c_void, _closure: *mut gobject_ffi::GClosure)
            where F: Fn(&[Value]) -> Option<Value> + Send + Sync + 'static
        {
            let _callback: Box<F> = Box::from_raw(notify_data as *mut _);
            // callback is dropped here.
        }

        unsafe {
            let size = 4 + 4 + 3 * mem::size_of::<*mut c_void>() as u32;
            let closure = gobject_ffi::g_closure_new_simple(size, ptr::null_mut());
            assert_ne!(closure, ptr::null_mut());
            let callback = Box::new(callback);
            let ptr: *mut F = Box::into_raw(callback);
            let ptr: *mut c_void = ptr as *mut _;
            gobject_ffi::g_closure_set_meta_marshal(closure, ptr, Some(marshal::<F>));
            gobject_ffi::g_closure_add_finalize_notifier(closure, ptr, Some(finalize::<F>));
            from_glib_none(closure)
        }
    }

    pub fn invoke(&self, values: &[&ToValue]) -> Option<Value> {
        let mut result = unsafe { Value::uninitialized() };

        let v_args: Vec<Value>;
        let mut s_args: [Value; 10] = unsafe { mem::zeroed() };
        let values = if values.len() <= 10 {
            for (i, arg) in values.iter().enumerate() {
                s_args[i] = arg.to_value();
            }
            &s_args[0..values.len()]
        } else {
            v_args = values.iter()
                .map(|v| v.to_value())
                .collect();
            v_args.as_slice()
        };

        unsafe {
            gobject_ffi::g_closure_invoke(self.to_glib_none().0 as *mut _, result.to_glib_none_mut().0,
                values.len() as u32, mut_override(values.as_ptr()) as *mut gobject_ffi::GValue, ptr::null_mut());
        }
        if result.type_() == Type::Invalid {
            None
        } else {
            Some(result)
        }
    }
}

#[cfg(test)]
mod tests {
    use std::sync::Arc;
    use std::sync::atomic::{AtomicUsize, Ordering};

    use super::Closure;
    use ToValue;
    use Value;

    fn closure_fn(values: &[Value]) -> Option<Value> {
        assert_eq!(values.len(), 2);
        let string: Option<String> = values[0].get();
        assert_eq!(string, Some("test".to_string()));
        let int: Option<i32> = values[1].get();
        assert_eq!(int, Some(42));
        Some(24.to_value())
    }

    #[test]
    fn test_closure() {
        let call_count = Arc::new(AtomicUsize::new(0));

        let count = call_count.clone();
        let closure = Closure::new(move |values| {
            count.fetch_add(1, Ordering::Relaxed);
            assert_eq!(values.len(), 2);
            let string: Option<String> = values[0].get();
            assert_eq!(string, Some("test".to_string()));
            let int: Option<i32> = values[1].get();
            assert_eq!(int, Some(42));
            None
        });
        let result = closure.invoke(&[&"test".to_string(), &42]);
        assert!(result.is_none());
        assert_eq!(call_count.load(Ordering::Relaxed), 1);

        let result = closure.invoke(&[&"test".to_string(), &42]);
        assert!(result.is_none());
        assert_eq!(call_count.load(Ordering::Relaxed), 2);

        let closure = Closure::new(closure_fn);
        let result = closure.invoke(&[&"test".to_string(), &42]);
        let int: Option<i32> = result.and_then(|result| result.get());
        assert_eq!(int, Some(24));
    }
}
<commit_msg>Derive PartialEq, Eq, Debug and Hash for Closure<commit_after>// Copyright 2013-2017, 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 <http://opensource.org/licenses/MIT>

// TODO: support marshaller.

use std::mem;
use std::ptr;
use std::slice;

use libc::{c_uint, c_void};

use ffi as glib_ffi;
use gobject_ffi;
use translate::{ToGlibPtr, ToGlibPtrMut, FromGlibPtrFull, Uninitialized, Stash, mut_override, from_glib_none};
use types::Type;
use Value;
use ToValue;

glib_wrapper! {
    #[derive(PartialEq, Eq, Debug, Hash)]
    pub struct Closure(Shared<gobject_ffi::GClosure>);

    match fn {
        ref => |ptr| {
            gobject_ffi::g_closure_ref(ptr);
            gobject_ffi::g_closure_sink(ptr);
        },
        unref => |ptr| gobject_ffi::g_closure_unref(ptr),
        get_type => || gobject_ffi::g_closure_get_type(),
    }
}

impl Closure {
    pub fn new<F: Fn(&[Value]) -> Option<Value> + Send + Sync + 'static>(callback: F) -> Self {
        unsafe extern "C" fn marshal<F>(_closure: *mut gobject_ffi::GClosure, return_value: *mut gobject_ffi::GValue,
            n_param_values: c_uint, param_values: *mut gobject_ffi::GValue, _invocation_hint: *mut c_void,
            marshal_data: *mut c_void)
            where F: Fn(&[Value]) -> Option<Value> + Send + Sync + 'static
        {
            let values = slice::from_raw_parts(param_values as *const _, n_param_values as usize);
            let callback: Box<F> = Box::from_raw(marshal_data as *mut _);
            let result = callback(values);
            if !return_value.is_null() {
                match result {
                    Some(result) => *return_value = result.into_raw(),
                    None => {
                        let result = Value::uninitialized();
                        *return_value = result.into_raw();
                    },
                }
            }
            mem::forget(callback);
        }

        unsafe extern "C" fn finalize<F>(notify_data: *mut c_void, _closure: *mut gobject_ffi::GClosure)
            where F: Fn(&[Value]) -> Option<Value> + Send + Sync + 'static
        {
            let _callback: Box<F> = Box::from_raw(notify_data as *mut _);
            // callback is dropped here.
        }

        unsafe {
            let size = 4 + 4 + 3 * mem::size_of::<*mut c_void>() as u32;
            let closure = gobject_ffi::g_closure_new_simple(size, ptr::null_mut());
            assert_ne!(closure, ptr::null_mut());
            let callback = Box::new(callback);
            let ptr: *mut F = Box::into_raw(callback);
            let ptr: *mut c_void = ptr as *mut _;
            gobject_ffi::g_closure_set_meta_marshal(closure, ptr, Some(marshal::<F>));
            gobject_ffi::g_closure_add_finalize_notifier(closure, ptr, Some(finalize::<F>));
            from_glib_none(closure)
        }
    }

    pub fn invoke(&self, values: &[&ToValue]) -> Option<Value> {
        let mut result = unsafe { Value::uninitialized() };

        let v_args: Vec<Value>;
        let mut s_args: [Value; 10] = unsafe { mem::zeroed() };
        let values = if values.len() <= 10 {
            for (i, arg) in values.iter().enumerate() {
                s_args[i] = arg.to_value();
            }
            &s_args[0..values.len()]
        } else {
            v_args = values.iter()
                .map(|v| v.to_value())
                .collect();
            v_args.as_slice()
        };

        unsafe {
            gobject_ffi::g_closure_invoke(self.to_glib_none().0 as *mut _, result.to_glib_none_mut().0,
                values.len() as u32, mut_override(values.as_ptr()) as *mut gobject_ffi::GValue, ptr::null_mut());
        }
        if result.type_() == Type::Invalid {
            None
        } else {
            Some(result)
        }
    }
}

#[cfg(test)]
mod tests {
    use std::sync::Arc;
    use std::sync::atomic::{AtomicUsize, Ordering};

    use super::Closure;
    use ToValue;
    use Value;

    fn closure_fn(values: &[Value]) -> Option<Value> {
        assert_eq!(values.len(), 2);
        let string: Option<String> = values[0].get();
        assert_eq!(string, Some("test".to_string()));
        let int: Option<i32> = values[1].get();
        assert_eq!(int, Some(42));
        Some(24.to_value())
    }

    #[test]
    fn test_closure() {
        let call_count = Arc::new(AtomicUsize::new(0));

        let count = call_count.clone();
        let closure = Closure::new(move |values| {
            count.fetch_add(1, Ordering::Relaxed);
            assert_eq!(values.len(), 2);
            let string: Option<String> = values[0].get();
            assert_eq!(string, Some("test".to_string()));
            let int: Option<i32> = values[1].get();
            assert_eq!(int, Some(42));
            None
        });
        let result = closure.invoke(&[&"test".to_string(), &42]);
        assert!(result.is_none());
        assert_eq!(call_count.load(Ordering::Relaxed), 1);

        let result = closure.invoke(&[&"test".to_string(), &42]);
        assert!(result.is_none());
        assert_eq!(call_count.load(Ordering::Relaxed), 2);

        let closure = Closure::new(closure_fn);
        let result = closure.invoke(&[&"test".to_string(), &42]);
        let int: Option<i32> = result.and_then(|result| result.get());
        assert_eq!(int, Some(24));
    }
}
<|endoftext|>


<commit_before>use crate::device_code_responses::*;
use async_timer::timer::new_timer;
use azure_sdk_core::errors::AzureError;
use futures::stream::unfold;
use log::debug;
pub use oauth2::{ClientId, ClientSecret};
use std::convert::TryInto;
use std::sync::Arc;
use std::time::Duration;
use url::form_urlencoded;

#[derive(Debug, Clone, Deserialize)]
pub struct DeviceCodePhaseOneResponse<'a> {
    device_code: String,
    user_code: String,
    verification_uri: String,
    expires_in: u64,
    interval: u64,
    message: String,
    #[serde(skip)]
    client: Arc<reqwest::Client>,
    #[serde(skip)]
    tenant_id: &'a str,
    // we store the ClientId as string instead of
    // the original type because it does not
    // implement Default and it's in another
    // create
    #[serde(skip)]
    client_id: String,
}

pub async fn begin_authorize_device_code_flow<'a, 'b>(
    client: Arc<reqwest::Client>,
    tenant_id: &'a str,
    client_id: &'a ClientId,
    scopes: &'b [&'b str],
) -> Result<DeviceCodePhaseOneResponse<'a>, AzureError> {
    let mut encoded = form_urlencoded::Serializer::new(String::new());
    let encoded = encoded.append_pair("client_id", client_id.as_str());
    let encoded = encoded.append_pair("scope", &scopes.join(" "));
    let encoded = encoded.finish();

    debug!("encoded ==> {}", encoded);

    let url = url::Url::parse(&format!(
        "https://login.microsoftonline.com/{}/oauth2/v2.0/devicecode",
        tenant_id
    ))?;

    client
        .post(url)
        .header("ContentType", "application/x-www-form-urlencoded")
        .body(encoded)
        .send()
        .await
        .map_err(|e| AzureError::GenericErrorWithText(e.to_string()))?
        .text()
        .await
        .map_err(|e| AzureError::GenericErrorWithText(e.to_string()))
        .and_then(|s| {
            serde_json::from_str::<DeviceCodePhaseOneResponse>(&s)
                // we need to capture some variables that will be useful in
                // the second phase (the client, the tenant_id and the client_id)
                .map(|device_code_reponse| DeviceCodePhaseOneResponse {
                    device_code: device_code_reponse.device_code,
                    user_code: device_code_reponse.user_code,
                    verification_uri: device_code_reponse.verification_uri,
                    expires_in: device_code_reponse.expires_in,
                    interval: device_code_reponse.interval,
                    message: device_code_reponse.message,
                    client: client.clone(),
                    tenant_id,
                    client_id: client_id.as_str().to_string(),
                })
                .map_err(|e| {
                    serde_json::from_str::<crate::errors::ErrorResponse>(&s)
                        .map(|er| AzureError::GenericErrorWithText(er.to_string()))
                        .unwrap_or_else(|_| {
                            AzureError::GenericErrorWithText(format!(
                                "Failed to parse Azure response: {}",
                                e.to_string()
                            ))
                        })
                })
        })
}

impl<'a> DeviceCodePhaseOneResponse<'a> {
    pub fn message(&self) -> &str {
        &self.message
    }

    pub fn stream(
        &self,
    ) -> impl futures::Stream<Item = Result<DeviceCodeResponse, DeviceCodeError>> + '_ {
        #[derive(Debug, Clone, PartialEq)]
        enum States {
            Continue,
            Finish,
        }

        unfold(States::Continue, async move |state: States| match state {
            States::Continue => {
                let uri = format!(
                    "https://login.microsoftonline.com/{}/oauth2/v2.0/token",
                    self.tenant_id,
                );

                // throttle down
                new_timer(Duration::from_secs(self.interval)).await;
                debug!("getting {}", &uri);

                let mut encoded = form_urlencoded::Serializer::new(String::new());
                let encoded = encoded
                    .append_pair("grant_type", "urn:ietf:params:oauth:grant-type:device_code");
                let encoded = encoded.append_pair("client_id", self.client_id.as_str());
                let encoded = encoded.append_pair("device_code", &self.device_code);
                let encoded = encoded.finish();

                let result = match self
                    .client
                    .post(&uri)
                    .header("ContentType", "application/x-www-form-urlencoded")
                    .body(encoded)
                    .send()
                    .await
                    .map_err(DeviceCodeError::ReqwestError)
                {
                    Ok(result) => result,
                    Err(error) => return Some((Err(error), States::Finish)),
                };
                debug!("result ==> {:?}", result);

                let result = match result.text().await.map_err(DeviceCodeError::ReqwestError) {
                    Ok(result) => result,
                    Err(error) => return Some((Err(error), States::Finish)),
                };
                debug!("result (as text) ==> {}", result);

                // here either we get an error response from Azure
                // or we get a success. A success can be either "Pending" or
                // "Completed". We finish the loop only on "Completed" (ie Success)
                match result.try_into() {
                    Ok(device_code_response) => {
                        let next_state = match &device_code_response {
                            DeviceCodeResponse::AuthorizationSucceded(_) => States::Finish,
                            DeviceCodeResponse::AuthorizationPending(_) => States::Continue,
                        };

                        Some((Ok(device_code_response), next_state))
                    }
                    Err(error) => Some((Err(error), States::Finish)),
                }
            }
            States::Finish => None,
        })
    }
}
<commit_msg>final fixes<commit_after>use crate::device_code_responses::*;
use async_timer::timer::new_timer;
use azure_sdk_core::errors::AzureError;
use futures::stream::unfold;
use log::debug;
pub use oauth2::{ClientId, ClientSecret};
use std::convert::TryInto;
use std::sync::Arc;
use std::time::Duration;
use url::form_urlencoded;

#[derive(Debug, Clone, Deserialize)]
pub struct DeviceCodePhaseOneResponse<'a> {
    device_code: String,
    user_code: String,
    verification_uri: String,
    expires_in: u64,
    interval: u64,
    message: String,
    // the skipped fields below do not come
    // from the Azure answer. They will be added
    // manually after deserialization
    #[serde(skip)]
    client: Arc<reqwest::Client>,
    #[serde(skip)]
    tenant_id: &'a str,
    // we store the ClientId as string instead of
    // the original type because it does not
    // implement Default and it's in another
    // create
    #[serde(skip)]
    client_id: String,
}

pub async fn begin_authorize_device_code_flow<'a, 'b>(
    client: Arc<reqwest::Client>,
    tenant_id: &'a str,
    client_id: &'a ClientId,
    scopes: &'b [&'b str],
) -> Result<DeviceCodePhaseOneResponse<'a>, AzureError> {
    let mut encoded = form_urlencoded::Serializer::new(String::new());
    let encoded = encoded.append_pair("client_id", client_id.as_str());
    let encoded = encoded.append_pair("scope", &scopes.join(" "));
    let encoded = encoded.finish();

    debug!("encoded ==> {}", encoded);

    let url = url::Url::parse(&format!(
        "https://login.microsoftonline.com/{}/oauth2/v2.0/devicecode",
        tenant_id
    ))?;

    client
        .post(url)
        .header("ContentType", "application/x-www-form-urlencoded")
        .body(encoded)
        .send()
        .await
        .map_err(|e| AzureError::GenericErrorWithText(e.to_string()))?
        .text()
        .await
        .map_err(|e| AzureError::GenericErrorWithText(e.to_string()))
        .and_then(|s| {
            serde_json::from_str::<DeviceCodePhaseOneResponse>(&s)
                // we need to capture some variables that will be useful in
                // the second phase (the client, the tenant_id and the client_id)
                .map(|device_code_reponse| DeviceCodePhaseOneResponse {
                    device_code: device_code_reponse.device_code,
                    user_code: device_code_reponse.user_code,
                    verification_uri: device_code_reponse.verification_uri,
                    expires_in: device_code_reponse.expires_in,
                    interval: device_code_reponse.interval,
                    message: device_code_reponse.message,
                    client: client.clone(),
                    tenant_id,
                    client_id: client_id.as_str().to_string(),
                })
                .map_err(|e| {
                    serde_json::from_str::<crate::errors::ErrorResponse>(&s)
                        .map(|er| AzureError::GenericErrorWithText(er.to_string()))
                        .unwrap_or_else(|_| {
                            AzureError::GenericErrorWithText(format!(
                                "Failed to parse Azure response: {}",
                                e.to_string()
                            ))
                        })
                })
        })
}

impl<'a> DeviceCodePhaseOneResponse<'a> {
    pub fn message(&self) -> &str {
        &self.message
    }

    pub fn stream(
        &self,
    ) -> impl futures::Stream<Item = Result<DeviceCodeResponse, DeviceCodeError>> + '_ {
        #[derive(Debug, Clone, PartialEq)]
        enum NextState {
            Continue,
            Finish,
        }

        unfold(
            NextState::Continue,
            async move |state: NextState| match state {
                NextState::Continue => {
                    let uri = format!(
                        "https://login.microsoftonline.com/{}/oauth2/v2.0/token",
                        self.tenant_id,
                    );

                    // throttle down as specified by Azure. This could be
                    // smarter: we could calculate the elapsed time since the
                    // last poll and wait only the delta. For now we do not
                    // need such precision.
                    new_timer(Duration::from_secs(self.interval)).await;
                    debug!("posting to {}", &uri);

                    let mut encoded = form_urlencoded::Serializer::new(String::new());
                    let encoded = encoded
                        .append_pair("grant_type", "urn:ietf:params:oauth:grant-type:device_code");
                    let encoded = encoded.append_pair("client_id", self.client_id.as_str());
                    let encoded = encoded.append_pair("device_code", &self.device_code);
                    let encoded = encoded.finish();

                    let result = match self
                        .client
                        .post(&uri)
                        .header("ContentType", "application/x-www-form-urlencoded")
                        .body(encoded)
                        .send()
                        .await
                        .map_err(DeviceCodeError::ReqwestError)
                    {
                        Ok(result) => result,
                        Err(error) => return Some((Err(error), NextState::Finish)),
                    };
                    debug!("result (raw) ==> {:?}", result);

                    let result = match result.text().await.map_err(DeviceCodeError::ReqwestError) {
                        Ok(result) => result,
                        Err(error) => return Some((Err(error), NextState::Finish)),
                    };
                    debug!("result (as text) ==> {}", result);

                    // here either we get an error response from Azure
                    // or we get a success. A success can be either "Pending" or
                    // "Completed". We finish the loop only on "Completed" (ie Success)
                    match result.try_into() {
                        Ok(device_code_response) => {
                            let next_state = match &device_code_response {
                                DeviceCodeResponse::AuthorizationSucceded(_) => NextState::Finish,
                                DeviceCodeResponse::AuthorizationPending(_) => NextState::Continue,
                            };

                            Some((Ok(device_code_response), next_state))
                        }
                        Err(error) => Some((Err(error), NextState::Finish)),
                    }
                }
                NextState::Finish => None,
            },
        )
    }
}
<|endoftext|>


<commit_before>use std::collections::btree_map::{BTreeMap, Range};
use std::cmp::Ordering::*;
use std::iter::Peekable;

use super::Result;

use self::NextIterValue::*;

pub type Patch = BTreeMap<Vec<u8>, Change>;
pub type Iter<'a> = Box<Iterator<'a> + 'a>;

#[derive(Debug, Clone)]
pub enum Change {
    Put(Vec<u8>),
    Delete,
}

// FIXME: make &mut Fork "unwind safe"
pub struct Fork {
    snapshot: Box<Snapshot>,
    changes: Patch,
    changelog: Vec<(Vec<u8>, Option<Change>)>,
    logged: bool,
}

pub struct ForkIter<'a> {
    snapshot: Iter<'a>,
    changes: Peekable<Range<'a, Vec<u8>, Change>>,
}

#[derive(Debug, PartialEq, Eq)]
enum NextIterValue {
    Stored,
    Replaced,
    Inserted,
    Deleted,
    MissDeleted,
    Finished,
}

pub trait Database: Send + Sync + 'static {
    fn clone(&self) -> Box<Database>;
    fn snapshot(&self) -> Box<Snapshot>;
    fn fork(&self) -> Fork {
        Fork {
            snapshot: self.snapshot(),
            changes: Patch::new(),
            changelog: Vec::new(),
            logged: false,
        }
    }
    fn merge(&mut self, patch: Patch) -> Result<()>;
}

pub trait Snapshot: 'static {
    fn get(&self, key: &[u8]) -> Option<Vec<u8>>;
    fn contains(&self, key: &[u8]) -> bool {
        self.get(key).is_some()
    }
    fn iter<'a>(&'a self, from: &[u8]) -> Iter<'a>;
}

pub trait Iterator<'a> {
    fn next(&mut self) -> Option<(&[u8], &[u8])>;
    fn peek(&mut self) -> Option<(&[u8], &[u8])>;
}

impl Snapshot for Fork {
    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
        match self.changes.get(key) {
            Some(change) => {
                match *change {
                    Change::Put(ref v) => Some(v.clone()),
                    Change::Delete => None,
                }
            }
            None => self.snapshot.get(key),
        }
    }

    fn contains(&self, key: &[u8]) -> bool {
        match self.changes.get(key) {
            Some(change) => {
                match *change {
                    Change::Put(..) => true,
                    Change::Delete => false,
                }
            }
            None => self.snapshot.get(key).is_some(),
        }
    }

    fn iter<'a>(&'a self, from: &[u8]) -> Iter<'a> {
        use std::collections::Bound::*;
        let range = (Included(from), Unbounded);
        Box::new(ForkIter {
                     snapshot: self.snapshot.iter(from),
                     changes: self.changes.range::<[u8], _>(range).peekable(),
                 })
    }
}

impl Fork {
    pub fn checkpoint(&mut self) {
        if self.logged {
            panic!("call checkpoint before rollback or commit");
        }
        self.logged = true;
    }

    pub fn commit(&mut self) {
        if !self.logged {
            panic!("call commit before checkpoint");
        }
        self.changelog.clear();
        self.logged = false;
    }

    pub fn rollback(&mut self) {
        if !self.logged {
            panic!("call rollback before checkpoint");
        }
        for (k, c) in self.changelog.drain(..).rev() {
            match c {
                Some(change) => self.changes.insert(k, change),
                None => self.changes.remove(&k),
            };
        }
        self.logged = false;
    }

    pub fn put(&mut self, key: Vec<u8>, value: Vec<u8>) {
        if self.logged {
            self.changelog
                .push((key.clone(), self.changes.insert(key, Change::Put(value))));
        } else {
            self.changes.insert(key, Change::Put(value));
        }
    }

    pub fn remove(&mut self, key: Vec<u8>) {
        if self.logged {
            self.changelog
                .push((key.clone(), self.changes.insert(key, Change::Delete)));
        } else {
            self.changes.insert(key, Change::Delete);
        }
    }

    pub fn remove_by_prefix(&mut self, prefix: &[u8]) {
        let mut iter = self.snapshot.iter(prefix);
        while let Some((k, ..)) = iter.next() {
            if !k.starts_with(prefix) {
                return;
            }
            let change = self.changes.insert(k.to_vec(), Change::Delete);
            if self.logged {
                self.changelog.push((k.to_vec(), change));
            }
        }
    }

    pub fn into_patch(self) -> Patch {
        self.changes
    }

    pub fn merge(&mut self, patch: Patch) {
        if self.logged {
            panic!("call merge before commit or rollback");
        }
        self.changes.extend(patch)
    }
}

impl AsRef<Snapshot> for Fork {
    fn as_ref(&self) -> &Snapshot {
        &*self
    }
}

impl ::std::fmt::Debug for Fork {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "Fork(..)")
    }
}

impl<'a> ForkIter<'a> {
    fn step(&mut self) -> NextIterValue {
        match self.changes.peek() {
            Some(&(k, change)) => {
                match self.snapshot.peek() {
                    Some((key, ..)) => {
                        match *change {
                            Change::Put(..) => {
                                match k[..].cmp(key) {
                                    Equal => Replaced,
                                    Less => Inserted,
                                    Greater => Stored,
                                }
                            }
                            Change::Delete => {
                                match k[..].cmp(key) {
                                    Equal => Deleted,
                                    Less => MissDeleted,
                                    Greater => Stored,
                                }
                            }
                        }
                    }
                    None => {
                        match *change {
                            Change::Put(..) => Inserted,
                            Change::Delete => MissDeleted,
                        }
                    }
                }
            }
            None => {
                match self.snapshot.peek() {
                    Some(..) => Stored,
                    None => Finished,
                }
            }
        }
    }
}

impl<'a> Iterator<'a> for ForkIter<'a> {
    fn next(&mut self) -> Option<(&[u8], &[u8])> {
        loop {
            match self.step() {
                Stored => return self.snapshot.next(),
                Replaced => {
                    self.snapshot.next();
                    return self.changes
                               .next()
                               .map(|(key, change)| {
                                        (key.as_slice(),
                                         match *change {
                                             Change::Put(ref value) => value.as_slice(),
                                             Change::Delete => unreachable!(),
                                         })
                                    });
                }
                Inserted => {
                    return self.changes
                               .next()
                               .map(|(key, change)| {
                                        (key.as_slice(),
                                         match *change {
                                             Change::Put(ref value) => value.as_slice(),
                                             Change::Delete => unreachable!(),
                                         })
                                    })
                }
                Deleted => {
                    self.changes.next();
                    self.snapshot.next();
                }
                MissDeleted => {
                    self.changes.next();
                }
                Finished => return None,
            }
        }
    }

    fn peek(&mut self) -> Option<(&[u8], &[u8])> {
        loop {
            match self.step() {
                Stored | Replaced => return self.snapshot.peek(),
                Inserted => {
                    return self.changes
                               .peek()
                               .map(|&(key, change)| {
                                        (key.as_slice(),
                                         match *change {
                                             Change::Put(ref value) => value.as_slice(),
                                             Change::Delete => unreachable!(),
                                         })
                                    })
                }
                Deleted => {
                    self.changes.next();
                    self.snapshot.next();
                }
                MissDeleted => {
                    self.changes.next();
                }
                Finished => return None,
            }
        }
    }
}
<commit_msg>Add AsRef<Snapshot> for Snapshot implementation<commit_after>use std::collections::btree_map::{BTreeMap, Range};
use std::cmp::Ordering::*;
use std::iter::Peekable;

use super::Result;

use self::NextIterValue::*;

pub type Patch = BTreeMap<Vec<u8>, Change>;
pub type Iter<'a> = Box<Iterator<'a> + 'a>;

#[derive(Debug, Clone)]
pub enum Change {
    Put(Vec<u8>),
    Delete,
}

// FIXME: make &mut Fork "unwind safe"
pub struct Fork {
    snapshot: Box<Snapshot>,
    changes: Patch,
    changelog: Vec<(Vec<u8>, Option<Change>)>,
    logged: bool,
}

pub struct ForkIter<'a> {
    snapshot: Iter<'a>,
    changes: Peekable<Range<'a, Vec<u8>, Change>>,
}

#[derive(Debug, PartialEq, Eq)]
enum NextIterValue {
    Stored,
    Replaced,
    Inserted,
    Deleted,
    MissDeleted,
    Finished,
}

pub trait Database: Send + Sync + 'static {
    fn clone(&self) -> Box<Database>;
    fn snapshot(&self) -> Box<Snapshot>;
    fn fork(&self) -> Fork {
        Fork {
            snapshot: self.snapshot(),
            changes: Patch::new(),
            changelog: Vec::new(),
            logged: false,
        }
    }
    fn merge(&mut self, patch: Patch) -> Result<()>;
}

pub trait Snapshot: 'static {
    fn get(&self, key: &[u8]) -> Option<Vec<u8>>;
    fn contains(&self, key: &[u8]) -> bool {
        self.get(key).is_some()
    }
    fn iter<'a>(&'a self, from: &[u8]) -> Iter<'a>;
}

pub trait Iterator<'a> {
    fn next(&mut self) -> Option<(&[u8], &[u8])>;
    fn peek(&mut self) -> Option<(&[u8], &[u8])>;
}

impl Snapshot for Fork {
    fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
        match self.changes.get(key) {
            Some(change) => {
                match *change {
                    Change::Put(ref v) => Some(v.clone()),
                    Change::Delete => None,
                }
            }
            None => self.snapshot.get(key),
        }
    }

    fn contains(&self, key: &[u8]) -> bool {
        match self.changes.get(key) {
            Some(change) => {
                match *change {
                    Change::Put(..) => true,
                    Change::Delete => false,
                }
            }
            None => self.snapshot.get(key).is_some(),
        }
    }

    fn iter<'a>(&'a self, from: &[u8]) -> Iter<'a> {
        use std::collections::Bound::*;
        let range = (Included(from), Unbounded);
        Box::new(ForkIter {
                     snapshot: self.snapshot.iter(from),
                     changes: self.changes.range::<[u8], _>(range).peekable(),
                 })
    }
}

impl Fork {
    pub fn checkpoint(&mut self) {
        if self.logged {
            panic!("call checkpoint before rollback or commit");
        }
        self.logged = true;
    }

    pub fn commit(&mut self) {
        if !self.logged {
            panic!("call commit before checkpoint");
        }
        self.changelog.clear();
        self.logged = false;
    }

    pub fn rollback(&mut self) {
        if !self.logged {
            panic!("call rollback before checkpoint");
        }
        for (k, c) in self.changelog.drain(..).rev() {
            match c {
                Some(change) => self.changes.insert(k, change),
                None => self.changes.remove(&k),
            };
        }
        self.logged = false;
    }

    pub fn put(&mut self, key: Vec<u8>, value: Vec<u8>) {
        if self.logged {
            self.changelog
                .push((key.clone(), self.changes.insert(key, Change::Put(value))));
        } else {
            self.changes.insert(key, Change::Put(value));
        }
    }

    pub fn remove(&mut self, key: Vec<u8>) {
        if self.logged {
            self.changelog
                .push((key.clone(), self.changes.insert(key, Change::Delete)));
        } else {
            self.changes.insert(key, Change::Delete);
        }
    }

    pub fn remove_by_prefix(&mut self, prefix: &[u8]) {
        let mut iter = self.snapshot.iter(prefix);
        while let Some((k, ..)) = iter.next() {
            if !k.starts_with(prefix) {
                return;
            }
            let change = self.changes.insert(k.to_vec(), Change::Delete);
            if self.logged {
                self.changelog.push((k.to_vec(), change));
            }
        }
    }

    pub fn into_patch(self) -> Patch {
        self.changes
    }

    pub fn merge(&mut self, patch: Patch) {
        if self.logged {
            panic!("call merge before commit or rollback");
        }
        self.changes.extend(patch)
    }
}

impl AsRef<Snapshot> for Snapshot + 'static {
    fn as_ref(&self) -> &Snapshot {
        self
    }
}

impl AsRef<Snapshot> for Fork {
    fn as_ref(&self) -> &Snapshot {
        &*self
    }
}

impl ::std::fmt::Debug for Fork {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "Fork(..)")
    }
}

impl<'a> ForkIter<'a> {
    fn step(&mut self) -> NextIterValue {
        match self.changes.peek() {
            Some(&(k, change)) => {
                match self.snapshot.peek() {
                    Some((key, ..)) => {
                        match *change {
                            Change::Put(..) => {
                                match k[..].cmp(key) {
                                    Equal => Replaced,
                                    Less => Inserted,
                                    Greater => Stored,
                                }
                            }
                            Change::Delete => {
                                match k[..].cmp(key) {
                                    Equal => Deleted,
                                    Less => MissDeleted,
                                    Greater => Stored,
                                }
                            }
                        }
                    }
                    None => {
                        match *change {
                            Change::Put(..) => Inserted,
                            Change::Delete => MissDeleted,
                        }
                    }
                }
            }
            None => {
                match self.snapshot.peek() {
                    Some(..) => Stored,
                    None => Finished,
                }
            }
        }
    }
}

impl<'a> Iterator<'a> for ForkIter<'a> {
    fn next(&mut self) -> Option<(&[u8], &[u8])> {
        loop {
            match self.step() {
                Stored => return self.snapshot.next(),
                Replaced => {
                    self.snapshot.next();
                    return self.changes
                               .next()
                               .map(|(key, change)| {
                                        (key.as_slice(),
                                         match *change {
                                             Change::Put(ref value) => value.as_slice(),
                                             Change::Delete => unreachable!(),
                                         })
                                    });
                }
                Inserted => {
                    return self.changes
                               .next()
                               .map(|(key, change)| {
                                        (key.as_slice(),
                                         match *change {
                                             Change::Put(ref value) => value.as_slice(),
                                             Change::Delete => unreachable!(),
                                         })
                                    })
                }
                Deleted => {
                    self.changes.next();
                    self.snapshot.next();
                }
                MissDeleted => {
                    self.changes.next();
                }
                Finished => return None,
            }
        }
    }

    fn peek(&mut self) -> Option<(&[u8], &[u8])> {
        loop {
            match self.step() {
                Stored | Replaced => return self.snapshot.peek(),
                Inserted => {
                    return self.changes
                               .peek()
                               .map(|&(key, change)| {
                                        (key.as_slice(),
                                         match *change {
                                             Change::Put(ref value) => value.as_slice(),
                                             Change::Delete => unreachable!(),
                                         })
                                    })
                }
                Deleted => {
                    self.changes.next();
                    self.snapshot.next();
                }
                MissDeleted => {
                    self.changes.next();
                }
                Finished => return None,
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Edit a `DataBase`.

use database::{write_database, DataBase};
use error::Result;
use ui::utils;
use ui::utils::{CommandList, CommandParser};

use std::error::Error;

#[derive(Clone, Copy, Debug)]
enum Command {
    AddResidue,
    RemoveResidue,
    AddSubstrate,
    RemoveSubstrate,
    WriteToDisk,
    SetLocation,
    ShowDatabase,
    QuitAndSave,
    QuitWithoutSaving,
}

pub fn user_menu(database: &mut DataBase) -> Result<&'static str> {
    let command_list: CommandList<Command> = vec![
        ("ra", Command::AddResidue, "Add a residue definition"),
        ("rr", Command::RemoveResidue, "Remove a residue definition"),
        ("sa", Command::AddSubstrate, "Add a substrate definition"),
        ("sr", Command::RemoveSubstrate, "Remove a substrate definition"),
        ("w", Command::WriteToDisk, "Write database to disk"),
        ("c", Command::SetLocation, "Change output location of database"),
        ("l", Command::ShowDatabase, "List database content"),
        ("f", Command::QuitAndSave, "Finish editing database"),
        ("a", Command::QuitWithoutSaving, "Abort editing and discard changes"),
    ];
    let commands = CommandParser::from_list(command_list);

    let path_backup = database.path.clone();
    let residues_backup = database.residue_defs.clone();
    let substrates_backup = database.substrate_defs.clone();

    println!("Editing the current database.\n");
    database.describe();
    println!("");

    loop {
        commands.print_menu();
        let input = utils::get_input_string("Selection")?;

        if let Some((cmd, tail)) = commands.get_selection_and_tail(&input) {
            match cmd {
                Command::AddResidue => {
                    match define_residue::user_menu() {
                        Ok(residue) => {
                            println!("Added residue '{}' to database.", residue.code);
                            database.residue_defs.push(residue);
                        },
                        Err(err) => println!("Could not create residue: {}", err.description()),
                    }
                },
                Command::RemoveResidue => {
                    match utils::remove_item(&mut database.residue_defs, &tail) {
                        Ok(i) => println!("Removed residue with index {} from database.", i),
                        Err(err) => println!("Could not remove residue: {}", err.description()),
                    }
                },
                Command::AddSubstrate => {
                    println!("Unimplemented!");
                },
                Command::RemoveSubstrate => {
                    match utils::remove_item(&mut database.substrate_defs, &tail) {
                        Ok(i) => println!("Removed substrate with index {} from database.", i),
                        Err(err) => println!("Could not remove substrate: {}", err.description()),
                    }
                },
                Command::WriteToDisk => {
                    match write_database(&database) {
                        Ok(_) => println!("Wrote database to '{}'.",
                                          database.path.as_ref().unwrap().to_str().unwrap()),
                        Err(err) => println!("Could not write database: {}", err.description()),
                    }
                },
                Command::SetLocation => {
                    match database.set_path(&tail) {
                        Ok(_) => println!("Database path set to '{}'.",
                                          database.get_path_pretty()),
                        Err(err) => println!("Could not change database path: {}",
                                             err.description()),
                    }
                },
                Command::ShowDatabase => {
                    println!("");
                    database.describe();
                },
                Command::QuitAndSave => {
                    return Ok("Finished editing database.");
                },
                Command::QuitWithoutSaving => {
                    database.path = path_backup;
                    database.residue_defs = residues_backup;
                    database.substrate_defs = substrates_backup;

                    return Ok("Discarding changes to database.");
                },
            }
        } else {
            println!("Not a valid selection.");
        }

        println!("");
    }
}

mod define_residue {
    use error::{Result, GrafenCliError, UIErrorKind};
    use ui::utils;
    use ui::utils::{CommandList, CommandParser};

    use grafen::system::{Atom, Coord, ResidueBase};
    use std::error::Error;

    #[derive(Clone, Copy, Debug)]
    enum ResidueCommand {
        SetName,
        AddAtom,
        RemoveAtom,
        SwapAtoms,
        ShowResidue,
        QuitAndSave,
        QuitWithoutSaving,
    }

    pub fn user_menu() -> Result<ResidueBase> {
        let command_list: CommandList<ResidueCommand> = vec![
            ("n", ResidueCommand::SetName, "Set residue name"),
            ("at", ResidueCommand::AddAtom, "Add atom to residue"),
            ("r", ResidueCommand::RemoveAtom, "Remove atom from residue"),
            ("s", ResidueCommand::SwapAtoms, "Swap two atoms in list"),
            ("l", ResidueCommand::ShowResidue, "List current residue data"),
            ("f", ResidueCommand::QuitAndSave, "Finish and add residue to list"),
            ("a", ResidueCommand::QuitWithoutSaving, "Abort and discard changes")
        ];
        let commands = CommandParser::from_list(command_list);

        println!("Creating a new residue.\n");

        let mut name = String::new();
        let mut atoms: Vec<Atom> = Vec::new();

        loop {
            commands.print_menu();
            let input = utils::get_input_string("Selection")?;
            println!("");

            if let Some((cmd, tail)) = commands.get_selection_and_tail(&input) {
                match cmd {
                    ResidueCommand::SetName => {
                        name = tail.to_uppercase().to_string();
                        println!("Set residue name to '{}'", &name);
                    },
                    ResidueCommand::AddAtom => {
                        match parse_string_for_atom(&tail) {
                            Ok(atom) => {
                                println!("Added atom '{}' to residue.", &atom.code);
                                atoms.push(atom);
                            },
                            Err(err) => println!("Could not add atom: {}", err.description()),
                        }

                    },
                    ResidueCommand::RemoveAtom => {
                        match utils::remove_item(&mut atoms, &tail) {
                            Ok(i) => println!("Removed atom with index {} from residue.", i),
                            Err(err) => println!("Could not remove atom: {}", err.description()),
                        }
                    },
                    ResidueCommand::SwapAtoms => {
                        match utils::swap_items(&mut atoms, &tail) {
                            Ok((i, j)) => println!("Swapped atoms at index {} with atom at {}.",
                                                   i, j),
                            Err(err) => println!("Could not swap atoms: {}", err.description()),
                        }
                    },
                    ResidueCommand::ShowResidue => {
                        describe_residue(&name, &atoms);
                    },
                    ResidueCommand::QuitAndSave => {
                        if name.is_empty() {
                            println!("Cannot add residue: No name is set");
                        } else if atoms.is_empty() {
                            println!("Cannot add residue: No atoms are set");
                        } else {
                            return Ok(ResidueBase {
                                code: name,
                                atoms: atoms,
                            });
                        }
                    }
                    ResidueCommand::QuitWithoutSaving => {
                        return Err(GrafenCliError::from(UIErrorKind::Abort));
                    },
                }
            } else {
                println!("Not a valid selection.");
            }

            println!("");
        }
    }

    fn parse_string_for_atom<'a>(input: &'a str) -> Result<Atom> {
        let mut iter = input.splitn(2, ' ');
        let name = iter.next().and_then(|s| {
                if s.is_empty() {
                    None
                } else {
                    Some(s)
                }
            })
            .ok_or(UIErrorKind::BadValue("No name was given".to_string()))?;

        let tail = iter.next().unwrap_or("");

        let coords = utils::parse_string(&tail)?;
        let &x = coords.get(0)
                       .ok_or(UIErrorKind::BadValue("3 positions are required".to_string()))?;
        let &y = coords.get(1)
                       .ok_or(UIErrorKind::BadValue("3 positions are required".to_string()))?;
        let &z = coords.get(2)
                       .ok_or(UIErrorKind::BadValue("3 positions are required".to_string()))?;

        Ok(Atom {
            code: name.to_uppercase().to_string(),
            position: Coord::new(x, y, z),
        })
    }

    fn describe_residue<'a>(name: &'a str, atoms: &[Atom]) {
        println!("Residue name: '{}'", name);
        println!("Atoms:");
        for (i, atom) in atoms.iter().enumerate() {
            let (x, y, z) = atom.position.to_tuple();
            println!("{:4}. {} at ({:.1}, {:.1}, {:.1})", i, atom.code, x, y, z);
        }
    }

    #[cfg(test)]
    mod tests {
        use super::*;

        #[test]
        fn parse_atom_string() {
            let atom = Atom { code: "A1".to_string(), position: Coord::new(1.0, 2.0, 0.0) };
            assert_eq!(atom, parse_string_for_atom("A1 1 2 0").unwrap());
        }

        #[test]
        fn parse_atoms_without_name_or_some_values_is_error() {
            assert!(parse_string_for_atom("\t\n").is_err());
            assert!(parse_string_for_atom("\tname\n 1.0").is_err());
            assert!(parse_string_for_atom("\tname 1.0\t2.0").is_err());
            assert!(parse_string_for_atom("\tname 1.0 2.0 3").is_ok());
            assert!(parse_string_for_atom("\tname 1.0 2.0 a").is_err());
        }

        #[test]
        fn parse_atoms_sets_name_to_uppercase() {
            assert_eq!("AT1", parse_string_for_atom("at1 1 2 0").unwrap().code);
        }
    }
}

mod define_substrate {

}
<commit_msg>Implement constructing substrates from the UI<commit_after>//! Edit a `DataBase`.

use database::{write_database, DataBase};
use error::Result;
use ui::utils;
use ui::utils::{CommandList, CommandParser};

use std::error::Error;

#[derive(Clone, Copy, Debug)]
enum Command {
    AddResidue,
    RemoveResidue,
    AddSubstrate,
    RemoveSubstrate,
    WriteToDisk,
    SetLocation,
    ShowDatabase,
    QuitAndSave,
    QuitWithoutSaving,
}

pub fn user_menu(database: &mut DataBase) -> Result<&'static str> {
    let command_list: CommandList<Command> = vec![
        ("ra", Command::AddResidue, "Add a residue definition"),
        ("rr", Command::RemoveResidue, "Remove a residue definition"),
        ("sa", Command::AddSubstrate, "Add a substrate definition"),
        ("sr", Command::RemoveSubstrate, "Remove a substrate definition"),
        ("w", Command::WriteToDisk, "Write database to disk"),
        ("c", Command::SetLocation, "Change output location of database"),
        ("l", Command::ShowDatabase, "List database content"),
        ("f", Command::QuitAndSave, "Finish editing database"),
        ("a", Command::QuitWithoutSaving, "Abort editing and discard changes"),
    ];
    let commands = CommandParser::from_list(command_list);

    let path_backup = database.path.clone();
    let residues_backup = database.residue_defs.clone();
    let substrates_backup = database.substrate_defs.clone();

    println!("Editing the current database.\n");
    database.describe();
    println!("");

    loop {
        commands.print_menu();
        let input = utils::get_input_string("Selection")?;

        if let Some((cmd, tail)) = commands.get_selection_and_tail(&input) {
            match cmd {
                Command::AddResidue => {
                    match define_residue::user_menu() {
                        Ok(residue) => {
                            println!("Added residue '{}' to database.", residue.code);
                            database.residue_defs.push(residue);
                        },
                        Err(err) => println!("Could not create residue: {}", err.description()),
                    }
                },
                Command::RemoveResidue => {
                    match utils::remove_item(&mut database.residue_defs, &tail) {
                        Ok(i) => println!("Removed residue with index {} from database.", i),
                        Err(err) => println!("Could not remove residue: {}", err.description()),
                    }
                },
                Command::AddSubstrate => {
                    match define_substrate::user_menu(&database.residue_defs) {
                        Ok(substrate) => {
                            println!("Added substrate definition '{}' to database.",
                                     substrate.name);
                            database.substrate_defs.push(substrate);
                        },
                        Err(err) => println!("Could not create substrate: {}", err.description()),
                    }
                },
                Command::RemoveSubstrate => {
                    match utils::remove_item(&mut database.substrate_defs, &tail) {
                        Ok(i) => println!("Removed substrate with index {} from database.", i),
                        Err(err) => println!("Could not remove substrate: {}", err.description()),
                    }
                },
                Command::WriteToDisk => {
                    match write_database(&database) {
                        Ok(_) => println!("Wrote database to '{}'.",
                                          database.path.as_ref().unwrap().to_str().unwrap()),
                        Err(err) => println!("Could not write database: {}", err.description()),
                    }
                },
                Command::SetLocation => {
                    match database.set_path(&tail) {
                        Ok(_) => println!("Database path set to '{}'.",
                                          database.get_path_pretty()),
                        Err(err) => println!("Could not change database path: {}",
                                             err.description()),
                    }
                },
                Command::ShowDatabase => {
                    println!("");
                    database.describe();
                },
                Command::QuitAndSave => {
                    return Ok("Finished editing database.");
                },
                Command::QuitWithoutSaving => {
                    database.path = path_backup;
                    database.residue_defs = residues_backup;
                    database.substrate_defs = substrates_backup;

                    return Ok("Discarding changes to database.");
                },
            }
        } else {
            println!("Not a valid selection.");
        }

        println!("");
    }
}

mod define_residue {
    use error::{GrafenCliError, Result, UIErrorKind};
    use ui::utils;
    use ui::utils::{CommandList, CommandParser};

    use grafen::system::{Atom, Coord, ResidueBase};
    use std::error::Error;

    #[derive(Clone, Copy, Debug)]
    enum ResidueCommand {
        SetName,
        AddAtom,
        RemoveAtom,
        SwapAtoms,
        ShowResidue,
        QuitAndSave,
        QuitWithoutSaving,
    }

    pub fn user_menu() -> Result<ResidueBase> {
        let command_list: CommandList<ResidueCommand> = vec![
            ("n", ResidueCommand::SetName, "Set residue name"),
            ("at", ResidueCommand::AddAtom, "Add atom to residue"),
            ("r", ResidueCommand::RemoveAtom, "Remove atom from residue"),
            ("s", ResidueCommand::SwapAtoms, "Swap two atoms in list"),
            ("l", ResidueCommand::ShowResidue, "List current residue data"),
            ("f", ResidueCommand::QuitAndSave, "Finish and add residue to list"),
            ("a", ResidueCommand::QuitWithoutSaving, "Abort and discard changes")
        ];
        let commands = CommandParser::from_list(command_list);

        println!("Creating a new residue.\n");

        let mut name = String::new();
        let mut atoms: Vec<Atom> = Vec::new();

        loop {
            commands.print_menu();
            let input = utils::get_input_string("Selection")?;
            println!("");

            if let Some((cmd, tail)) = commands.get_selection_and_tail(&input) {
                match cmd {
                    ResidueCommand::SetName => {
                        name = tail.to_uppercase().to_string();
                        println!("Set residue name to '{}'", &name);
                    },
                    ResidueCommand::AddAtom => {
                        match parse_string_for_atom(&tail) {
                            Ok(atom) => {
                                println!("Added atom '{}' to residue.", &atom.code);
                                atoms.push(atom);
                            },
                            Err(err) => println!("Could not add atom: {}", err.description()),
                        }

                    },
                    ResidueCommand::RemoveAtom => {
                        match utils::remove_item(&mut atoms, &tail) {
                            Ok(i) => println!("Removed atom with index {} from residue.", i),
                            Err(err) => println!("Could not remove atom: {}", err.description()),
                        }
                    },
                    ResidueCommand::SwapAtoms => {
                        match utils::swap_items(&mut atoms, &tail) {
                            Ok((i, j)) => println!("Swapped atoms at index {} with atom at {}.",
                                                   i, j),
                            Err(err) => println!("Could not swap atoms: {}", err.description()),
                        }
                    },
                    ResidueCommand::ShowResidue => {
                        describe_residue(&name, &atoms);
                    },
                    ResidueCommand::QuitAndSave => {
                        if name.is_empty() {
                            println!("Cannot add residue: No name is set");
                        } else if atoms.is_empty() {
                            println!("Cannot add residue: No atoms are set");
                        } else {
                            return Ok(ResidueBase {
                                code: name,
                                atoms: atoms,
                            });
                        }
                    }
                    ResidueCommand::QuitWithoutSaving => {
                        return Err(GrafenCliError::from(UIErrorKind::Abort));
                    },
                }
            } else {
                println!("Not a valid selection.");
            }

            println!("");
        }
    }

    fn parse_string_for_atom<'a>(input: &'a str) -> Result<Atom> {
        let mut iter = input.splitn(2, ' ');
        let name = iter.next().and_then(|s| {
                if s.is_empty() {
                    None
                } else {
                    Some(s)
                }
            })
            .ok_or(UIErrorKind::BadValue("No name was given".to_string()))?;

        let tail = iter.next().unwrap_or("");

        let coords = utils::parse_string(&tail)?;
        let &x = coords.get(0)
                       .ok_or(UIErrorKind::BadValue("3 positions are required".to_string()))?;
        let &y = coords.get(1)
                       .ok_or(UIErrorKind::BadValue("3 positions are required".to_string()))?;
        let &z = coords.get(2)
                       .ok_or(UIErrorKind::BadValue("3 positions are required".to_string()))?;

        Ok(Atom {
            code: name.to_uppercase().to_string(),
            position: Coord::new(x, y, z),
        })
    }

    fn describe_residue<'a>(name: &'a str, atoms: &[Atom]) {
        println!("Residue name: '{}'", name);
        println!("Atoms:");
        for (i, atom) in atoms.iter().enumerate() {
            let (x, y, z) = atom.position.to_tuple();
            println!("{:4}. {} at ({:.1}, {:.1}, {:.1})", i, atom.code, x, y, z);
        }
    }

    #[cfg(test)]
    mod tests {
        use super::*;

        #[test]
        fn parse_atom_string() {
            let atom = Atom { code: "A1".to_string(), position: Coord::new(1.0, 2.0, 0.0) };
            assert_eq!(atom, parse_string_for_atom("A1 1 2 0").unwrap());
        }

        #[test]
        fn parse_atoms_without_name_or_some_values_is_error() {
            assert!(parse_string_for_atom("\t\n").is_err());
            assert!(parse_string_for_atom("\tname\n 1.0").is_err());
            assert!(parse_string_for_atom("\tname 1.0\t2.0").is_err());
            assert!(parse_string_for_atom("\tname 1.0 2.0 3").is_ok());
            assert!(parse_string_for_atom("\tname 1.0 2.0 a").is_err());
        }

        #[test]
        fn parse_atoms_sets_name_to_uppercase() {
            assert_eq!("AT1", parse_string_for_atom("at1 1 2 0").unwrap().code);
        }
    }
}

mod define_substrate {
    use database::SubstrateConfEntry;
    use error::{GrafenCliError, Result};
    use ui::utils;

    use grafen::substrate::LatticeType;
    use grafen::system::ResidueBase;

    #[derive(Clone, Copy, Debug)]
    /// Available lattices to construct from. Each of these require
    /// a separate constructor since they have different qualities in
    /// their corresponding `LatticeType` unit.
    enum LatticeCommand {
        Triclinic,
        Hexagonal,
        PoissonDisc,
    }

    pub fn user_menu(residue_list: &Vec<ResidueBase>) -> Result<SubstrateConfEntry> {
        let name = utils::get_input_string("Substrate name")
            .and_then(|string| {
                if string.is_empty() {
                    Err(GrafenCliError::UIError("No name was entered".to_string()))
                } else {
                    Ok(string)
                }
            })
            .map_err(|err| GrafenCliError::from(err))?;
        println!("");

        let residue = select_residue(&residue_list)?;
        println!("");

        let lattice = select_lattice()?;
        println!("");

        let std_z = select_deviation_along_z()?;
        println!("");

        Ok(SubstrateConfEntry { name, lattice, residue, std_z })
    }

    fn select_residue(residue_list: &Vec<ResidueBase>) -> Result<ResidueBase> {
        println!("Available residues:");
        for (i, residue) in residue_list.iter().enumerate() {
            println!("{:4}. {}", i, residue.code);
        }
        println!("");

        let input = utils::get_input_string("Selection")?;
        let index = utils::parse_string_for_index(&input, &residue_list)?;

        Ok(residue_list[index].clone())
    }

    fn select_lattice() -> Result<LatticeType> {
        let lattice_list = vec![
            (LatticeCommand::Triclinic, "Triclinic lattice: two base vector lengths and an angle in-between"),
            (LatticeCommand::Hexagonal, "Hexagonal lattice: a honeycomb grid with a spacing"),
            (LatticeCommand::PoissonDisc, "Poisson disc: Randomly generated points with a density")
        ];

        println!("Available lattices:");
        for (i, lattice) in lattice_list.iter().enumerate() {
            println!("{:4}. {}", i, lattice.1);
        }
        println!("");

        let input = utils::get_input_string("Selection")?;
        let index = utils::parse_string_for_index(&input, &lattice_list)?;

        match lattice_list[index].0 {
            LatticeCommand::Triclinic => {
                println!("A triclinic lattice is constructed from two base ");
                println!("vectors of length a and b, separated by an angle γ.");
                println!("");

                let input = utils::get_input_string("Input length 'a'")?;
                let a = utils::parse_string_single(&input)?;
                let input = utils::get_input_string("Input length 'b'")?;
                let b = utils::parse_string_single(&input)?;
                let input = utils::get_input_string("Input angle 'γ'")?;
                let gamma = utils::parse_string_single(&input)?;

                Ok(LatticeType::Triclinic { a, b, gamma })
            },

            LatticeCommand::Hexagonal => {
                println!("A hexagonal lattice is a honeycomb grid with an input side length.");
                println!("");

                let input = utils::get_input_string("Input side length")?;
                let a = utils::parse_string_single(&input)?;

                Ok(LatticeType::Hexagonal { a })
            },

            LatticeCommand::PoissonDisc => {
                println!("A Poisson disc is a generated set of points with an even distribution.");
                println!("They are generated with an input density in points per area.");
                println!("");

                let input = utils::get_input_string("Input density")?;
                let density = utils::parse_string_single(&input)?;

                Ok(LatticeType::PoissonDisc { density })
            },
        }
    }

    fn select_deviation_along_z() -> Result<Option<f64>> {
        let query = "Distribute residue positions along z with this deviation (default: No)";
        let selection = utils::get_input_string(query)?;

        match utils::parse_string_single(&selection) {
            Ok(value) => Ok(Some(value)),
            _ => Ok(None),
        }
    }
}
<|endoftext|>


<commit_before>extern crate wm_daemons;
use wm_daemons::config::load_config;
use wm_daemons::dbus_listen::{CallbackMap, SignalInfo, match_signal, make_signal_info};

extern crate config;
use self::config::types::Config;

extern crate dbus;
use self::dbus::{Connection, BusType};

use std::error::Error;

fn run_program(action: &str, conf: &Config) -> () {
    // TODO
}

fn handle_signal(info: &SignalInfo, conf: &Config) -> () {
    if info.member == Some("Lock".to_string()) {
        run_program("lock", conf);
    } else if info.member == Some("Unlock".to_string()) {
        run_program("unlock", conf);
    }
}

fn try_main() -> Result<(), Box<Error>> {
    let conf = try!(load_config("wm-session-agent", "config"));
    let conn = try!(Connection::get_private(BusType::System));

    let cbs: CallbackMap<Config> = vec![
        (make_signal_info(
            "org.freedesktop.login1.Session",
            "/org/freedesktop/login1/session/_33",
            "Lock",
        ), handle_signal),
        (make_signal_info(
            "org.freedesktop.login1.Session",
            "/org/freedesktop/login1/session/_33",
            "Unlock",
        ), handle_signal),
    ];

    for items in conn.iter(100) {
        match_signal(items, &cbs, &conf);
    }

    Ok(())
}

fn main() -> () {
    if let Err(err) = try_main() {
        panic!("{}", err.description());
    }
}
<commit_msg>wm-session-agent: minor fixes<commit_after>extern crate wm_daemons;
use wm_daemons::config::load_config;
use wm_daemons::dbus_listen::{CallbackMap, SignalInfo, match_signal, make_signal_info};

extern crate config;
use self::config::types::Config;

extern crate dbus;
use self::dbus::{Connection, BusType};

use std::error::Error;

fn run_program(action: &str, conf: &Config) -> () {
    // TODO
}

fn handle_signal(info: &SignalInfo, conf: &Config) -> () {
    if info.member == Some("Lock".to_string()) {
        run_program("lock", conf);
    } else if info.member == Some("Unlock".to_string()) {
        run_program("unlock", conf);
    }
}

fn try_main() -> Result<(), Box<Error>> {
    let conf = try!(load_config("wm-session-agent", "config"));
    let conn = try!(Connection::get_private(BusType::System));

    let cbs: CallbackMap<Config> = vec![
        (make_signal_info(
            "/org/freedesktop/login1/session/_33",
            "org.freedesktop.login1.Session",
            "Lock",
        ), handle_signal),
        (make_signal_info(
            "/org/freedesktop/login1/session/_33",
            "org.freedesktop.login1.Session",
            "Unlock",
        ), handle_signal),
    ];

    try!(conn.add_match("type='signal'"));

    for items in conn.iter(100) {
        match_signal(items, &cbs, &conf);
    }

    Ok(())
}

fn main() -> () {
    if let Err(err) = try_main() {
        panic!("{}", err.description());
    }
}
<|endoftext|>


<commit_before>use std::thread::{self, Thread};
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::collections::VecDeque;
use std::fs;
use modular_flow::graph::*;
use modular_flow::context::Context;
use plugin_loader::{self, NodeLibrary};

pub struct Instance {
    pub ctx: Arc<Context>,
    pub nodes: NodeInstances,
    pub types: NodeDescriptors,
}

impl Instance {
    pub fn new() -> Instance {
        Instance {
            ctx: Arc::new(Context::new(Graph::new())),
            nodes: NodeInstances::new(),
            types: NodeDescriptors::new(),
        }
    }
    pub fn load_lib(&self, path: &str) {
        {
            let libs = self.types.libs();
            let old_lib = libs.iter().find(|lib| lib.path == path);
            if let Some(old_lib) = old_lib {
                for node in self.nodes.nodes() {
                    if old_lib.nodes.iter().find(|desc| desc.name == node.type_name).is_some() {
                        self.stop_node(node.ctl.node().id()).unwrap();
                    }
                }
            }
        }
        let lib = self.types.load_library(path).unwrap();
        for node in self.nodes.nodes() {
            if let Some(node_desc) = lib.nodes.iter().find(|desc| desc.name == node.type_name) {
                self.nodes.remove(node.ctl.node().id());
                let ctl = (node_desc.new)(self.ctx.clone(), NewNodeConfig { node: Some(node.ctl.node().id()) });
                self.nodes.insert(NodeInstance {
                    ctl,
                    type_name: node.type_name.clone(),
                });
            }
        }
    }
    pub fn kill_node(&self, id: NodeID) -> Result<()> {
        self.stop_node(id)?;
        self.ctx
            .graph()
            .remove_node(id)?;
        self.nodes.remove(id);
        Ok(())
    }
    pub fn stop_node(&self, id: NodeID) -> Result<Arc<NodeInstance>> {
        let node = self.nodes.node(id).ok_or(Error::InvalidNode)?;
        node.ctl.stop();
        node.ctl.node().subscribe();
        while node.ctl.node().attached() {
            thread::park(); // TODO: relying on implementation detail
        }
        node.ctl.node().unsubscribe();
        node.ctl.node().flush()?;
        Ok(node)
    }
}

#[derive(Clone)]
pub struct NodeInstance {
    pub ctl: Arc<RemoteControl>,
    pub type_name: String,
}

pub struct NodeInstances {
    list: Mutex<Vec<Arc<NodeInstance>>>,
}

impl NodeInstances {
    pub fn new() -> NodeInstances {
        NodeInstances {
            list: Mutex::new(Vec::new()),
        }
    }
    pub fn insert(&self, inst: NodeInstance) {
        self.list.lock().unwrap().push(Arc::new(inst));
    }
    pub fn remove(&self, id: NodeID) {
        self.list.lock().unwrap().retain(|node| node.ctl.node().id() != id);
    }
    pub fn node(&self, id: NodeID) -> Option<Arc<NodeInstance>> {
        self.list.lock().unwrap().iter().cloned().find(|node| node.ctl.node().id() == id)
    }
    pub fn nodes(&self) -> Vec<Arc<NodeInstance>> {
        self.list.lock().unwrap().clone()
    }
}

pub struct NewNodeConfig {
    pub node: Option<NodeID>, // node id to attach to
}

#[derive(Clone, Debug)]
pub struct NodeDescriptor {
    pub name: String,
    pub new: fn(Arc<Context>, NewNodeConfig) -> Arc<RemoteControl>,
}

pub struct NodeDescriptors {
    load_count: AtomicUsize,
    libs: Mutex<Vec<Arc<NodeLibrary>>>,
}

impl NodeDescriptors {
    pub fn new() -> NodeDescriptors {
        NodeDescriptors {
            load_count: AtomicUsize::new(0),
            libs: Mutex::new(vec![]),
        }
    }
    pub fn libs(&self) -> Vec<Arc<NodeLibrary>> {
        self.libs.lock().unwrap().clone()
    }
    /// Replaces existing library with the same path if it exists
    pub fn load_library(&self, path: &str) -> plugin_loader::Result<Arc<NodeLibrary>> {
        let mut libs = self.libs.lock().unwrap();
        if let Some(old_lib_idx) = libs.iter_mut().position(|lib| lib.path == path) {
            let old_lib = libs.swap_remove(old_lib_idx);
            fs::remove_file(&old_lib.file_path).unwrap();
        }
        let new_path = path.to_string() + &usize::to_string(&self.load_count.fetch_add(1, Ordering::SeqCst));
        fs::copy(path, &new_path).unwrap();
        let new_lib = Arc::new(NodeLibrary::load(path, &new_path)?);
        libs.push(new_lib.clone());
        Ok(new_lib)
    }
    pub fn node(&self, name: &str) -> Option<NodeDescriptor> {
        self.nodes().iter().cloned().find(|node| node.name == name)
    }
    pub fn nodes(&self) -> Vec<NodeDescriptor> {
        self.libs.lock().unwrap().iter().flat_map(|lib| lib.nodes.clone()).collect()
    }
}

pub mod message {
    #[derive(Clone, Debug)]
    pub enum Type {
        Bool,
        Int,
        Float,
        String,
    }
    #[derive(Clone, Debug)]
    pub enum Value {
        Bool(bool),
        Int(i64),
        Float(f64),
        String(String),
    }
    #[derive(Clone, Debug)]
    pub struct ArgDesc {
        pub name: String,
        pub ty: Type,
    }
    #[derive(Clone, Debug)]
    pub struct Desc {
        pub name: String,
        pub args: Vec<ArgDesc>,
    }
    #[derive(Clone, Debug)]
    pub struct Message {
        pub desc: Desc,
        pub args: Vec<Value>,
    }
}

pub struct RemoteControl {
    ctx: Arc<Context>,
    node: Arc<Node>,
    stop_thread: Mutex<Option<Thread>>,
    stopped: AtomicBool,
    messages: Vec<message::Desc>,
    msg_queue: Mutex<VecDeque<message::Message>>,
}
impl RemoteControl {
    pub fn new(ctx: Arc<Context>, node: Arc<Node>, messages: Vec<message::Desc>) -> RemoteControl {
        RemoteControl {
            ctx,
            node,
            stop_thread: Mutex::new(None),
            stopped: AtomicBool::new(false),
            messages,
            msg_queue: Mutex::new(VecDeque::new()),
        }
    }
    pub fn message_descriptors(&self) -> &[message::Desc] {
        &self.messages
    }
    pub fn send_message(&self, msg: message::Message) {
        self.msg_queue.lock().unwrap().push_back(msg);
        self.node.set_aborting(true);
        self.node.notify();
    }
    pub fn recv_message(&self) -> Option<message::Message> {
        self.msg_queue.lock().unwrap().pop_front()
    }
    /// dangerous, assumes only one thread!! FIXME
    pub fn block_until_stopped(&self) {
        *self.stop_thread.lock().unwrap() = Some(thread::current());
        while !self.stopped.load(Ordering::Acquire) {
            thread::park();
        }
    }
    pub fn stop(&self) {
        self.node.set_aborting(true);
        self.stopped.store(true, Ordering::Release);
        self.stop_thread.lock().unwrap().as_ref().map(|thread| thread.unpark());
    }
    pub fn stopped(&self) -> bool {
        self.stopped.load(Ordering::Acquire)
    }
    pub fn node(&self) -> &Node {
        &*self.node
    }
    pub fn context(&self) -> Arc<Context> {
        self.ctx.clone()
    }
}
<commit_msg>periodically inform nodes that they need to die to work around a race<commit_after>use std::thread::{self, Thread};
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::collections::VecDeque;
use std::time::Duration;
use std::fs;
use modular_flow::graph::*;
use modular_flow::context::Context;
use plugin_loader::{self, NodeLibrary};

pub struct Instance {
    pub ctx: Arc<Context>,
    pub nodes: NodeInstances,
    pub types: NodeDescriptors,
}

impl Instance {
    pub fn new() -> Instance {
        Instance {
            ctx: Arc::new(Context::new(Graph::new())),
            nodes: NodeInstances::new(),
            types: NodeDescriptors::new(),
        }
    }
    pub fn load_lib(&self, path: &str) {
        {
            let libs = self.types.libs();
            let old_lib = libs.iter().find(|lib| lib.path == path);
            if let Some(old_lib) = old_lib {
                for node in self.nodes.nodes() {
                    if old_lib.nodes.iter().find(|desc| desc.name == node.type_name).is_some() {
                        self.stop_node(node.ctl.node().id()).unwrap();
                    }
                }
            }
        }
        let lib = self.types.load_library(path).unwrap();
        for node in self.nodes.nodes() {
            if let Some(node_desc) = lib.nodes.iter().find(|desc| desc.name == node.type_name) {
                self.nodes.remove(node.ctl.node().id());
                let ctl = (node_desc.new)(self.ctx.clone(), NewNodeConfig { node: Some(node.ctl.node().id()) });
                self.nodes.insert(NodeInstance {
                    ctl,
                    type_name: node.type_name.clone(),
                });
            }
        }
    }
    pub fn kill_node(&self, id: NodeID) -> Result<()> {
        self.stop_node(id)?;
        self.ctx
            .graph()
            .remove_node(id)?;
        self.nodes.remove(id);
        Ok(())
    }
    pub fn stop_node(&self, id: NodeID) -> Result<Arc<NodeInstance>> {
        let node = self.nodes.node(id).ok_or(Error::InvalidNode)?;
        node.ctl.stop();
        node.ctl.node().subscribe();
        while node.ctl.node().attached() {
            node.ctl.node().notify();
            thread::sleep(Duration::from_millis(25));
        }
        node.ctl.node().unsubscribe();
        node.ctl.node().flush()?;
        Ok(node)
    }
}

#[derive(Clone)]
pub struct NodeInstance {
    pub ctl: Arc<RemoteControl>,
    pub type_name: String,
}

pub struct NodeInstances {
    list: Mutex<Vec<Arc<NodeInstance>>>,
}

impl NodeInstances {
    pub fn new() -> NodeInstances {
        NodeInstances {
            list: Mutex::new(Vec::new()),
        }
    }
    pub fn insert(&self, inst: NodeInstance) {
        self.list.lock().unwrap().push(Arc::new(inst));
    }
    pub fn remove(&self, id: NodeID) {
        self.list.lock().unwrap().retain(|node| node.ctl.node().id() != id);
    }
    pub fn node(&self, id: NodeID) -> Option<Arc<NodeInstance>> {
        self.list.lock().unwrap().iter().cloned().find(|node| node.ctl.node().id() == id)
    }
    pub fn nodes(&self) -> Vec<Arc<NodeInstance>> {
        self.list.lock().unwrap().clone()
    }
}

pub struct NewNodeConfig {
    pub node: Option<NodeID>, // node id to attach to
}

#[derive(Clone, Debug)]
pub struct NodeDescriptor {
    pub name: String,
    pub new: fn(Arc<Context>, NewNodeConfig) -> Arc<RemoteControl>,
}

pub struct NodeDescriptors {
    load_count: AtomicUsize,
    libs: Mutex<Vec<Arc<NodeLibrary>>>,
}

impl NodeDescriptors {
    pub fn new() -> NodeDescriptors {
        NodeDescriptors {
            load_count: AtomicUsize::new(0),
            libs: Mutex::new(vec![]),
        }
    }
    pub fn libs(&self) -> Vec<Arc<NodeLibrary>> {
        self.libs.lock().unwrap().clone()
    }
    /// Replaces existing library with the same path if it exists
    pub fn load_library(&self, path: &str) -> plugin_loader::Result<Arc<NodeLibrary>> {
        let mut libs = self.libs.lock().unwrap();
        if let Some(old_lib_idx) = libs.iter_mut().position(|lib| lib.path == path) {
            let old_lib = libs.swap_remove(old_lib_idx);
            fs::remove_file(&old_lib.file_path).unwrap();
        }
        let new_path = path.to_string() + &usize::to_string(&self.load_count.fetch_add(1, Ordering::SeqCst));
        fs::copy(path, &new_path).unwrap();
        let new_lib = Arc::new(NodeLibrary::load(path, &new_path)?);
        libs.push(new_lib.clone());
        Ok(new_lib)
    }
    pub fn node(&self, name: &str) -> Option<NodeDescriptor> {
        self.nodes().iter().cloned().find(|node| node.name == name)
    }
    pub fn nodes(&self) -> Vec<NodeDescriptor> {
        self.libs.lock().unwrap().iter().flat_map(|lib| lib.nodes.clone()).collect()
    }
}

pub mod message {
    #[derive(Clone, Debug)]
    pub enum Type {
        Bool,
        Int,
        Float,
        String,
    }
    #[derive(Clone, Debug)]
    pub enum Value {
        Bool(bool),
        Int(i64),
        Float(f64),
        String(String),
    }
    #[derive(Clone, Debug)]
    pub struct ArgDesc {
        pub name: String,
        pub ty: Type,
    }
    #[derive(Clone, Debug)]
    pub struct Desc {
        pub name: String,
        pub args: Vec<ArgDesc>,
    }
    #[derive(Clone, Debug)]
    pub struct Message {
        pub desc: Desc,
        pub args: Vec<Value>,
    }
}

pub struct RemoteControl {
    ctx: Arc<Context>,
    node: Arc<Node>,
    stop_thread: Mutex<Option<Thread>>,
    stopped: AtomicBool,
    messages: Vec<message::Desc>,
    msg_queue: Mutex<VecDeque<message::Message>>,
}
impl RemoteControl {
    pub fn new(ctx: Arc<Context>, node: Arc<Node>, messages: Vec<message::Desc>) -> RemoteControl {
        RemoteControl {
            ctx,
            node,
            stop_thread: Mutex::new(None),
            stopped: AtomicBool::new(false),
            messages,
            msg_queue: Mutex::new(VecDeque::new()),
        }
    }
    pub fn message_descriptors(&self) -> &[message::Desc] {
        &self.messages
    }
    pub fn send_message(&self, msg: message::Message) {
        self.msg_queue.lock().unwrap().push_back(msg);
        self.node.set_aborting(true);
        self.node.notify();
    }
    pub fn recv_message(&self) -> Option<message::Message> {
        self.msg_queue.lock().unwrap().pop_front()
    }
    /// dangerous, assumes only one thread!! FIXME
    pub fn block_until_stopped(&self) {
        *self.stop_thread.lock().unwrap() = Some(thread::current());
        while !self.stopped.load(Ordering::Acquire) {
            thread::park();
        }
    }
    pub fn stop(&self) {
        self.node.set_aborting(true);
        self.stopped.store(true, Ordering::Release);
        self.stop_thread.lock().unwrap().as_ref().map(|thread| thread.unpark());
    }
    pub fn stopped(&self) -> bool {
        self.stopped.load(Ordering::Acquire)
    }
    pub fn node(&self) -> &Node {
        &*self.node
    }
    pub fn context(&self) -> Arc<Context> {
        self.ctx.clone()
    }
}
<|endoftext|>


<commit_before>//public mods
pub mod opcode;

//private mods
mod common_defs;
mod cpu_executor;
mod cpu_state;

// hoisted interfaces
pub use self::common_defs::OpcodeDebugInfo;
pub use self::common_defs::OpcodeExecInfo;

pub use self::cpu_executor::CpuExecutor;

pub use self::cpu_state::CpuState;
pub use self::cpu_state::DecodeRegister;

<commit_msg>brought OpcodeClass and AddressMode nums into cpu:: namespace<commit_after>//public mods
pub mod opcode;

//private mods
mod common_defs;
mod cpu_executor;
mod cpu_state;

// hoisted interfaces
pub use self::common_defs::OpcodeDebugInfo;
pub use self::common_defs::OpcodeExecInfo;
pub use self::common_defs::opcode_class::OpcodeClass;
pub use self::common_defs::address_mode::AddressMode;

pub use self::cpu_executor::CpuExecutor;

pub use self::cpu_state::CpuState;
pub use self::cpu_state::DecodeRegister;

<|endoftext|>


<commit_before>use cron::Schedule;
use chrono::{FixedOffset, Local};

use std::str::FromStr;
use std::thread;
use std::time::Duration;

use command::Command;

/// The object to create and execute cronjobs for yout application.
pub struct CronJob {
    name: String,
    command: Box<dyn Command>,
    seconds: Option<String>,
    minutes: Option<String>,
    hours: Option<String>,
    day_of_month: Option<String>,
    month: Option<String>,
    day_of_week: Option<String>,
    year: Option<String>,
    offset: Option<FixedOffset>,
}

impl CronJob {
    /// Constructs new `CronJob` object.
    pub fn new<C: Command>(name: &str, command: C) -> Self {
        CronJob {
            name: name.to_string(),
            command: Box::new(command),
            seconds: None,
            minutes: None,
            hours: None,
            day_of_month: None,
            month: None,
            day_of_week: None,
            year: None,
            offset: None,
        }
    }

    pub fn seconds(&mut self, seconds: &str) -> &mut Self {
        self.seconds = Some(seconds.to_string());
        self
    }

    pub fn minutes(&mut self, minutes: &str) -> &mut Self {
        self.minutes = Some(minutes.to_string());
        self
    }

    pub fn hours(&mut self, hours: &str) -> &mut Self {
        self.hours = Some(hours.to_string());
        self
    }

    pub fn day_of_month(&mut self, day_of_month: &str) -> &mut Self {
        self.day_of_month = Some(day_of_month.to_string());
        self
    }

    pub fn month(&mut self, month: &str) -> &mut Self {
        self.month = Some(month.to_string());
        self
    }

    pub fn day_of_week(&mut self, day_of_week: &str) -> &mut Self {
        self.day_of_week = Some(day_of_week.to_string());
        self
    }

    pub fn year(&mut self, year: &str) -> &mut Self {
        self.year = Some(year.to_string());
        self
    }

    pub fn offset(&mut self, timezone_offset: i32) -> &mut Self {
        self.offset = Some(FixedOffset::east(timezone_offset));
        self
    }

    pub fn get_schedule(&mut self) -> Schedule {
        let cron = format!("{} {} {} {} {} {} {}",
                           self.seconds.clone().unwrap_or("*".to_string()),
                           self.minutes.clone().unwrap_or("*".to_string()),
                           self.hours.clone().unwrap_or("*".to_string()),
                           self.day_of_month.clone().unwrap_or("*".to_string()),
                           self.month.clone().unwrap_or("*".to_string()),
                           self.day_of_week.clone().unwrap_or("*".to_string()),
                           self.year.clone().unwrap_or("*".to_string()));
        Schedule::from_str(&cron).unwrap()
    }

    /// Starts the cronjob without threading.
    pub fn start_job(&mut self) {
        let schedule = self.get_schedule();
        let offset = self.offset.unwrap_or(FixedOffset::east(0));

        loop {
            let mut upcoming = schedule.upcoming(offset).take(1);
            thread::sleep(Duration::from_millis(500));
            let local = &Local::now();

            if let Some(datetime) = upcoming.next() {
                if datetime.timestamp() <= local.timestamp() {
                    self.command.execute(&self.name);
                }
            }
        }
    }

    /// Starts the cronjob with threading. Stops when application quits.
    pub fn start_job_threaded(mut cronjob: CronJob) {
        thread::Builder::new()
            .name(cronjob.name.to_string())
            .spawn(move || { cronjob.start_job(); })
            .expect("There was an error in an cronjob");
    }
}
<commit_msg>optimized some more<commit_after>use cron::Schedule;
use chrono::{FixedOffset, Local};

use std::str::FromStr;
use std::thread;
use std::time::Duration;

use command::Command;

/// The object to create and execute cronjobs for yout application.
pub struct CronJob {
    name: String,
    command: Box<dyn Command>,
    seconds: Option<String>,
    minutes: Option<String>,
    hours: Option<String>,
    day_of_month: Option<String>,
    month: Option<String>,
    day_of_week: Option<String>,
    year: Option<String>,
    offset: Option<FixedOffset>,
}

impl CronJob {
    /// Constructs new `CronJob` object.
    pub fn new<C: Command>(name: &str, command: C) -> Self {
        CronJob {
            name: name.to_string(),
            command: Box::new(command),
            seconds: None,
            minutes: None,
            hours: None,
            day_of_month: None,
            month: None,
            day_of_week: None,
            year: None,
            offset: None,
        }
    }

    pub fn seconds(&mut self, seconds: &str) -> &mut Self {
        self.seconds = Some(seconds.to_string());
        self
    }

    pub fn minutes(&mut self, minutes: &str) -> &mut Self {
        self.minutes = Some(minutes.to_string());
        self
    }

    pub fn hours(&mut self, hours: &str) -> &mut Self {
        self.hours = Some(hours.to_string());
        self
    }

    pub fn day_of_month(&mut self, day_of_month: &str) -> &mut Self {
        self.day_of_month = Some(day_of_month.to_string());
        self
    }

    pub fn month(&mut self, month: &str) -> &mut Self {
        self.month = Some(month.to_string());
        self
    }

    pub fn day_of_week(&mut self, day_of_week: &str) -> &mut Self {
        self.day_of_week = Some(day_of_week.to_string());
        self
    }

    pub fn year(&mut self, year: &str) -> &mut Self {
        self.year = Some(year.to_string());
        self
    }

    pub fn offset(&mut self, timezone_offset: i32) -> &mut Self {
        self.offset = Some(FixedOffset::east(timezone_offset));
        self
    }

    /// Returns the schedule for the cronjob, with this you are able to get the next occurences.
    pub fn get_schedule(&mut self) -> Schedule {
        let asterix = String::from("*");
        let cron = format!("{} {} {} {} {} {} {}",
                           self.seconds.as_ref().unwrap_or(&asterix),
                           self.minutes.as_ref().unwrap_or(&asterix),
                           self.hours.as_ref().unwrap_or(&asterix),
                           self.day_of_month.as_ref().unwrap_or(&asterix),
                           self.month.as_ref().unwrap_or(&asterix),
                           self.day_of_week.as_ref().unwrap_or(&asterix),
                           self.year.as_ref().unwrap_or(&asterix));
        Schedule::from_str(&cron).unwrap()
    }

    /// Starts the cronjob without threading.
    pub fn start_job(&mut self) {
        let schedule = self.get_schedule();
        let offset = self.offset.unwrap_or(FixedOffset::east(0));

        loop {
            let mut upcoming = schedule.upcoming(offset).take(1);
            thread::sleep(Duration::from_millis(500));
            let local = &Local::now();

            if let Some(datetime) = upcoming.next() {
                if datetime.timestamp() <= local.timestamp() {
                    self.command.execute(&self.name);
                }
            }
        }
    }

    /// Starts the cronjob with threading. Stops when application quits.
    pub fn start_job_threaded(mut cronjob: CronJob) {
        thread::Builder::new()
            .name(cronjob.name.clone())
            .spawn(move || { cronjob.start_job(); })
            .expect("There was an error in an cronjob");
    }
}
<|endoftext|>