Rust Tuple Struct for Positional JSON Arrays
Use a tuple struct when JSON encodes a fixed-length, heterogeneous array of values like coordinates or RGB triples.
Detailed Explanation
Tuple Structs for Positional JSON Arrays
Some JSON APIs encode small fixed-shape values as positional arrays instead of objects. Latitude/longitude pairs, RGB triples, and matrix rows are common examples. Rust's tuple struct is the perfect fit.
Example JSON
{
"color": [255, 128, 0],
"location": [40.7128, -74.0060]
}
Auto-generated output (before refactor)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Root {
pub color: Vec<i32>,
pub location: Vec<f64>,
}
Promoted to tuple structs
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Color(pub u8, pub u8, pub u8);
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Location(pub f64, pub f64);
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Root {
pub color: Color,
pub location: Location,
}
Why bother
A Vec<i32> of length 3 is conceptually different from a coordinate. The tuple struct gives the compiler enough information to reject Color(255, 128) (only two channels) and provides natural color.0, color.1, color.2 accessors.
Plain tuples vs tuple structs
Plain tuples ((u8, u8, u8)) also serialize as arrays via serde, but they cannot have methods or be exported as a named type. Use a tuple struct when the value has any domain meaning — colors, points, audio samples — and a plain tuple only for throwaway anonymous pairs.
Fixed-size arrays
For very performance-sensitive code, [u8; 3] (an array, not a Vec) skips the heap allocation entirely. Serde supports it, and the size mismatch is a compile error rather than a runtime panic.
Use Case
Geometry, computer graphics, signal processing, and any scientific dataset that uses positional encoding benefits from tuple structs. They are smaller, faster, and more self-documenting than Vec<T>.