implement computing message layout
This commit is contained in:
parent
50fa2b43e3
commit
b207c98df7
22
src/bag.rs
22
src/bag.rs
@ -1,9 +1,9 @@
|
|||||||
use std::{fs::File, path::Path};
|
use std::{fs::File, path::Path};
|
||||||
|
|
||||||
use eyre::Context;
|
use eyre::Context;
|
||||||
use log::{error, trace};
|
use log::debug;
|
||||||
|
|
||||||
use crate::{Result, index::BagIndex, info::BagInfo, message::parse_msgs, reader::MmapReader};
|
use crate::{index::BagIndex, info::BagInfo, message::compute_layout, reader::MmapReader, Result};
|
||||||
|
|
||||||
pub struct Bag {
|
pub struct Bag {
|
||||||
reader: MmapReader,
|
reader: MmapReader,
|
||||||
@ -20,21 +20,8 @@ impl Bag {
|
|||||||
|
|
||||||
pub fn compute_message_layouts(&mut self) -> Result<()> {
|
pub fn compute_message_layouts(&mut self) -> Result<()> {
|
||||||
for conn in &self.index.connections {
|
for conn in &self.index.connections {
|
||||||
match parse_msgs(conn) {
|
let layout = compute_layout(conn)?;
|
||||||
Ok(msgs) => {
|
debug!("message layout: {:#?}", layout);
|
||||||
for msg in &msgs {
|
|
||||||
trace!(
|
|
||||||
"message definition parsed: {:#?}",
|
|
||||||
msg.fields()
|
|
||||||
.iter()
|
|
||||||
.filter(|field| !field.is_constant())
|
|
||||||
.map(ToString::to_string)
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => error!("could not parse message definition: {}", err),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -43,4 +30,3 @@ impl Bag {
|
|||||||
BagInfo::compute(&mut self.reader, &self.index)
|
BagInfo::compute(&mut self.reader, &self.index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
136
src/layout.rs
136
src/layout.rs
@ -1,6 +1,39 @@
|
|||||||
use ros_message::I8Variant;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::SmallStr;
|
use eyre::{bail, eyre};
|
||||||
|
use ros_message::{DataType, FieldCase, FieldInfo, I8Variant, MessagePath, Msg, U8Variant};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::{Result, SmallStr};
|
||||||
|
|
||||||
|
type Dependencies = HashMap<MessagePath, MessageLayoutRef>;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Error)]
|
||||||
|
#[error("missing dependent message definition: {0}")]
|
||||||
|
pub struct MissingDependency(MessagePath);
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Error)]
|
||||||
|
#[error("dependency cycle involving: {0:?}")]
|
||||||
|
pub struct DependencyCycle(Vec<String>);
|
||||||
|
|
||||||
|
struct Resolver<'a> {
|
||||||
|
dependencies: &'a HashMap<MessagePath, MessageLayoutRef>,
|
||||||
|
current_path: &'a MessagePath,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Resolver<'a> {
|
||||||
|
fn get_dep(&self, path: &MessagePath) -> Result<MessageLayoutRef> {
|
||||||
|
self.dependencies
|
||||||
|
.get(path)
|
||||||
|
.cloned()
|
||||||
|
.ok_or_else(|| eyre!(MissingDependency(path.clone())))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_local_dep(&self, name: &str) -> Result<MessageLayoutRef> {
|
||||||
|
let full_path = self.current_path.peer(name);
|
||||||
|
self.get_dep(&full_path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum FieldType {
|
pub enum FieldType {
|
||||||
@ -15,7 +48,7 @@ pub enum FieldType {
|
|||||||
/// Represents `int64`.
|
/// Represents `int64`.
|
||||||
I64,
|
I64,
|
||||||
/// Represents `uint8` or `char`.
|
/// Represents `uint8` or `char`.
|
||||||
U8(I8Variant),
|
U8(U8Variant),
|
||||||
/// Represents `uint16`.
|
/// Represents `uint16`.
|
||||||
U16,
|
U16,
|
||||||
/// Represents `uint32`.
|
/// Represents `uint32`.
|
||||||
@ -36,6 +69,29 @@ pub enum FieldType {
|
|||||||
Message(MessageLayoutRef),
|
Message(MessageLayoutRef),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FieldType {
|
||||||
|
fn from_datatype_and_resolver(datatype: &DataType, resolver: &Resolver) -> Result<Self> {
|
||||||
|
Ok(match datatype {
|
||||||
|
DataType::Bool => FieldType::Bool,
|
||||||
|
DataType::I8(v) => FieldType::I8(v.clone()),
|
||||||
|
DataType::I16 => FieldType::I16,
|
||||||
|
DataType::I32 => FieldType::I32,
|
||||||
|
DataType::I64 => FieldType::I64,
|
||||||
|
DataType::U8(v) => FieldType::U8(v.clone()),
|
||||||
|
DataType::U16 => FieldType::U16,
|
||||||
|
DataType::U32 => FieldType::U32,
|
||||||
|
DataType::U64 => FieldType::U64,
|
||||||
|
DataType::F32 => FieldType::F32,
|
||||||
|
DataType::F64 => FieldType::F64,
|
||||||
|
DataType::String => FieldType::String,
|
||||||
|
DataType::Time => FieldType::Time,
|
||||||
|
DataType::Duration => FieldType::Duration,
|
||||||
|
DataType::LocalMessage(path) => FieldType::Message(resolver.get_local_dep(path)?),
|
||||||
|
DataType::GlobalMessage(path) => FieldType::Message(resolver.get_dep(path)?),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct FieldLayout {
|
pub struct FieldLayout {
|
||||||
pub typ: FieldType,
|
pub typ: FieldType,
|
||||||
@ -43,6 +99,21 @@ pub struct FieldLayout {
|
|||||||
pub multiplicity: Multiplicity,
|
pub multiplicity: Multiplicity,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FieldLayout {
|
||||||
|
fn from_info_and_resolver(info: &FieldInfo, resolver: &Resolver) -> Result<Self> {
|
||||||
|
Ok(Self {
|
||||||
|
typ: FieldType::from_datatype_and_resolver(info.datatype(), resolver)?,
|
||||||
|
name: info.name().into(),
|
||||||
|
multiplicity: match info.case() {
|
||||||
|
FieldCase::Unit => Multiplicity::Unit,
|
||||||
|
FieldCase::Vector => Multiplicity::Dynamic,
|
||||||
|
FieldCase::Array(n) => Multiplicity::Fixed(*n),
|
||||||
|
FieldCase::Const(_) => unreachable!(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Multiplicity {
|
pub enum Multiplicity {
|
||||||
Unit,
|
Unit,
|
||||||
@ -56,3 +127,62 @@ pub struct MessageLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub type MessageLayoutRef = std::sync::Arc<MessageLayout>;
|
pub type MessageLayoutRef = std::sync::Arc<MessageLayout>;
|
||||||
|
|
||||||
|
impl MessageLayout {
|
||||||
|
pub fn from_msgs<'a, M, I>(msgs: M) -> Result<MessageLayout>
|
||||||
|
where
|
||||||
|
M: IntoIterator<IntoIter = I>,
|
||||||
|
I: Iterator<Item = &'a Msg> + DoubleEndedIterator,
|
||||||
|
{
|
||||||
|
let mut dependencies: Dependencies = Default::default();
|
||||||
|
let mut msgs = msgs.into_iter();
|
||||||
|
let main = msgs
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| eyre!("at least one msg required"))?;
|
||||||
|
|
||||||
|
let mut deps: Vec<_> = msgs.collect();
|
||||||
|
|
||||||
|
while !deps.is_empty() {
|
||||||
|
let mut remaining = Vec::new();
|
||||||
|
let orig_length = deps.len();
|
||||||
|
for msg in deps.drain(..) {
|
||||||
|
let layout = match MessageLayout::from_msg_and_deps(msg, &dependencies) {
|
||||||
|
Ok(layout) => layout,
|
||||||
|
Err(err) => {
|
||||||
|
if err.root_cause().is::<MissingDependency>() {
|
||||||
|
// Has a missing dependency, resovle it on the next iteration
|
||||||
|
remaining.push(msg);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
dependencies.insert(msg.path().clone(), MessageLayoutRef::from(layout));
|
||||||
|
}
|
||||||
|
if remaining.len() == orig_length {
|
||||||
|
// Made no progress, there is a dependency cycle
|
||||||
|
bail!(DependencyCycle(
|
||||||
|
remaining.iter().map(|msg| msg.path().to_string()).collect()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
deps = remaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageLayout::from_msg_and_deps(main, &dependencies)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_msg_and_deps(msg: &Msg, dependencies: &Dependencies) -> Result<MessageLayout> {
|
||||||
|
let resolver = Resolver {
|
||||||
|
dependencies,
|
||||||
|
current_path: msg.path(),
|
||||||
|
};
|
||||||
|
let fields = msg
|
||||||
|
.fields()
|
||||||
|
.iter()
|
||||||
|
.filter(|field| !field.is_constant())
|
||||||
|
.map(|field| FieldLayout::from_info_and_resolver(field, &resolver))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
Ok(MessageLayout { fields })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,10 +5,10 @@ use log::trace;
|
|||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use ros_message::{MessagePath, Msg};
|
use ros_message::{MessagePath, Msg};
|
||||||
|
|
||||||
use crate::{index::ConnInfo, Result};
|
use crate::{index::ConnInfo, layout::MessageLayout, Result};
|
||||||
|
|
||||||
fn parse_msg(message_name: &str, msgdef: &str) -> Result<Msg> {
|
fn parse_msg(message_name: &str, msgdef: &str) -> Result<Msg> {
|
||||||
trace!("message definition: {}", msgdef);
|
trace!("message definition {}: {}", message_name, msgdef);
|
||||||
let path = MessagePath::try_from(message_name)?;
|
let path = MessagePath::try_from(message_name)?;
|
||||||
let msgtype = Msg::new(path, msgdef)?;
|
let msgtype = Msg::new(path, msgdef)?;
|
||||||
Ok(msgtype)
|
Ok(msgtype)
|
||||||
@ -18,7 +18,7 @@ lazy_static! {
|
|||||||
static ref BOUNDARY_RE: Regex = Regex::new(r"\r?\n==+\r?\nMSG: ([^\r\n]+)\r?\n").unwrap();
|
static ref BOUNDARY_RE: Regex = Regex::new(r"\r?\n==+\r?\nMSG: ([^\r\n]+)\r?\n").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_msgs(conn: &ConnInfo) -> Result<Vec<Msg>> {
|
fn parse_msgs(conn: &ConnInfo) -> Result<Vec<Msg>> {
|
||||||
let msgdefs = &conn.message_definition;
|
let msgdefs = &conn.message_definition;
|
||||||
let mut name = conn.datatype.clone();
|
let mut name = conn.datatype.clone();
|
||||||
let mut begin = 0usize;
|
let mut begin = 0usize;
|
||||||
@ -43,3 +43,8 @@ pub fn parse_msgs(conn: &ConnInfo) -> Result<Vec<Msg>> {
|
|||||||
|
|
||||||
Ok(msgs)
|
Ok(msgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn compute_layout(conn: &ConnInfo) -> Result<MessageLayout> {
|
||||||
|
let msgs = parse_msgs(conn)?;
|
||||||
|
MessageLayout::from_msgs(&msgs)
|
||||||
|
}
|
||||||
|
@ -13,4 +13,4 @@ pub type IResult<'a, T> = nom::IResult<Input<'a>, T, Error<Input<'a>>>;
|
|||||||
pub type InputStr<'a> = &'a str;
|
pub type InputStr<'a> = &'a str;
|
||||||
pub type IResultStr<'a, T> = nom::IResult<InputStr<'a>, T, Error<InputStr<'a>>>;
|
pub type IResultStr<'a, T> = nom::IResult<InputStr<'a>, T, Error<InputStr<'a>>>;
|
||||||
|
|
||||||
pub type SmallStr = String;
|
pub type SmallStr = crate::SmallStr;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user