Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion generator/sbpg/targets/resources/sbp_messages_mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use self::unknown::Unknown;
use serde::{Serialize, Deserialize};
use crate::serialize::SbpSerialize;
use crate::framer::FramerError;
use crate::parser::SbpParse;

pub trait SBPMessage: SbpSerialize {
fn get_message_type(&self) -> u16;
Expand All @@ -48,7 +49,7 @@ impl SBP {
let x: Result<SBP, crate::Error> = match msg_id {
((*- for m in msgs *))
(((m.sbp_id))) => {
let mut msg = (((m.identifier|camel_case)))::parse(payload)?;
let mut msg: (((m.identifier|camel_case))) = payload.parse()?;
msg.set_sender_id(sender_id);
Ok(SBP::(((m.identifier|camel_case)))(msg))
},
Expand Down
29 changes: 4 additions & 25 deletions generator/sbpg/targets/resources/sbp_messages_template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,11 @@

//! (((description | replace("\n", "\n//! "))))

extern crate byteorder;
#[allow(unused_imports)]
use self::byteorder::{LittleEndian,ReadBytesExt};
#[cfg(feature = "sbp_serde")]
use serde::{Serialize, Deserialize};

#[allow(unused_imports)]
use crate::SbpString;
use crate::{parser::SbpParse, UnboundedSbpString, BoundedSbpString};

((*- for i in includes *))
use super::(((i)))::*;
Expand Down Expand Up @@ -50,36 +47,18 @@ pub struct (((m.identifier|camel_case))) {
((*- endfor *))
}

impl (((m.identifier|camel_case))) {
impl SbpParse<(((m.identifier|camel_case)))> for &[u8] {
#[rustfmt::skip]
pub fn parse(_buf: &mut &[u8]) -> Result<(((m.identifier|camel_case))), crate::Error> {
fn parse(&mut self) -> crate::Result<(((m.identifier|camel_case)))> {
Ok( (((m.identifier|camel_case))){
((*- if m.is_real_message *))
sender_id: None,
((*- endif *))
((*- for f in m.fields *))
(((f.identifier))): (((f|parse_type)))?,
(((f.identifier))): self.parse()?,
((*- endfor *))
} )
}

((*- if not m.is_real_message *))
pub fn parse_array(buf: &mut &[u8]) -> Result<Vec<(((m.identifier|camel_case)))>, crate::Error> {
let mut v = Vec::new();
while buf.len() > 0 {
v.push( (((m.identifier|camel_case)))::parse(buf)? );
}
Ok(v)
}

pub fn parse_array_limit(buf: &mut &[u8], n: usize) -> Result<Vec<(((m.identifier|camel_case)))>, crate::Error> {
let mut v = Vec::new();
for _ in 0..n {
v.push( (((m.identifier|camel_case)))::parse(buf)? );
}
Ok(v)
}
((*- endif *))
}

((*- if m.is_real_message *))
Expand Down
17 changes: 12 additions & 5 deletions generator/sbpg/targets/rust.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,22 @@ def commentify(value):
's32': 'i32',
's64': 'i64',
'float': 'f32',
'double': 'f64',
'string': 'SbpString'}
'double': 'f64'}

def type_map(field):
if field.type_id in TYPE_MAP:
return TYPE_MAP[field.type_id]
elif field.type_id == 'array':
t = field.options['fill'].value
return "Vec<{}>".format(TYPE_MAP.get(t, t))
if field.options.get('size', None):
return "[{}; {}]".format(TYPE_MAP.get(t,t), field.options.get('size').value)
else:
return "Vec<{}>".format(TYPE_MAP.get(t, t))
elif field.type_id == 'string':
if field.options.get('size', None):
return "BoundedSbpString<{}>".format(field.options.get('size').value)
else:
return "UnboundedSbpString"
else:
return field.type_id

Expand Down Expand Up @@ -88,12 +95,12 @@ def parse_type(field):
t = field.options['fill'].value
if t in TYPE_MAP.keys():
if 'size' in field.options:
return 'crate::parser::read_%s_array_limit(_buf, %d)' % (t, field.options['size'].value)
return 'crate::parser::read_%s_array_fixed(_buf)' % t
else:
return 'crate::parser::read_%s_array(_buf)' % t
else:
if 'size' in field.options:
return '%s::parse_array_limit(_buf, %d)' % (t, field.options['size'].value)
return '%s::parse_array_fixed(_buf)' % t
else:
return '%s::parse_array(_buf)' % t
else:
Expand Down
151 changes: 121 additions & 30 deletions rust/sbp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub mod serialize;
#[cfg(feature = "sbp2json")]
pub mod sbp2json;

use std::convert::{From, Into};
use std::convert::{From, Into, TryFrom};
use std::error;
use std::fmt;
use std::result;
Expand All @@ -22,66 +22,157 @@ pub type Result<T> = result::Result<T, Error>;

pub const SBP_MAX_PAYLOAD_SIZE: usize = 255;

pub trait SbpString {
fn as_bytes(&self) -> &[u8];
fn to_string(&self) -> String;
}

#[derive(Debug, Clone)]
pub struct SbpString(Vec<u8>);
pub struct UnboundedSbpString(Vec<u8>);

impl SbpString {
pub fn as_bytes(&self) -> &[u8] {
impl SbpString for UnboundedSbpString {
fn as_bytes(&self) -> &[u8] {
&self.0
}
pub fn to_string(&self) -> String {
fn to_string(&self) -> String {
String::from_utf8_lossy(&self.0).into()
}
}

impl fmt::Display for UnboundedSbpString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "SbpString({})", SbpString::to_string(self))
}
}

#[cfg(feature = "sbp_serde")]
impl<'de> Deserialize<'de> for UnboundedSbpString {
fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Deserialize::deserialize(deserializer).map(|s: String| UnboundedSbpString::from(s))
}
}

#[cfg(feature = "sbp_serde")]
impl Serialize for SbpString {
impl Serialize for UnboundedSbpString {
fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
where
S: Serializer,
{
let s: String = self.clone().into();
let s = SbpString::to_string(self);
serializer.serialize_str(&s)
}
}

impl From<UnboundedSbpString> for String {
fn from(s: UnboundedSbpString) -> String {
SbpString::to_string(&s)
}
}

impl From<UnboundedSbpString> for Vec<u8> {
fn from(s: UnboundedSbpString) -> Vec<u8> {
s.0
}
}

impl From<String> for UnboundedSbpString {
fn from(s: String) -> UnboundedSbpString {
UnboundedSbpString(s.into_bytes())
}
}

impl TryFrom<&mut &[u8]> for UnboundedSbpString {
type Error = Error;
fn try_from(buf: &mut &[u8]) -> Result<UnboundedSbpString> {
let amount = buf.len();
let (head, tail) = buf.split_at(amount);
*buf = tail;
Ok(UnboundedSbpString(head.to_vec()))
}
}

#[derive(Debug, Clone)]
pub struct BoundedSbpString<const SIZE: usize>([u8; SIZE]);
Comment on lines +97 to +98
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only intentional change in functionality, when the SBP message specifies a fixed length string we store the entire string instead of up to the maximum length.


impl<const SIZE: usize> SbpString for BoundedSbpString<SIZE> {
fn as_bytes(&self) -> &[u8] {
&self.0
}
fn to_string(&self) -> String {
String::from_utf8_lossy(&self.0).into()
}
}

impl<const SIZE: usize> Default for BoundedSbpString<SIZE> {
fn default() -> BoundedSbpString<SIZE> {
BoundedSbpString([0; SIZE])
}
}

impl<const SIZE: usize> fmt::Display for BoundedSbpString<SIZE> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "SbpString({})", SbpString::to_string(self))
}
}

