Crate object_space[][src]

NOTICE: THE LIBRARY IS STILL EXPERIMENTAL AND VERY BUGGY. API IS INCOMPLETE AND SUBJECTED TO CHANGE. PLEASE PROCEED WITH CAUTION

This crate is an implementation of ObjectSpace - a natural progression on the idea of TupleSpace proposed by Gelernter in 1985. ObjectSpace is a data structure with the capability of holding any structure (e.g: a string, an int, and a complex struct could all lives under one ObjectSpace). It also allows retrieving a struct based on the value of a field.

This crate also provides a fully thread-safe implementation of ObjectSpace, which allows simple concurrent and distributed programming.

API

An ObjectSpace could perform the following tasks:

  • write an object to the space. E.g: space.write(test_struct)
  • try_read (non-blocking), read (blocking), and read_all structs of a type. E.g: space.try_read::<TestStruct>()
  • try_take, take, and take_all to remove and returns struct of a type. E.g: space.try_take::<TestStruct>()

Notice that an ObjectSpace could hold data from any types, which means that an i64, a String, and a complex struct could all live under one space (which leads to the somewhat wordy API for retrieving items).

Additionally, by implementing ValueLookupObjectSpace and RangeLookupObjectSpace, an ObjectSpace could retrieve item based on the value of a field. Notice that the field must be a "basic" field: the type of the field must be either an int, a string, or a bool.

E.g: Given a TestStruct:

struct Prop {
        touched: bool
}

struct TestStruct {
    index: i32,
    property: Prop,
}

space.try_take_by_value::<TestStruct>("property.touched", true) will return a TestStruct with the value true for property.touched. space.try_take_by_range::<TestStruct>("index", 2..10) will return a TestStruct with the value of index between in the range 2..10

For further information, please read the documentation of ObjectSpace, RangeLookupObjectSpace, and ValueLookupObjectSpace

TreeObjectSpace

TreeSpaceObject is a referenced implementation of ObjectSpace trait. It is, in essence, a concurrent HashMap of TypeId and corresponding Entry for each type. Each Entry stores objects by serializing & flattening their structure, then put the values of basic fields in a BTreeMap for efficient lookup. TreeSpaceObject is thread-safe, which allows it to be used in concurrent and distributed settings.

Example

Here is a program to calculate all primes up to a limit using ObjectSpace

extern crate object_space;
extern crate serde;
#[macro_use]
extern crate serde_derive;

use std::thread;
use std::env;
use std::sync::Arc;

use object_space::{ObjectSpace, ValueLookupObjectSpace, RangeLookupObjectSpace, TreeObjectSpace};

fn main() {
    let mut args = env::args();
    let upper_lim = 1000000;
    let thread_count = 4;

    // setup. add 2 & 3 just because we can
    let mut n = 4;
    let space = Arc::new(TreeObjectSpace::new());
    space.write::<i64>(2);
    space.write::<i64>(3);

    // create 4 worker threads
    for _ in 0..thread_count {
        let space_clone = space.clone();
        thread::spawn(move || {
            check_numbers(space_clone);
        });
    }

    // continue until we hit limit
    while n < upper_lim {
        let max = if n * n < upper_lim { n * n } else { upper_lim };

        for i in 0..thread_count {
            // divide work evenly between threads
            let start =
                n + (((max - n) as f64) / (thread_count as f64) * (i as f64)).round() as i64;
            let end =
                n + (((max - n) as f64) / (thread_count as f64) * ((i + 1) as f64)).round() as i64;

            let clone = space.clone();
            clone.write(Task {
                finished: false,
                start: start,
                end: end,
            });
        }

        // "joining" threads
        for _ in 0..thread_count {
            let clone = space.clone();
            clone.take_by_value::<Task>("finished", &true);
        }
        n = max;
    }
}

fn check_numbers(space: Arc<TreeObjectSpace>) {
    loop {
        let task = space.take_by_value::<Task>("finished", &false);
        let max = task.end;
        let min = task.start;
        let primes: Vec<i64> = space.read_all::<i64>().filter(|i| i * i < max).collect();
        for i in min..max {
            if primes.iter().all(|prime| i % prime != 0) {
                space.write(i);
            }
        }
        space.write(Task {
            finished: true,
            start: min,
            end: max,
        });
    }
}

#[derive(Serialize, Deserialize)]
struct Task {
    finished: bool,
    start: i64,
    end: i64,
}

Structs

TreeObjectSpace

A thread-safe reference ObjectSpace implementation

Traits

ObjectSpace

Basic interface of an ObjectSpace.

RangeLookupObjectSpace

An extension of ObjectSpace supporting retrieving structs by range of a field.

ValueLookupObjectSpace

An extension of ObjectSpace supporting retrieving structs by value of a field.