msgpack

Download zip
Author
Version
0.1.0
License
MIT
Last updated
last year
Downloads
19

#MoonBit MessagePack Library

This is a MessagePack implementation for MoonBit, ported from Deno's std/msgpack.

#Overview

MessagePack is an efficient binary serialization format. It lets you exchange data among multiple languages like JSON, but it's faster and smaller. Small integers are encoded into a single byte, and typical short strings require only one extra byte in addition to the strings themselves.

#Features

  • Basic data types: nil, boolean, integers, floats, strings
  • Collections: arrays and maps
  • Binary data: arbitrary byte sequences
  • Efficient encoding: Uses MessagePack's optimized formats (fixint, fixstr, fixarray, fixmap)
  • Round-trip compatibility: Encode and decode with full fidelity
  • Error handling: Comprehensive error types with descriptive messages

#Supported Data Types

The library supports encoding and decoding the following types:

  • nil values
  • boolean values (true/false)
  • Integers: 32-bit (Int), 64-bit signed (Int64), 64-bit unsigned (UInt64)
  • Floating-point: 64-bit (Double)
  • UTF-8 strings
  • Binary data (Bytes)
  • Arrays of values
  • Maps with string keys

#API Reference

#Core Types

enum Value {
Nil
Bool(Bool)
Int(Int)
Int64(Int64)
UInt64(UInt64)
Float(Double)
String(String)
Binary(Bytes)
Array(Array[Value])
Map(Map[String, Value])
}

enum MsgPackError {
IOError(String)
TypeMismatch(String)
InvalidData(String)
}

#Core Functions

// Encode a MessagePack value to bytes
fn encode(value : Value) -> Bytes

// Decode bytes to a MessagePack value
fn decode(data : Bytes) -> Result[Value, MsgPackError]

#Value Creation Helpers

fn create_nil() -> Value
fn create_bool(b : Bool) -> Value
fn create_int(i : Int) -> Value
fn create_int64(i : Int64) -> Value
fn create_uint64(u : UInt64) -> Value
fn create_float(f : Double) -> Value
fn create_string(s : String) -> Value
fn create_binary(b : Bytes) -> Value
fn create_array(arr : Array[Value]) -> Value
fn create_map(map : Map[String, Value]) -> Value

#Value Conversion Methods

fn Value::to_string(self : Value) -> Result[String, MsgPackError]
fn Value::to_int(self : Value) -> Result[Int, MsgPackError]
fn Value::to_bool(self : Value) -> Result[Bool, MsgPackError]

#Usage Examples

#Basic Encoding and Decoding

// Create values
let nil_val = create_nil()
let bool_val = create_bool(true)
let int_val = create_int(42)
let str_val = create_string("hello")

// Encode to MessagePack
let nil_encoded = encode(nil_val) // 1 byte: [0xc0]
let bool_encoded = encode(bool_val) // 1 byte: [0xc3]
let int_encoded = encode(int_val) // 1 byte: [0x2a]
let str_encoded = encode(str_val) // 6 bytes: [0xa5, 'h', 'e', 'l', 'l', 'o']

// Decode from MessagePack
match decode(nil_encoded) {
Ok(Nil) => println("Successfully decoded nil")
Ok(_) => println("Wrong type")
Err(e) => println("Error: " + e.to_string())
}

#Working with Collections

// Create an array
let array_val = create_array([
create_int(1),
create_int(2),
create_int(3)
])

// Create a map
let map = Map::new()
map["name"] = create_string("MoonBit")
map["version"] = create_int(1)
let map_val = create_map(map)

// Encode collections
let array_encoded = encode(array_val) // [0x93, 0x01, 0x02, 0x03]
let map_encoded = encode(map_val) // [0x82, ...]

#Round-trip Example

// Original data
let original = create_array([
create_nil(),
create_bool(true),
create_int(42),
create_string("hello")
])

// Encode and decode
let encoded = encode(original)
match decode(encoded) {
Ok(decoded) => {
// `decoded` should be equivalent to `original`
println("Round-trip successful!")
}
Err(e) => println("Round-trip failed: " + e.to_string())
}

#MessagePack Format Compliance

