Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add serde support #102

Merged
merged 15 commits into from
Jul 20, 2023
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:

matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
rust: ["1.60", stable, beta]
rust: ["1.61", stable, beta]
env:
RUSTUP_MAX_RETRIES: 10
CARGO_NET_RETRY: 10
Expand Down
23 changes: 16 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ repository = "https://github.com/AeroRust/nmea"
readme = "README.md"

edition = "2021"
rust-version = "1.60"
rust-version = "1.61"

[package.metadata.docs.rs]
all-features = true
Expand All @@ -29,25 +29,34 @@ rustdoc-args = ["--cfg", "docsrs"]
arrayvec = { version = "0.7.2", default-features = false }
chrono = { version = "0.4.19", default-features = false }
heapless = "0.7.15"
nom = { version = "7.1.1", default-features = false }
nom = { version = "7.1", default-features = false }

# we include num-traits only when `std` is not enabled
# because of `fract()` and `trunc()` methods
num-traits = { version = "0.2", default-features = false, features = ["libm"]}

cfg-if = "1"
serde = { version = "1.0", default-features = false, optional = true }
serde_with = { version = "3.0", default-features = false, optional = true }

[dev-dependencies]
approx = "0.5.1"
approx = "0.5"
doc-comment = "0.3"
pretty_assertions = "1"
quickcheck = { version = "1.0.3", default-features = false }
quickcheck = { version = "1", default-features = false }
# criterion 0.5 has clap_builder version which requires at least Rust 1.64
criterion = "0.4"

[features]
default = ["std", "all-sentences"]
std = ["nom/std", "chrono/std", "arrayvec/std"]

std = ["nom/std", "chrono/std", "arrayvec/std", "serde?/std", "serde_with?/std"]
serde = [
"serde/derive",
"serde_with/macros",
"serde_with/chrono_0_4",
"heapless/serde",
"chrono/serde",
"arrayvec/serde"
]

all-sentences = ["GNSS", "waypoint", "maritime", "water", "vendor-specific", "other"]
# GNSS specific sentences related to the possition or speed relative to the ground
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
//!
//! - `default` features - `std`
//! - `std` - enable `std`
//! - `serde` - enable `serde`
//!
//! [`Nmea::parse()`]: Nmea::parse
//! [`Nmea::parse_for_fix()`]: Nmea::parse_for_fix
Expand Down
3 changes: 3 additions & 0 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use nom::{
};

use cfg_if::cfg_if;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use crate::{sentences::*, Error, SentenceType};

Expand All @@ -35,6 +37,7 @@ pub const SENTENCE_MAX_LEN: usize = 102;
pub const TEXT_PARAMETER_MAX_LEN: usize = 64;

/// A known and parsable Nmea sentence type.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct NmeaSentence<'a> {
pub talker_id: &'a str,
pub message_id: SentenceType,
Expand Down
56 changes: 56 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
Error, ParseResult,
};

#[cfg(feature = "serde")]
use serde::{de::Visitor, ser::SerializeSeq, Deserialize, Serialize};

/// NMEA parser
///
/// This struct parses NMEA sentences, including checksum checks and sentence
Expand All @@ -31,6 +34,7 @@
/// # }

/// ```
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Default)]
pub struct Nmea {
pub fix_time: Option<NaiveTime>,
Expand Down Expand Up @@ -434,6 +438,7 @@
}
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Default)]
struct SatsPack {
/// max number of visible GNSS satellites per hemisphere, assuming global coverage
Expand All @@ -442,10 +447,59 @@
/// BeiDou: 12 + 3 IGSO + 3 GEO
/// Galileo: 12
/// => 58 total Satellites => max 15 rows of data
#[cfg_attr(feature = "serde", serde(with = "serde_deq"))]
data: Deque<Vec<Option<Satellite>, 4>, 15>,
max_len: usize,
}

