use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TypeDescriptionMsg {
pub type_description: TypeDescription,
pub referenced_type_descriptions: Vec<TypeDescription>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TypeDescription {
pub type_name: String,
pub fields: Vec<FieldDescription>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FieldDescription {
pub name: String,
#[serde(rename = "type")]
pub field_type: FieldTypeDescription,
#[serde(default)]
pub default_value: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct FieldTypeDescription {
pub type_id: u8,
pub capacity: u64,
pub string_capacity: u64,
pub nested_type_name: String,
}
impl FieldTypeDescription {
pub fn primitive(type_id: u8) -> Self {
Self {
type_id,
capacity: 0,
string_capacity: 0,
nested_type_name: String::new(),
}
}
pub fn nested(type_id: u8, nested_type_name: impl Into<String>) -> Self {
Self {
type_id,
capacity: 0,
string_capacity: 0,
nested_type_name: nested_type_name.into(),
}
}
pub fn array(type_id: u8, capacity: u64) -> Self {
Self {
type_id,
capacity,
string_capacity: 0,
nested_type_name: String::new(),
}
}
pub fn nested_array(type_id: u8, capacity: u64, nested_type_name: impl Into<String>) -> Self {
Self {
type_id,
capacity,
string_capacity: 0,
nested_type_name: nested_type_name.into(),
}
}
}
#[derive(Serialize)]
pub struct FieldDescriptionForHash<'a> {
pub name: &'a str,
#[serde(rename = "type")]
pub field_type: &'a FieldTypeDescription,
}
#[derive(Serialize)]
pub struct TypeDescriptionForHash<'a> {
pub type_name: &'a str,
pub fields: Vec<FieldDescriptionForHash<'a>>,
}
#[derive(Serialize)]
pub struct TypeDescriptionMsgForHash<'a> {
pub type_description: TypeDescriptionForHash<'a>,
pub referenced_type_descriptions: Vec<TypeDescriptionForHash<'a>>,
}
pub fn to_hash_version(msg: &TypeDescriptionMsg) -> TypeDescriptionMsgForHash<'_> {
TypeDescriptionMsgForHash {
type_description: TypeDescriptionForHash {
type_name: &msg.type_description.type_name,
fields: msg
.type_description
.fields
.iter()
.map(|f| FieldDescriptionForHash {
name: &f.name,
field_type: &f.field_type,
})
.collect(),
},
referenced_type_descriptions: msg
.referenced_type_descriptions
.iter()
.map(|td| TypeDescriptionForHash {
type_name: &td.type_name,
fields: td
.fields
.iter()
.map(|f| FieldDescriptionForHash {
name: &f.name,
field_type: &f.field_type,
})
.collect(),
})
.collect(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_type_description_serialization() {
let td = TypeDescription {
type_name: "std_msgs/msg/String".to_string(),
fields: vec![FieldDescription {
name: "data".to_string(),
field_type: FieldTypeDescription::primitive(17), default_value: String::new(),
}],
};
let json = serde_json::to_string(&td).unwrap();
assert!(json.contains("std_msgs/msg/String"));
assert!(json.contains("data"));
}
#[test]
fn test_field_type_description_builders() {
let prim = FieldTypeDescription::primitive(6); assert_eq!(prim.type_id, 6);
assert_eq!(prim.capacity, 0);
assert!(prim.nested_type_name.is_empty());
let nested = FieldTypeDescription::nested(1, "geometry_msgs/msg/Point");
assert_eq!(nested.type_id, 1);
assert_eq!(nested.nested_type_name, "geometry_msgs/msg/Point");
let arr = FieldTypeDescription::array(54, 10); assert_eq!(arr.type_id, 54);
assert_eq!(arr.capacity, 10);
}
}