Skip to content

Commit 91ef124

Browse files
authored
Merge pull request #293 from YuanYuYuan/feat/ros2-action-hash
feat: ros2 action hash support
2 parents 33fbcd0 + 3851ad3 commit 91ef124

File tree

1 file changed

+76
-1
lines changed

1 file changed

+76
-1
lines changed

roslibrust_codegen/src/lib.rs

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use std::{
1212
collections::{BTreeMap, BTreeSet, VecDeque},
1313
fmt::{Debug, Display},
14-
path::PathBuf,
14+
path::{Path, PathBuf},
1515
};
1616

1717
use log::*;
@@ -55,6 +55,14 @@ impl Ros2Hash {
5555
pub fn to_hash_string(&self) -> String {
5656
format!("RIHS01_{}", hex::encode(self.0))
5757
}
58+
59+
pub fn from_string(hash_str: &str) -> Self {
60+
// Remove "RIHS01_" prefix if present
61+
let hex_str = hash_str.trim_start_matches("RIHS01_");
62+
let mut bytes = [0u8; 32];
63+
hex::decode_to_slice(hex_str, &mut bytes).expect("Invalid hex string");
64+
Ros2Hash(bytes)
65+
}
5866
}
5967

6068
// Conversion from Ros2Hash to TokenStream for use in generated code
@@ -341,6 +349,53 @@ impl ServiceFile {
341349
}
342350
}
343351

352+
/// Resolved action file with type hashes for ROS 2 action service wrappers
353+
pub struct ActionWithHashes {
354+
pub parsed: ParsedActionFile,
355+
pub send_goal_hash: Ros2Hash,
356+
pub get_result_hash: Ros2Hash,
357+
pub feedback_message_hash: Ros2Hash,
358+
}
359+
360+
impl ActionWithHashes {
361+
/// Creates an ActionWithHashes with type hashes loaded from ROS 2 JSON metadata
362+
pub fn from_json_metadata(parsed: ParsedActionFile, json_path: &Path) -> Option<Self> {
363+
use std::fs;
364+
365+
let json_content = fs::read_to_string(json_path).ok()?;
366+
let json: serde_json::Value = serde_json::from_str(&json_content).ok()?;
367+
368+
let type_hashes = json.get("type_hashes")?.as_array()?;
369+
370+
// Helper to find hash by suffix
371+
let find_hash = |suffix: &str| -> Option<Ros2Hash> {
372+
type_hashes.iter().find_map(|type_hash| {
373+
let type_name = type_hash.get("type_name")?.as_str()?;
374+
let hash_string = type_hash.get("hash_string")?.as_str()?;
375+
376+
type_name
377+
.ends_with(suffix)
378+
.then(|| Ros2Hash::from_string(hash_string))
379+
})
380+
};
381+
382+
Some(ActionWithHashes {
383+
parsed,
384+
send_goal_hash: find_hash("_SendGoal")?,
385+
get_result_hash: find_hash("_GetResult")?,
386+
feedback_message_hash: find_hash("_FeedbackMessage")?,
387+
})
388+
}
389+
390+
pub fn get_package_name(&self) -> String {
391+
self.parsed.package.clone()
392+
}
393+
394+
pub fn get_short_name(&self) -> String {
395+
self.parsed.name.clone()
396+
}
397+
}
398+
344399
/// Stores the ROS string representation of a literal
345400
#[derive(Clone, Debug)]
346401
pub struct RosLiteral {
@@ -836,6 +891,26 @@ pub(crate) fn parse_ros_files(
836891
Ok((parsed_messages, parsed_services, parsed_actions))
837892
}
838893

894+
/// Resolves parsed actions into ActionWithHashes with type hashes from JSON metadata
895+
pub fn resolve_action_hashes(parsed_actions: Vec<ParsedActionFile>) -> Vec<ActionWithHashes> {
896+
parsed_actions
897+
.into_iter()
898+
.filter_map(|parsed_action| {
899+
// The JSON file should be in the same directory as the .action file
900+
let json_path = parsed_action.path.with_extension("json");
901+
902+
ActionWithHashes::from_json_metadata(parsed_action.clone(), &json_path).or_else(|| {
903+
log::warn!(
904+
"Failed to resolve action hashes for {}/{}",
905+
parsed_action.package,
906+
parsed_action.name
907+
);
908+
None
909+
})
910+
})
911+
.collect()
912+
}
913+
839914
#[cfg(test)]
840915
mod test {
841916
use crate::find_and_generate_ros_messages;

0 commit comments

Comments
 (0)