#[cfg(feature = "serde")]
mod serde_deq {
use super::*;

pub fn serialize<S>(v: &Deque<Vec<Option<Satellite>, 4>, 15>, s: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut seq = s.serialize_seq(Some(15))?;
for e in v.iter() {
seq.serialize_element(e)?;

Check warning on line 465 in src/parser.rs

View check run for this annotation

Codecov / codecov/patch

src/parser.rs#L463-L465

Added lines #L463 - L465 were not covered by tests
}
seq.end()

Check warning on line 467 in src/parser.rs

View check run for this annotation

Codecov / codecov/patch

src/parser.rs#L467

Added line #L467 was not covered by tests
}

struct DequeVisitor;

impl<'de> Visitor<'de> for DequeVisitor {
type Value = Deque<Vec<Option<Satellite>, 4>, 15>;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("deque of vectors containing optional Satellite structs")

Check warning on line 476 in src/parser.rs

View check run for this annotation

Codecov / codecov/patch

src/parser.rs#L475-L476

Added lines #L475 - L476 were not covered by tests
}

fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut deq: Deque<Vec<Option<Satellite>, 4>, 15> = Deque::new();

Check warning on line 483 in src/parser.rs

View check run for this annotation

Codecov / codecov/patch

src/parser.rs#L483

Added line #L483 was not covered by tests

while let Some(v) = seq.next_element()? {
deq.push_back(v)
.map_err(|_| serde::de::Error::invalid_length(deq.capacity() + 1, &self))?;

Check warning on line 487 in src/parser.rs

View check run for this annotation

Codecov / codecov/patch

src/parser.rs#L485-L487

Added lines #L485 - L487 were not covered by tests
}

Ok(deq)

Check warning on line 490 in src/parser.rs

View check run for this annotation

Codecov / codecov/patch

src/parser.rs#L490

Added line #L490 was not covered by tests
}
}

