implement computing message layout
This commit is contained in:
parent
50fa2b43e3
commit
b207c98df7
30
src/bag.rs
30
src/bag.rs
@ -1,9 +1,9 @@
|
||||
use std::{fs::File, path::Path};
|
||||
|
||||
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 {
|
||||
reader: MmapReader,
|
||||
@ -20,27 +20,13 @@ impl Bag {
|
||||
|
||||
pub fn compute_message_layouts(&mut self) -> Result<()> {
|
||||
for conn in &self.index.connections {
|
||||
match parse_msgs(conn) {
|
||||
Ok(msgs) => {
|
||||
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),
|
||||
}
|
||||
let layout = compute_layout(conn)?;
|
||||
debug!("message layout: {:#?}", layout);
|
||||
}
|
||||
Ok(())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compute_info(&mut self) -> Result<BagInfo> {
|
||||
BagInfo::compute(&mut self.reader, &self.index)
|
||||
}
|
||||
pub fn compute_info(&mut self) -> Result<BagInfo> {
|
||||
BagInfo::compute(&mut self.reader, &self.index)
|
||||
}
|
||||
}
|
||||
|
||||
|
142
src/layout.rs
142
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)]
|
||||
pub enum FieldType {
|
||||
@ -15,7 +48,7 @@ pub enum FieldType {
|
||||
/// Represents `int64`.
|
||||
I64,
|
||||
/// Represents `uint8` or `char`.
|
||||
U8(I8Variant),
|
||||
U8(U8Variant),
|
||||
/// Represents `uint16`.
|
||||
U16,
|
||||
/// Represents `uint32`.
|
||||
@ -36,6 +69,29 @@ pub enum FieldType {
|
||||
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)]
|
||||
pub struct FieldLayout {
|
||||
pub typ: FieldType,
|
||||
@ -43,11 +99,26 @@ pub struct FieldLayout {
|
||||
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)]
|
||||
pub enum Multiplicity {
|
||||
Unit,
|
||||
Fixed(usize),
|
||||
Dynamic,
|
||||
Unit,
|
||||
Fixed(usize),
|
||||
Dynamic,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -56,3 +127,62 @@ pub struct 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 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> {
|
||||
trace!("message definition: {}", msgdef);
|
||||
trace!("message definition {}: {}", message_name, msgdef);
|
||||
let path = MessagePath::try_from(message_name)?;
|
||||
let msgtype = Msg::new(path, msgdef)?;
|
||||
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();
|
||||
}
|
||||
|
||||
pub fn parse_msgs(conn: &ConnInfo) -> Result<Vec<Msg>> {
|
||||
fn parse_msgs(conn: &ConnInfo) -> Result<Vec<Msg>> {
|
||||
let msgdefs = &conn.message_definition;
|
||||
let mut name = conn.datatype.clone();
|
||||
let mut begin = 0usize;
|
||||
@ -43,3 +43,8 @@ pub fn parse_msgs(conn: &ConnInfo) -> Result<Vec<Msg>> {
|
||||
|
||||
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 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