imag/libimagruby/src/store.rs

409 lines
13 KiB
Rust
Raw Normal View History

2017-01-18 14:33:57 +00:00
//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
2017-01-21 17:16:24 +00:00
use libimagstore::store::Store;
use libimagerror::trace::trace_error;
use std::error::Error;
use std::ops::Deref;
use std::ops::DerefMut;
use ruru::{Class, Object, AnyObject, Boolean, RString, VM, Hash, NilClass, VerifiedObject};
use ruby_utils::IntoToml;
use toml_utils::IntoRuby;
use util::Wrap;
use util::Unwrap;
use storeid::RStoreId;
use entry::RFileLockEntry;
use cache::StoreHandle;
2017-01-21 17:16:24 +00:00
wrappable_struct!(StoreHandle, StoreWrapper, STORE_WRAPPER);
2017-01-21 17:16:24 +00:00
class!(RStore);
impl_wrap!(StoreHandle, STORE_WRAPPER);
impl_unwrap!(RStore, StoreHandle, STORE_WRAPPER);
2017-01-21 17:16:24 +00:00
impl_verified_object!(RStore);
macro_rules! call_on_store_by_handle {
{
$store_handle:ident named $name:ident inside $operation:block
}=> {{
call_on_store_by_handle! {
$store_handle
named $name
inside $operation
on fail return NilClass::new().to_any_object()
}
}};
{
$store_handle:ident named $name:ident inside $operation:block on fail return $ex:expr
} => {{
use cache::RUBY_STORE_CACHE;
let arc = RUBY_STORE_CACHE.clone();
{
let lock = arc.lock();
match lock {
Ok(mut hm) => {
match hm.get($store_handle) {
Some($name) => { $operation },
None => {
VM::raise(Class::from_existing("RuntimeError"),
"Tried to operate on non-existing object");
$ex
}
}
},
Err(e) => {
VM::raise(Class::from_existing("RuntimeError"), e.description());
$ex
}
}
}
}};
}
macro_rules! call_on_store {
2017-01-21 18:49:24 +00:00
{
$store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
$fle_name:ident <- fetch $fle_handle_name:ident
operation $operation:block
} => {
call_on_store! {
$store_name <- $itself wrapped inside $wrapper,
$fle_name <- fetch $fle_handle_name,
operation $operation,
on fail return NilClass::new()
}
};
{
$store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
$fle_name:ident <- fetch $fle_handle_name:ident,
operation $operation:block,
on fail return $fail_expr:expr
} => {
let handle = $itself.get_data(&*$wrapper);
call_on_store_by_handle! {
handle named $store_name inside {
let $fle_name = match $store_name.get($fle_handle_name) {
Ok(Some(fle)) => fle,
Ok(None) => {
VM::raise(Class::from_existing("RuntimeError"), "Obj does not exist");
return $fail_expr
},
Err(e) => {
VM::raise(Class::from_existing("RuntimeError"), e.description());
return $fail_expr
},
};
$operation
}
on fail return $fail_expr
}
2017-01-21 18:49:24 +00:00
};
2017-01-21 18:49:24 +00:00
{
$store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
operation $operation:block,
on fail return $fail_expr:expr
} => {
let handle = $itself.get_data(&*$wrapper);
call_on_store_by_handle! {
handle named $store_name inside $operation on fail return $fail_expr
}
2017-01-21 18:49:24 +00:00
};
{
$store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
operation $block
} => {
let handle = $itself.get_data(&*$wrapper);
call_on_store_by_handle! { handle named $name inside $operation }
2017-01-21 18:49:24 +00:00
};
}
2017-01-21 17:16:24 +00:00
methods!(
RStore,
itself,
// Create an FileLockEntry in the store
//
// # Returns:
//
// On success: A RFileLockEntry
// On failure: Nil
// On error: Nil + Exception
//
fn create(id: RStoreId) -> AnyObject {
2017-01-22 11:46:13 +00:00
use entry::FileLockEntryHandle;
let sid = typecheck!(id or return any NilClass::new()).unwrap().clone();
call_on_store! {
store <- itself wrapped inside STORE_WRAPPER,
operation {
match store.create(sid.clone()) {
Err(e) => {
trace_error(&e);
VM::raise(Class::from_existing("RuntimeError"), e.description());
NilClass::new().to_any_object()
},
Ok(entry) => {
// Take the location (StoreId) of the entry (we know it exists... so this
// is fine) and wrap it into a RFileLockEntry which is then returned to the
// user (as handle)
let sid = entry.get_location().clone();
let store_handle = itself.get_data(&*STORE_WRAPPER).clone();
FileLockEntryHandle::new(store_handle, sid).wrap()
},
}
},
on fail return NilClass::new().to_any_object()
}
}
2017-01-21 17:16:24 +00:00
// Retrieve an FileLockEntry from the store
//
// # Returns:
//
// On success: A RFileLockEntry
// On error: Nil + Exception
//
fn retrieve(id: RStoreId) -> AnyObject {
2017-01-22 11:45:26 +00:00
use entry::FileLockEntryHandle;
let sid = typecheck!(id or return any NilClass::new()).unwrap().clone();
call_on_store! {
store <- itself wrapped inside STORE_WRAPPER,
operation {
match store.retrieve(sid.clone()) {
Err(e) => {
trace_error(&e);
VM::raise(Class::from_existing("RuntimeError"), e.description());
NilClass::new().to_any_object()
},
Ok(entry) => {
// Take the location (StoreId) of the entry (we know it exists... so this
// is fine) and wrap it into a RFileLockEntry which is then returned to the
// user (as handle)
let sid = entry.get_location().clone();
let store_handle = itself.get_data(&*STORE_WRAPPER).clone();
FileLockEntryHandle::new(store_handle, sid).wrap()
},
}
},
on fail return NilClass::new().to_any_object()
}
2017-01-21 15:07:24 +00:00
}
2017-01-18 14:33:57 +00:00
2017-01-21 17:16:24 +00:00
// Get an FileLockEntry from the store
//
// # Returns:
//
// On success, if there is some: A RFileLockEntry
// On success, if there is none: Nil
// On error: Nil + Exception
//
fn get(sid: RStoreId) -> AnyObject {
2017-01-21 19:06:04 +00:00
use entry::FileLockEntryHandle;
let sid = typecheck!(sid or return any NilClass::new()).unwrap().clone();
call_on_store! {
store <- itself wrapped inside STORE_WRAPPER,
operation {
match store.get(sid.clone()) {
Err(e) => {
trace_error(&e);
VM::raise(Class::from_existing("RuntimeError"), e.description());
NilClass::new().to_any_object()
},
Ok(None) => NilClass::new().to_any_object(),
Ok(Some(entry)) => {
// Take the location (StoreId) of the entry (we know it exists... so this
// is fine) and wrap it into a RFileLockEntry which is then returned to the
// user (as handle)
let sid = entry.get_location().clone();
let store_handle = itself.get_data(&*STORE_WRAPPER).clone();
FileLockEntryHandle::new(store_handle, sid).wrap()
},
}
},
on fail return NilClass::new().to_any_object()
}
2017-01-18 14:33:57 +00:00
}
2017-01-21 17:16:24 +00:00
// Get all FileLockEntry of a module from the store
//
// # Returns:
//
// On success: A Array[RFileLockEntry]
// On error: Nil + Exception
//
fn retrieve_for_module(name: RString) -> AnyObject {
unimplemented!()
2017-01-20 10:12:06 +00:00
}
2017-01-21 17:16:24 +00:00
// Update a FileLockEntry in the store
//
// # Returns:
//
// On success: Nil
// On error: Nil + Exception
//
fn update(fle: RFileLockEntry) -> NilClass {
let fle = typecheck!(fle).unwrap().clone();
call_on_store! {
store <- itself wrapped inside STORE_WRAPPER,
real_fle <- fetch fle,
operation {
if let Err(e) = store.update(real_fle) {
trace_error(&e);
VM::raise(Class::from_existing("RuntimeError"), e.description());
}
NilClass::new()
},
on fail return NilClass::new()
}
2017-01-21 17:16:24 +00:00
}
2017-01-21 17:16:24 +00:00
// Delete a FileLockEntry from the store
//
// # Returns:
//
// On success: Nil
// On error: Nil + Exception
//
fn delete(sid: RStoreId) -> NilClass {
let sid = typecheck!(sid).unwrap().clone();
call_on_store! {
store <- itself wrapped inside STORE_WRAPPER,
operation {
if let Err(e) = store.delete(sid) {
trace_error(&e);
VM::raise(Class::from_existing("RuntimeError"), e.description());
}
NilClass::new()
},
on fail return NilClass::new()
}
2017-01-21 17:16:24 +00:00
}
2017-01-21 17:16:24 +00:00
// Save a FileLockEntry in a new path inside the store, keep the RFileLockEntry
//
// # Returns:
//
// On success: Nil
// On error: Nil + Exception
//
fn save_to(fle: RFileLockEntry, sid: RStoreId) -> NilClass {
let fle = typecheck!(fle).unwrap().clone();
let sid = typecheck!(sid).unwrap().clone();
2017-01-21 18:49:24 +00:00
call_on_store! {
store <- itself wrapped inside STORE_WRAPPER,
real_fle <- fetch fle,
operation {
if let Err(e) = store.save_to(&real_fle, sid) {
trace_error(&e);
VM::raise(Class::from_existing("RuntimeError"), e.description());
}
NilClass::new()
},
on fail return NilClass::new()
}
2017-01-21 17:16:24 +00:00
}
2017-01-21 17:16:24 +00:00
// Save a FileLockEntry in a new path inside the store, move the RFileLockEntry
//
// # Returns:
//
// On success: Nil
// On error: Nil + Exception
//
fn save_as(fle: RFileLockEntry, sid: RStoreId) -> NilClass {
let fle = typecheck!(fle).unwrap().clone();
let sid = typecheck!(sid).unwrap().clone();
2017-01-21 18:49:24 +00:00
call_on_store! {
store <- itself wrapped inside STORE_WRAPPER,
real_fle <- fetch fle,
operation {
if let Err(e) = store.save_as(real_fle, sid) {
trace_error(&e);
VM::raise(Class::from_existing("RuntimeError"), e.description());
}
NilClass::new()
},
on fail return NilClass::new()
}
2017-01-21 17:16:24 +00:00
}
2017-01-21 17:16:24 +00:00
// Move one entry in the store to another place, by its ID
//
// # Returns:
//
// On success: Nil
// On error: Nil + Exception
//
fn move_by_id(old: RStoreId, nw: RStoreId) -> NilClass {
let old = typecheck!(old).unwrap().clone();
let nw = typecheck!(nw).unwrap().clone();
2017-01-21 18:49:24 +00:00
call_on_store! {
store <- itself wrapped inside STORE_WRAPPER,
operation {
if let Err(e) = store.move_by_id(old, nw) {
trace_error(&e);
VM::raise(Class::from_existing("RuntimeError"), e.description());
}
NilClass::new()
},
on fail return NilClass::new()
}
2017-01-21 17:16:24 +00:00
}
2017-01-21 17:16:24 +00:00
// Get the path of the store object
//
// # Returns:
//
// A RString
//
fn path() -> RString {
2017-01-21 18:49:24 +00:00
call_on_store! {
store <- itself wrapped inside STORE_WRAPPER,
operation {
store.path()
.clone()
.to_str()
.map(RString::new)
.unwrap_or(RString::new(""))
},
on fail return RString::new("")
}
2017-01-21 17:16:24 +00:00
}
2017-01-21 17:16:24 +00:00
);
2017-01-21 17:16:24 +00:00
pub fn setup() {
unimplemented!()
2017-01-20 10:12:06 +00:00
}