This implementation follows the official MessagePack specification. Key format features:

  • Positive fixint (0x00-0x7f): Single-byte encoding for integers 0-127
  • Negative fixint (0xe0-0xff): Single-byte encoding for integers -32 to -1
  • fixstr (0xa0-0xbf): Compact encoding for strings up to 31 bytes
  • fixarray (0x90-0x9f): Compact encoding for arrays up to 15 elements
  • fixmap (0x80-0x8f): Compact encoding for maps up to 15 key-value pairs
  • Extended formats: Support for larger strings, arrays, and maps
  • Type safety: Strong typing prevents encoding/decoding errors

#Running the Demo

To see the library in action:

moon run .

This will run a comprehensive demo showing:
  1. Basic type encoding and decoding
  2. Round-trip encoding/decoding tests
  3. MessagePack format verification
  4. Collection handling (arrays and maps)

#Current Limitations

This is a basic implementation with some current limitations:

  1. Float encoding: Currently uses placeholder bytes instead of proper IEEE 754 encoding
  2. 64-bit integers: Simplified encoding (currently encoded as 32-bit placeholders)
  3. Binary data: Basic support (currently encodes length headers only)
  4. String encoding: Proper UTF-8 support but simplified length handling
  5. Extended types: MessagePack extension types are not yet implemented

#Future Enhancements

#Testing

The library includes comprehensive tests covering:

  • Basic type encoding/decoding
  • Round-trip compatibility
  • MessagePack format compliance
  • Error handling
  • Edge cases

Run tests with:

moon test

#Contributing

This library was created as a learning exercise in porting JavaScript/TypeScript libraries to MoonBit. Contributions are welcome to improve the implementation and add missing features.

#License

This implementation is inspired by and ported from the Deno standard library's MessagePack implementation, which is MIT licensed.

MsgPackError

pub enum MsgPackError {
TypeMismatch(String)
InvalidData(String)
}

MsgPackError::to_string

fn MsgPackError::to_string(self : MsgPackError) -> String

Value

pub enum Value {
Nil
Bool(Bool)
Int(Int)
Int64(Int64)
UInt64(UInt64)
Float(Double)
String(String)
Binary(Bytes)
Array(Array[Value])
Map(Map[String, Value])
}

Value::to_bool

fn Value::to_bool(self : Value) -> Result[Bool, MsgPackError]

Value::to_int

fn Value::to_int(self : Value) -> Result[Int, MsgPackError]

Value::to_string

fn Value::to_string(self : Value) -> Result[String, MsgPackError]

ARRAY16_CODE

let ARRAY16_CODE : Int

ARRAY32_CODE

let ARRAY32_CODE : Int

BIN8_CODE

let BIN8_CODE : Int

FALSE_CODE

let FALSE_CODE : Int

FIXARRAY_CODE

let FIXARRAY_CODE : Int

FIXMAP_CODE

let FIXMAP_CODE : Int

FIXSTR_CODE

let FIXSTR_CODE : Int

FLOAT64_CODE

let FLOAT64_CODE : Int

INT16_CODE

let INT16_CODE : Int

INT32_CODE

let INT32_CODE : Int

INT8_CODE

let INT8_CODE : Int

MAP16_CODE

let MAP16_CODE : Int

MAP32_CODE

let MAP32_CODE : Int

NEGATIVE_FIXINT_CODE

let NEGATIVE_FIXINT_CODE : Int

NIL_CODE

let NIL_CODE : Int

STR16_CODE

let STR16_CODE : Int

STR32_CODE

let STR32_CODE : Int

STR8_CODE

let STR8_CODE : Int

TRUE_CODE

let TRUE_CODE : Int

UINT32_CODE

let UINT32_CODE : Int

bytes_equal

fn bytes_equal(a : Bytes, b : Bytes) -> Bool

create_array

fn create_array(arr : Array[Value]) -> Value

create_binary

fn create_binary(b : Bytes) -> Value

create_bool

fn create_bool(b : Bool) -> Value

create_bytes

fn create_bytes(values : Array[Int]) -> Bytes

create_float

fn create_float(f : Double) -> Value

create_int

fn create_int(i : Int) -> Value

create_int64

fn create_int64(i : Int64) -> Value

create_map

fn create_map(map : Map[String, Value]) -> Value

create_nil

fn create_nil() -> Value

create_string

fn create_string(s : String) -> Value

create_uint64

fn create_uint64(u : UInt64) -> Value

decode

fn decode(data : Bytes) -> Result[Value, MsgPackError]

encode

fn encode(value : Value) -> Bytes