#[cfg(feature = "sbp_serde")]
impl<'de> Deserialize<'de> for SbpString {
impl<'de, const SIZE: usize> Deserialize<'de> for BoundedSbpString<SIZE> {
fn deserialize<D>(deserializer: D) -> result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Deserialize::deserialize(deserializer).map(|s: String| SbpString::from(s))
Deserialize::deserialize(deserializer).map(|s: String| BoundedSbpString::<SIZE>::from(s))
}
}

impl From<String> for SbpString {
fn from(s: String) -> SbpString {
SbpString(s.as_bytes().to_vec())
#[cfg(feature = "sbp_serde")]
impl<const SIZE: usize> Serialize for BoundedSbpString<SIZE> {
fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = SbpString::to_string(self);
serializer.serialize_str(&s)
}
}

impl Into<String> for SbpString {
fn into(self) -> String {
self.to_string()
impl<const SIZE: usize> From<BoundedSbpString<SIZE>> for String {
fn from(s: BoundedSbpString<SIZE>) -> String {
SbpString::to_string(&s)
}
}

impl Into<String> for &SbpString {
fn into(self) -> String {
self.to_string()
impl<const SIZE: usize> From<BoundedSbpString<SIZE>> for Vec<u8> {
fn from(s: BoundedSbpString<SIZE>) -> Vec<u8> {
s.0.into()
}
}

impl Into<Vec<u8>> for SbpString {
fn into(self) -> Vec<u8> {
self.0
impl<const SIZE: usize> From<String> for BoundedSbpString<SIZE> {
fn from(s: String) -> BoundedSbpString<SIZE> {
let len = std::cmp::min(SIZE, s.len());
let s = &s[..len];

let mut result = BoundedSbpString::<SIZE>::default();
result.0[..len].copy_from_slice(s.as_bytes());
result
}
}

impl fmt::Display for SbpString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "SbpString({})", Into::<String>::into(self.clone()))
impl<const SIZE: usize> TryFrom<&mut &[u8]> for BoundedSbpString<SIZE> {
type Error = Error;
fn try_from(buf: &mut &[u8]) -> Result<BoundedSbpString<SIZE>> {
let amount = std::cmp::min(SIZE, buf.len());
let (head, tail) = buf.split_at(amount);

let mut s = BoundedSbpString::<SIZE>::default();
s.0[..amount].copy_from_slice(head);
*buf = tail;

Ok(s)
}
}

Expand Down Expand Up @@ -127,6 +218,8 @@ impl From<std::io::Error> for Error {

#[cfg(test)]
mod tests {
use crate::{SbpString, UnboundedSbpString};

#[test]
fn baseline_ecef() {
let baseline_ecef_payload = [
Expand Down Expand Up @@ -330,15 +423,13 @@ mod tests {

#[test]
fn sbp_string() {
use crate::SbpString;

let sbp_str = SbpString(b"1234".to_vec());
let s = sbp_str.to_string();
let sbp_str = UnboundedSbpString(b"1234".to_vec());
let s = SbpString::to_string(&sbp_str);

assert_eq!("1234", s);

let sbp_str = SbpString(b"1234\xFF".to_vec());
let s = sbp_str.to_string();
let sbp_str = UnboundedSbpString(b"1234\xFF".to_vec());
let s = SbpString::to_string(&sbp_str);

assert_eq!("1234\u{FFFD}", s);
}
Expand Down
Loading