| Crates.io | arrow-message |
| lib.rs | arrow-message |
| version | 0.1.6 |
| created_at | 2025-03-21 18:03:54.077894+00 |
| updated_at | 2025-04-02 12:21:23.010824+00 |
| description | arrow-message implements a way to define messages according to the Arrow format in both Rust and Python |
| homepage | |
| repository | https://github.com/Hennzau/arrow-message |
| max_upload_size | |
| id | 1600936 |
| size | 69,944 |
arrow-message makes it possible to create a Message struct in Rust or Python and convert it into a single arrow::array::ArrayData without any copy. It's also possible to get back to the initial struct without any copy as well.
The resulting arrow::array::ArrayData can then be sent safely over the network, a mpsc channel or to a Python script thanks to the pyo3 crate and the pyarrow feature.
The project aims to be used in context where we want to send a single payload containing multiple large fields. Like a struct representing an image or a video frame. This is ideal for Robotics and AI applications.
use arrow::array::*;
use arrow_message::prelude::*;
#[derive(Debug, ArrowMessage)]
enum Encoding {
RGB8,
RGBA8,
BGR8,
BGRA8,
}
#[derive(Debug, ArrowMessage)]
struct Metadata {
name: Option<String>,
width: u32,
height: u32,
encoding: Option<Encoding>,
}
#[derive(Debug, ArrowMessage)]
struct Image {
data: UInt8Array,
metadata: Option<Metadata>,
}
fn main() -> arrow::error::Result<()> {
let image = Image {
data: UInt8Array::from(vec![1, 2, 3]),
metadata: Some(Metadata {
name: Some("example".to_string()),
width: 12,
height: 12,
encoding: Some(Encoding::RGB8),
}),
};
println!("{:?}", image);
let arrow = ArrayData::try_from(image)?;
let image = Image::try_from(arrow)?;
println!("{:?}", image);
Ok(())
}
You can see an expanded version without the Derive macro here, and a more complex example here.
A python version here
from pyarrow_message import ArrowMessage
from dataclasses import dataclass
from typing import Optional
from enum import Enum
import numpy as np
class Encoding(ArrowMessage, Enum):
RGB8 = "RGB8"
RGBA8 = "RGBA8"
BGR8 = "BGR8"
BGRA8 = "BGRA8"
@dataclass
class Metadata(ArrowMessage):
name: Optional[str]
width: np.uint32
height: np.uint32
encoding: Optional[Encoding]
@dataclass
class Image(ArrowMessage):
data: np.ndarray
metadata: Optional[Metadata]
def main():
image = Image(
data=np.array([1, 2, 3], dtype=np.uint8),
metadata=Metadata(
width=np.uint32(12),
height=np.uint32(12),
name="example",
encoding=Encoding.RGB8,
),
)
print(image)
arrow = image.to_arrow()
image2 = Image.from_arrow(arrow)
print(image2)
if __name__ == "__main__":
main()
As you can see above, you can convert an ArrowMessage into an ArrayData. But it's also possible to operate on an ArrayData thanks to the trait ArrayDataFlattening to flatten an entire ArrayData in a single buffer, so it's easy to send the message through a protocol (SharedMemory, TCP etc...).
let arrow = ArrayData::try_from(image)?;
let flat = arrow.flattened()?; // Copy of the data but flattened
let image = Image::try_from(flat)?; // Always possible to convert back to Image
If you need to send the message through a protocol you can get both the Layout and the Buffer associated with the ArrayData:
let arrow = ArrayData::try_from(image)?;
let (layout, values) = arrow.layout_with_values(); // (ArrayDataLayout, Buffer)
let arrow = ArrayData::from_layout_and_values(layout, values)?;
let image = Image::try_from(arrow)?;
Note: ArrayDataLayout implements Serialize and Deserialize so you can send it over the network
In special cases you would like to write directly the values of the ArrayData into a custom buffer:
let arrow = ArrayData::try_from(image)?;
let layout = arrow.layout();
let size = arrow.required_size();
let mut target = vec![0u8; size]; // Allocate a buffer of the required size
arrow.fill(&mut target);
// ...
// Send (layout, target) and reconstruct an ArrayData
// ...
let values = arrow::buffer::Buffer::from_vec(target);
let arrow = ArrayData::from_layout_and_values(layout, values)?;
let image = Image::try_from(arrow)?;
We use a justfile to run examples:
just example-derive-enum # rust enum_derive.rs example
just example-derive-inherit # python enum_inherit.py example
Fields supported
Operations supported