Module swipl::blob

source ·
Expand description

Blob support.

Blobs are a way to share data with SWI-Prolog which does not fit in any one of the built-in term types. They are stored in the SWI-Prolog environment as a special kind of atom.

This module, together with the various blob macros, implement support for different classes of blobs.

For all blob types, macros have been defined to easily define and implement them. This allows your type to be used with Term::get, Term::put, and Term::unify.

ArcBlob

This type of blob is a pointer to atomically reference counted rust data. Upon getting, putting or unifying terms with data of this type, only the pointer is transfered and reference counts are updated.

Examples

Using the default implementation for write and compare:


// note the keyword 'defaults' below - this makes sure that a
// default implementation of `ArcBlobImpl` is generated.
#[arc_blob("foo", defaults)]
struct Foo {
    num: u64
}

fn do_something(term1: &Term, term2: &Term) -> PrologResult<()> {
    let arc = Arc::new(Foo{num: 42});
    term1.unify(&arc)?;
    let retrieved: Arc<Foo> = term1.get()?;
    assert_eq!(42, retrieved.num);
    term2.put(&retrieved)?;

    Ok(())
}

Provide your own implementation for write and compare:


#[arc_blob("foo")]
struct Foo {
    num: u64
}

impl ArcBlobImpl for Foo {
    fn write(&self, stream: &mut PrologStream) -> std::io::Result<()> {
        write!(stream, "<foo {}>", self.num)
    }

    fn compare(&self, other: &Self) -> Ordering {
        self.num.cmp(&other.num)
    }
}

WrappedArcBlob

This type of blob is very similar to an ArcBlob. The difference is that it is wrapped in a struct. This is done due to the requirement that a trait from another crate can only be implemented for your own types. This means that ArcBlob cannot be directly implemented from code that depends on the swipl crate for an Arc that comes out of another dependency. The wrapper allows a trait to be implemented that does the job.

Examples

Using the default implementation for write and compare:


// Note that it is not possible to implement ArcBlob directly on a
// Vec<bool>, as it is not a type defined by us. That's why it
// needs to be wrapped.
wrapped_arc_blob!("foo", Foo, Vec<bool>, defaults);

fn do_something(term1: &Term, term2: &Term) -> PrologResult<()> {
    let wrapped = Foo(Arc::new(vec![true,false,true]));
    term1.unify(&wrapped)?;
    let retrieved: Foo = term1.get()?;
    assert!(!retrieved[1]);
    term2.put(&retrieved)?;

    Ok(())
}

Provide your own implementation for write and compare:


wrapped_arc_blob!("foo", Foo, Vec<bool> );

impl WrappedArcBlobImpl for Foo {
    fn write(this: &Vec<bool>, stream: &mut PrologStream) -> std::io::Result<()> {
        write!(stream, "<foo {:?}>",this)
    }

    fn compare(this: &Vec<bool>, other: &Vec<bool>) -> Ordering {
        this.cmp(other)
    }
}

CloneBlob

This type of blob copies its contents to and from SWI-Prolog when getting, putting or unifying terms with the data.

Examples


// note the keyword 'defaults' below - this makes sure that a
// default implementation of `CloneBlobImpl` is generated.
// note also that the struct below derives Clone, which allows it
// to be used as a clone blob.
#[clone_blob("foo", defaults)]
#[derive(Clone)]
struct Foo {
    num: u64
}

fn do_something(term1: &Term, term2: &Term) -> PrologResult<()> {
    let val = Foo{num: 42};
    term1.unify(&val)?;
    let retrieved: Foo = term1.get()?;
    assert_eq!(42, retrieved.num);
    term2.put(&retrieved)?;

    Ok(())
}

Provide your own implementation for write and compare:


#[clone_blob("foo")]
#[derive(Clone)]
struct Foo {
    num: u64
}

impl CloneBlobImpl for Foo {
    fn write(&self, stream: &mut PrologStream) -> std::io::Result<()> {
        write!(stream, "<foo {}>", self.num)
    }

    fn compare(&self, other: &Self) -> Ordering {
        self.num.cmp(&other.num)
    }
}

wrapped CloneBlob

For convenience, there’s also a wrapped_clone_blob! macro for cases where we wish to generate a blob out of cloneable data that is of a type defined in another crate. This is analogous to the wrapped arc blob, except that no extra types are required. There is no WrappedCloneBlob, instead, the wrapper just implements CloneBlob directly.

Examples


wrapped_clone_blob!("foo", Foo, Vec<bool>, defaults);

fn do_something(term1: &Term, term2: &Term) -> PrologResult<()> {
    let val = Foo(vec![true, false, true]);
    term1.unify(&val)?;
    let retrieved: Foo = term1.get()?;
    assert!(!retrieved[1]);
    term2.put(&retrieved)?;

    Ok(())
}

Provide your own implementation for write and compare:


wrapped_clone_blob!("foo", Foo, Vec<bool>);

impl CloneBlobImpl for Foo {
    fn write(&self, stream: &mut PrologStream) -> std::io::Result<()> {
        write!(stream, "<foo {:?}>", self.0)
    }

    fn compare(&self, other: &Self) -> Ordering {
        self.0.cmp(&other.0)
    }
}

Traits

Functions