ros_message/
srv.rs
1use crate::{Error, MessagePath, Msg, Result};
2use lazy_static::lazy_static;
3use regex::RegexBuilder;
4use serde_derive::{Deserialize, Serialize};
5use std::convert::TryFrom;
6use std::fmt;
7use std::fmt::Formatter;
8
9#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
11#[serde(into = "SrvSerde")]
12#[serde(try_from = "SrvSerde")]
13pub struct Srv {
14 path: MessagePath,
15 source: String,
16 req: Msg,
17 res: Msg,
18}
19
20impl fmt::Display for Srv {
21 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
22 self.source.fmt(f)
23 }
24}
25
26impl Srv {
27 pub fn new(path: MessagePath, source: impl Into<String>) -> Result<Srv> {
63 let source = source.into();
64 let (req, res) = Self::build_req_res(&path, &source)?;
65 Ok(Srv {
66 path,
67 source,
68 req,
69 res,
70 })
71 }
72
73 pub fn path(&self) -> &MessagePath {
75 &self.path
76 }
77
78 pub fn source(&self) -> &str {
80 &self.source
81 }
82
83 pub fn request(&self) -> &Msg {
85 &self.req
86 }
87
88 pub fn response(&self) -> &Msg {
90 &self.res
91 }
92
93 fn build_req_res(path: &MessagePath, source: &str) -> Result<(Msg, Msg)> {
94 lazy_static! {
95 static ref RE_SPLIT: regex::Regex = RegexBuilder::new("^---$")
96 .multi_line(true)
97 .build()
98 .expect("Invalid regex `^---$`");
99 }
100 let (req, res) = match RE_SPLIT.split(source).collect::<Vec<_>>().as_slice() {
101 &[req] => (req, ""),
102 &[req, res] => (req, res),
103 &[] => {
104 return Err(Error::BadMessageContent(format!(
105 "Service {} does not have any content",
106 path
107 )))
108 }
109 v => {
110 return Err(Error::BadMessageContent(format!(
111 "Service {} is split into {} parts",
112 path,
113 v.len()
114 )))
115 }
116 };
117
118 Ok((
119 Msg::new(path.peer(format!("{}Req", path.name())), req)?,
120 Msg::new(path.peer(format!("{}Res", path.name())), res)?,
121 ))
122 }
123}
124
125#[derive(Serialize, Deserialize)]
126struct SrvSerde {
127 path: MessagePath,
128 source: String,
129}
130
131impl TryFrom<SrvSerde> for Srv {
132 type Error = Error;
133
134 fn try_from(src: SrvSerde) -> Result<Self> {
135 Self::new(src.path, &src.source)
136 }
137}
138
139impl From<Srv> for SrvSerde {
140 fn from(src: Srv) -> Self {
141 Self {
142 path: src.path,
143 source: src.source,
144 }
145 }
146}