Module interoptopus::patterns::service[][src]

Expand description

Bundles function with common receiver into a service or ‘class’ in object oriented languages.

Services provide a convenient way to manage state and memory between method invocations. They are similar to classes in object oriented languages, but we refrained from naming them as such because for lifetime and memory-safety reasons it would be best practice to only have “a few” well-defined instances around at any given time, not millions with arbitrary inter-dependencies.

That said, services usually translate to classes in languages supporting them, automatically guard against panics (prevent them from bubbling into C which would be undefined behavior) and can provide transparent error handling.

In short, if your library offers a “service”, the service pattern might give you a noticeable quality of life improvement.

Defining Services

To define a service you need the following parts:

  • An opaque type; the instance of a service
  • A Rust Error type mappable to an FFIError enum via From<Error>
  • Some methods on the opaque type.

Example

In this example we define a service called SimpleService with a constructor and two methods. The type MyFFIError is not shown, but implemented as in the FFIError example.

use interoptopus::{ffi_type, ffi_service, ffi_service_ctor, ffi_service_method};
use interoptopus::patterns::result::FFIError;

#[ffi_type(opaque)]
pub struct SimpleService {
    pub some_value: u32,
}

#[ffi_service(error = "MyFFIError", prefix = "simple_service_")]
impl SimpleService {

    #[ffi_service_ctor]
    pub fn new_with(some_value: u32) -> Result<Self, Error> {
        Ok(Self { some_value })
    }

    pub fn maybe_fails(&self, x: u32) -> Result<(), Error> {
        Ok(())
    }

    #[ffi_service_method(direct)]
    pub fn just_return_value(&self) -> u32 {
        self.some_value
    }
}

In languages supporting this pattern bindings will be generated allowing the service to be instantiated and called like this:

var x = new SimpleService(123);
x.MaybeFails(456);
x.JustReturnValue();
x.Dispose();

In other languages and on the C FFI level the following methods would be emitted:

myffierror simple_service_new_with(simpleservice** context, uint32_t some_value);
myffierror simple_service_destroy(simpleservice** context);
myffierror simple_service_maybe_fails(simpleservice* context, uint32_t x);
uint32_t simple_service_just_return_value(simpleservice* context);

Structs

Combines a receiver, constructor, destructor and multiple methods in one entity.