Rust Object Format (.rof)

Rust object format allows rust objects to be serialized to a file in a text format very closely resembling the original object. It also allows easy transfer of objects between different programming langauges, as the objects can be created in their respective language, serialized to string, send to another programming language, deserialzed and used once again.

TL;DR A library that can serialize and deserialize rust objects to string which allows simple file saving and transmission of rust objects between separate programming languages.

Table of contents

Design Goals
Language
Rust Library Docs
JS Library Docs

Design Goals

Use case

Language

Structs

Encapsulated by a pair of curly brackets

js { title: string = "Ferris the crab"; }

Each object property is defined as follows, and always ended by a semicolon.

propertyname: _propertytype_ = propertyvalue_;

propertyname_ = propertyvalue_;

Simple Property Types

A simple property type only includes a base type

Boolean Types

type annotation optional, can be implied

rust is_swimming: bool = false;

Text Types

type annotation optional, can be implied

Number Types

All integer type values are written the same

All floating type values are written the same

type annotation mandatory, cannot be implied

Complex Property Types

A complex/compound property includes a base type along with x number of sub types which can be mix of simple and complex property types

Tuples and Arrays

type annotation optional if tuple parameter types are optional

type annotation optional if array object type is optional

Structs and Hashmaps

rust passwords: hashmap<u16, string> = { 739341: "abc123"; 210405: "football32"; 826135: "dragon97"; };

type annotation optional if hashmap key and value object types are optional

rust passwords = { 739341: string = "abc123", "210405": string = "football32", 826135: enum<string> = None; };

Hashmaps and structs are not interchangeable as there are some key differences

Type annotation mandatory; If you want your data to be loaded in as a hashmap, then you must annotate the value as a hashmap, or it will be loaded in as a struct, and vice-versa.

Enums


rust enum action { IDLE, SLEEPING, JUMP(f64 /* jump power */), RUN(f64 /* x-velocity */, f64 /* y-velocity */), EAT(String /* food item */), }

Type annotation optional if enum parameter types are optional

The keyword "option" can also be used to subsitute "enum" and works exactly the same as the "enum" keyword; When using option enums you can then use the "option" keyword instead of "enum" to make it more readable. The "option" keyword will work fine for any other enum types, but is strongly discouraged.

Formatting

js { title: string = "Ferris the crab"; age: usize = 25; favourite_color: enum = ORANGE; accessories: array<enum<usize>> = [ SUNGLASSES(3), GOLDEN_SHOES(1) ]; }

Rust Library Documentation

High Level API

```rs

[derive(RofCompat)]

enum SongGenre { ROCK, POP, HIPHOP, JAZZ, COUNTRY, HEAVYMETAL, EDM }

[derive(RofCompat)]

struct Song { songtitle: String, songauthor: String, timestamp: usize, song_genre: SongGenre }

fn main() { let mut song = Song::loadfromfile("C:\Songs\Song32.rof");

song.timestamp += 1; // Increment the timestamp by 1

song.save_to_file(
        "C:\\Songs\\Song32.rof",
        true /* pretty print option, adds tabs, spaces and newlines to make the file more human-readable, but will not change the data itself in any way */,
    )
    .expect("Could not save song to a file");

} ```

The high level API is as simple as implementing the RofCompat trait for any rust struct or enum. This RofCompat trait allows you to serialize the object back to a low level DataValue strucutre, which can then be saved to a file. The RofCompat trait can also deserialize low level data value structures back into it's original form. The RofCompat trait also provides other utility functions such as

Almost any struct or enum can implement the RofCompat trait by using it's derive macro under these requirements

As explained above you can implement RofCompat manually, as shown in the example below, it is recommended that you read over the low level api before trying this for yourself. This allows for more fine tuned control over how exactly your struct/enum is represented in a low level form.

```rs

[derive(Default)]

struct Color { r: u8, g: u8, b: u8, }

impl RofCompat for Color { fn serialize(&self) -> Box { Box::new(DataValueInteger::U32( 65536 * (self.r as u32) + 256 * (self.g as u32) + (self.b as u32), )) }

fn deserialize(rof_object: Box<dyn DataValue>) -> Self {
    let color_int: u32 = rof_object.as_u32();

    Self {
        r: (color_int % 16_777_216 / 65_536) as u8,
        g: (color_int % 65_536 / 256) as u8,
        b: (color_int % 256) as u8,
    }
}

} ```

The utility functions are implemented for you based on those two functions. As you can see, now the stored data is much more concise and this is a good example of even though not always necessary, sometimes implementing RofCompat manually is a good idea.

Unlike the low level api, using the RofCompat trait requires little understanding of how the internal system actually works, and can quickly be setup.

Low Level API

The Rof object is responsible for all serializing and deserializing to files in Rof, and backs the higher level RofCompat trait. You can define a new Rof as follows.

```rs // Load computer file as a rof

let computerrof = Rof::loadfromfile("J:\Programming\Rust\rof\exampleobjects\computer.rof");

// Convert the rof to a struct structure

let mut computerstructure = computerrof.getobject().asstruct_structure();

let computername: String = match computerstructure.get("computername") { Some(loadedcomputername) => loadedcomputername.asstring(), None => String::default(), // "" };

let mut computerram: usize = match computerstructure.get("computerram") { Some(loadedcomputerram) => loadedcomputerram.asusize(), None => usize::default(), // 0 };

let computertype: ComputerType = match computerstructure.get("computertype") { Some(loadedcomputertype) => match loadedcomputertype.asenumstructure().0.asref() { "windows" => ComputerType::WINDOWS, "linux" => ComputerType::LINUX, "macos" => ComputerType::MACOS, "reactos" => ComputerType::REACTOS, _ => ComputerType::REACTOS, }, None => ComputerType::default(), };

// Print out the parsed computer

println!( "Loaded {:?} Computer, named {} with {}gb of ram", computertype, computername, computer_ram );

// Modify the computer

computer_ram += 1;

// Convert the computer back into a struct structure

let computerstructproperties: Vec = vec![ Property::new( String::from("computername"), Box::new(DataValueString::new(computername)), // OR computername.serialize() ), Property::new( String::from("computerram"), Box::new(DataValueInteger::USIZE(computerram)), // OR computerram.serialize() ), Property::new( String::from("computertype"), Box::new(DataValueEnum::new( match computertype { ComputerType::WINDOWS => "windows", ComputerType::LINUX => "linux", ComputerType::MACOS => "macos", ComputerType::REACTOS => "reactos", } .to_string(), Vec::new(), )), ), ];

let computerstructstructure = DataValueStruct::new(computerstructproperties);

// Save rof to computer file

// Must create a new rof object, becausue the .get_object() function returns an immutable reference

Rof::new(Box::new(computerstructstructure)) .savetofile( "J:\Programming\Rust\rof\example_objects\computer.rof", true, ) .expect("Could not save computer to file"); ```

The low level api is there for anybody who wants to use it, although using the high level RofCompat api is recommended because it is more readable, requires much less boilerplate and is more beginner friendly.

Javascript Library Documentation

In Development