Packages

Libraries for operational transformations, via a Rust NIF.

Current section

Files

Jump to
ot_ex_rust native rust_ot src lib.rs
Raw

native/rust_ot/src/lib.rs

extern crate rustler;
mod ot;
use ot::Operation;
use ot::OperationSeq;
use rustler::*;
use serde_rustler::{from_term, to_term};
use std::iter::FromIterator;
mod atoms {
rustler::atoms! {
ok,
error,
//atom __true__ = "true";
//atom __false__ = "false";
}
}
impl<'a> Decoder<'a> for Operation {
fn decode(term: Term<'a>) -> Result<Operation, rustler::Error> {
Ok(from_term(term).unwrap())
}
}
impl<'a> Encoder for OperationSeq {
fn encode<'b>(&self, env: Env<'b>) -> Term<'b> {
to_term(env, self).unwrap()
}
}
#[nif]
fn apply<'a>(env: Env<'a>, code: String, operations: Vec<Operation>) -> Result<Term<'a>, Error> {
let operation = OperationSeq::from_iter(operations);
let utf16_encoded_code = code.encode_utf16().collect::<Vec<u16>>();
let result = operation.apply(&utf16_encoded_code);
match result {
Ok(encoded_result) => {
Ok((atoms::ok(), String::from_utf16_lossy(&encoded_result)).encode(env))
}
Err(err) => Ok((atoms::error(), format!("{}", err)).encode(env)),
}
}
#[nif]
fn transform<'a>(
env: Env<'a>,
operation_a_arg: Vec<Operation>,
operation_b_arg: Vec<Operation>,
) -> Result<Term<'a>, Error> {
let operation_a: OperationSeq = OperationSeq::from_iter(operation_a_arg);
let operation_b: OperationSeq = OperationSeq::from_iter(operation_b_arg);
match operation_a.transform(&operation_b) {
Ok((left, right)) => Ok((atoms::ok(), left, right).encode(env)),
Err(err) => Ok((atoms::error(), format!("{}", err)).encode(env)),
}
}
#[nif]
fn transform_index<'a>(
env: Env<'a>,
operation_a_arg: Vec<Operation>,
index: u64,
) -> Result<Term<'a>, Error> {
let operation_a = OperationSeq::from_iter(operation_a_arg);
Ok((operation_a.transform_index(index)).encode(env))
}
#[nif]
fn compose<'a>(
env: Env<'a>,
operation_a_arg: Vec<Operation>,
operation_b_arg: Vec<Operation>,
) -> Result<Term<'a>, Error> {
let operation_a = OperationSeq::from_iter(operation_a_arg);
let operation_b = OperationSeq::from_iter(operation_b_arg);
match operation_a.compose(&operation_b) {
Ok(composed_op) => Ok((atoms::ok(), composed_op).encode(env)),
Err(err) => Ok((atoms::error(), format!("{}", err)).encode(env)),
}
}
#[nif]
fn compose_many<'a>(env: Env<'a>, operation_args: Vec<Vec<Operation>>) -> Result<Term<'a>, Error> {
let mut operation_args_clone = operation_args.clone();
let operation_arg_a = operation_args_clone.remove(0);
let mut final_result = OperationSeq::from_iter(operation_arg_a);
for op_arg in operation_args_clone {
let new_op = OperationSeq::from_iter(op_arg);
match final_result.compose(&new_op) {
Ok(result) => final_result = result,
Err(ot_error) => return Ok((atoms::error(), format!("{}", ot_error)).encode(env)),
}
}
Ok((atoms::ok(), final_result).encode(env))
}
init! {
"Elixir.Rust.OT",
[
apply,
transform,
transform_index,
compose,
compose_many
]
}