pub fn deserialize<'de, D>(d: D) -> Result<Deque<Vec<Option<Satellite>, 4>, 15>, D::Error>
where
D: serde::Deserializer<'de>,
{
d.deserialize_seq(DequeVisitor)

Check warning on line 498 in src/parser.rs

View check run for this annotation

Codecov / codecov/patch

src/parser.rs#L498

Added line #L498 was not covered by tests
}
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, PartialEq)]
/// Satellite information
pub struct Satellite {
Expand Down Expand Up @@ -708,6 +762,7 @@
/// ### Vendor extensions
///
/// - [`SentenceType::RMZ`]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]

Check warning on line 765 in src/parser.rs

View check run for this annotation

Codecov / codecov/patch

src/parser.rs#L765

Added line #L765 was not covered by tests
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
#[allow(rustdoc::bare_urls)]
Expand Down Expand Up @@ -1191,6 +1246,7 @@
}
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]
pub struct SentenceMask {
mask: u128,
Expand Down
4 changes: 4 additions & 0 deletions src/sentences/aam.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ use nom::{
number::complete::float,
};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use crate::{parse::NmeaSentence, sentences::utils::array_string, Error, SentenceType};

/// AAM - Waypoint Arrival Alarm
Expand All @@ -30,6 +33,7 @@ use crate::{parse::NmeaSentence, sentences::utils::array_string, Error, Sentence
/// Example: $GPAAM,A,A,0.10,N,WPTNME*43
/// WPTNME is the waypoint name.
/// ```
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq)]
pub struct AamData {
pub arrival_circle_entered: Option<bool>,
Expand Down
4 changes: 4 additions & 0 deletions src/sentences/alm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ use nom::{
IResult,
};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use crate::{Error, NmeaSentence, SentenceType};

use super::utils::number;
Expand Down Expand Up @@ -44,6 +47,7 @@ use super::utils::number;
/// 16. Checksum
///
/// Fields 5 through 15 are dumped as raw hex.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AlmData {
pub total_number_of_messages: Option<u16>,
Expand Down
4 changes: 4 additions & 0 deletions src/sentences/bod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ use nom::{
sequence::preceded,
};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// BOD - Bearing - Waypoint to Waypoint
///
/// <https://gpsd.gitlab.io/gpsd/NMEA.html#_bod_bearing_waypoint_to_waypoint>
Expand All @@ -18,6 +21,7 @@ use nom::{
/// | | | | | | |
/// $--BOD,x.x,T,x.x,M,c--c,c--c*hh<CR><LF>
/// ```
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct BodData {
pub bearing_true: Option<f32>,
Expand Down
4 changes: 4 additions & 0 deletions src/sentences/bwc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ use nom::{
bytes::complete::is_not, character::complete::char, combinator::opt, number::complete::float,
};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use crate::{
parse::{NmeaSentence, TEXT_PARAMETER_MAX_LEN},
sentences::utils::{parse_hms, parse_lat_lon},
Expand All @@ -20,6 +23,7 @@ use crate::{
/// | | | | | | | | | | | | | |
/// $--BWC,hhmmss.ss,llll.ll,a,yyyyy.yy,a,x.x,T,x.x,M,x.x,N,c--c,m,*hh<CR><LF>
/// ```
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq)]
pub struct BwcData {
pub fix_time: Option<NaiveTime>,
Expand Down
4 changes: 4 additions & 0 deletions src/sentences/bww.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ use nom::{
bytes::complete::is_not, character::complete::char, combinator::opt, number::complete::float,
};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use crate::{
parse::{NmeaSentence, TEXT_PARAMETER_MAX_LEN},
Error, SentenceType,
Expand All @@ -29,6 +32,7 @@ use super::utils::array_string;
/// 6. FROM Waypoint ID
/// 7. Checksum

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq)]
pub struct BwwData {
pub true_bearing: Option<f32>,
Expand Down
4 changes: 4 additions & 0 deletions src/sentences/dbk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use nom::{
IResult,
};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use crate::{parse::NmeaSentence, Error, ParseResult, SentenceType};

/// DBK - Depth Below Keel
Expand All @@ -24,6 +27,7 @@ use crate::{parse::NmeaSentence, Error, ParseResult, SentenceType};
/// 5: Depth, Fathoms
/// 6: F = Fathoms
/// 7: Mandatory NMEA checksum
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq)]
pub struct DbkData {
pub depth_feet: Option<f64>,
Expand Down
5 changes: 5 additions & 0 deletions src/sentences/faa_mode.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use nom::{character::complete::anychar, combinator::opt, IResult};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use super::{nom_parse_failure, FixType};

/// for now let's handle only two GPS and GLONASS
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct FaaModes {
sys_state0: FaaMode,
Expand All @@ -24,6 +28,7 @@ impl From<FaaModes> for FixType {
}
}

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FaaMode {
/// A - Autonomous mode
Expand Down
4 changes: 4 additions & 0 deletions src/sentences/fix_type.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// Fix type
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum FixType {
Invalid,
Expand Down
4 changes: 4 additions & 0 deletions src/sentences/gbs.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use chrono::NaiveTime;
use nom::{character::complete::char, combinator::opt, number::complete::float, IResult};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use crate::{
parse::NmeaSentence,
sentences::utils::{number, parse_hms, parse_lat_lon},
Expand All @@ -16,6 +19,7 @@ use crate::{
/// | | | | | | | | |
/// $--GBS,hhmmss.ss,x.x,x.x,x.x,x.x,x.x,x.x,x.x*hh<CR><LF>
/// ```
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct GbsData {
pub time: Option<NaiveTime>,
Expand Down
4 changes: 4 additions & 0 deletions src/sentences/gga.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ use nom::{
IResult,
};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use crate::{
parse::NmeaSentence,
sentences::{
Expand All @@ -26,6 +29,7 @@ use crate::{
/// | | | | | | | | | | | | | | |
/// $--GGA,hhmmss.ss,ddmm.mm,a,ddmm.mm,a,x,xx,x.x,x.x,M,x.x,M,x.x,xxxx*hh<CR><LF>
/// ```
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq)]
pub struct GgaData {
pub fix_time: Option<NaiveTime>,
Expand Down
5 changes: 5 additions & 0 deletions src/sentences/gll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ use nom::{
IResult,
};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

use super::{faa_mode::parse_faa_mode, nom_parse_failure, FaaMode};
use crate::{
parse::NmeaSentence,
Expand All @@ -28,6 +31,8 @@ use crate::{
/// | | | | | | |
/// $--GLL,ddmm.mm,a,dddmm.mm,a,hhmmss.ss,a,m*hh<CR><LF>
/// ```

#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq)]
pub struct GllData {
pub latitude: Option<f64>,
Expand Down
Loading