diff --git a/src/bin/aisparser.rs b/src/bin/aisparser.rs index 614df94..f50bead 100644 --- a/src/bin/aisparser.rs +++ b/src/bin/aisparser.rs @@ -1,35 +1,43 @@ use ais::lib; +use ais::sentence::{AisFragments, AisParser, AisSentence}; +use lib::std::io::{self, BufRead}; +use serde_json; -use ais::sentence::{AisFragments, AisParser}; -use lib::std::io::BufRead; -use lib::std::io; - -fn parse_nmea_line(parser: &mut AisParser, line: &[u8]) -> Result<(), ais::errors::Error> { +fn parse_nmea_line_to_json(parser: &mut AisParser, line: &[u8]) -> Result<(), ais::errors::Error> { let sentence = parser.parse(line, true)?; if let AisFragments::Complete(sentence) = sentence { - println!( - "{:?}\t{:?}", - lib::std::str::from_utf8(line).unwrap(), - sentence.message - ); + match serialize_to_json(&sentence) { + Ok(json) => println!("{}", json), + Err(err) => eprintln!("Error serializing to JSON: {}", err), + } } Ok(()) } +pub fn serialize_to_json(sentence: &AisSentence) -> serde_json::Result { + serde_json::to_string(sentence) +} + +pub fn deserialize_from_json(json_data: &str) -> serde_json::Result { + serde_json::from_str(json_data) +} + fn main() { let mut parser = AisParser::new(); let stdin = io::stdin(); - { - let handle = stdin.lock(); + let handle = stdin.lock(); - handle - .split(b'\n') - .map(|line| line.unwrap()) - .for_each(|line| { - parse_nmea_line(&mut parser, &line).unwrap_or_else(|err| { - eprintln!("{:?}\t{:?}", lib::std::str::from_utf8(&line).unwrap(), err); - }); + handle + .split(b'\n') + .map(|line| line.unwrap()) + .for_each(|line| { + parse_nmea_line_to_json(&mut parser, &line).unwrap_or_else(|err| { + eprintln!( + "Error parsing line: {:?}\t{:?}", + lib::std::str::from_utf8(&line).unwrap(), + err + ); }); - } + }); } diff --git a/src/lib.rs b/src/lib.rs index 1f6e576..9346fe2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,39 +1,44 @@ -//! AIS parsing library, for reading AIS NMEA sentences +//! AIS parsing library for reading AIS NMEA sentences, with support for JSON serialization. //! -//! Given an NMEA stream, this library can extract various AIS message types in more detail. +//! This library parses NMEA AIS (Automatic Identification System) sentences and provides +//! structured representations of the data, allowing further processing or analysis. +//! +//! # Features +//! - Parses AIS NMEA sentences into structured types. +//! - Supports JSON serialization and deserialization for `AisSentence` objects. //! -//! # Example: +//! # Example //! ``` -//! use ais::{AisFragments, AisParser}; +//! use ais::{AisFragments, AisParser, serialize_to_json, deserialize_from_json}; //! use ais::messages::AisMessage; //! -//! // The line below is an NMEA sentence, much as you'd see coming out of an AIS decoder. //! let line = b"!AIVDM,1,1,,B,E>kb9O9aS@7PUh10dh19@;0Tah2cWrfP:l?M`00003vP100,0*01"; -//! //! let mut parser = AisParser::new(); -//! if let AisFragments::Complete(sentence) = parser.parse(line, true)? { -//! // This sentence is complete, ie unfragmented +//! +//! if let AisFragments::Complete(sentence) = parser.parse(line, true).unwrap() { //! assert_eq!(sentence.num_fragments, 1); -//! // The data was transmitted on AIS channel B //! assert_eq!(sentence.channel, Some('B')); //! -//! if let Some(message) = sentence.message { +//! if let Some(ref message) = sentence.message { //! match message { //! AisMessage::AidToNavigationReport(report) => { //! assert_eq!(report.mmsi, 993692028); //! assert_eq!(report.name, "SF OAK BAY BR VAIS E"); -//! // There are a ton more fields available here //! }, //! _ => panic!("Unexpected message type"), //! } //! } +//! +//! let json = serialize_to_json(&sentence).unwrap(); +//! let deserialized_sentence = deserialize_from_json(&json).unwrap(); +//! assert_eq!(sentence, deserialized_sentence); //! } -//! # Ok::<(), ais::errors::Error>(()) //! ``` + #![cfg_attr(not(feature = "std"), no_std)] #[doc(hidden)] -/// standard library stuff available crate-wide, regardless of `no_std` state +/// Standard library items, available crate-wide regardless of `no_std` state. pub mod lib { #[cfg(all(not(feature = "std"), not(feature = "alloc")))] pub mod std { @@ -80,6 +85,19 @@ pub mod sentence; pub use errors::Result; pub use sentence::{AisFragments, AisParser}; +use serde_json::Error as SerdeError; +use sentence::AisSentence; + +/// Serializes an `AisSentence` to JSON +pub fn serialize_to_json(sentence: &AisSentence) -> std::result::Result { + serde_json::to_string(sentence) +} + +/// Deserializes an `AisSentence` from JSON +pub fn deserialize_from_json(json_data: &str) -> std::result::Result { + serde_json::from_str(json_data) +} + #[cfg(test)] mod test_helpers { #[inline] @@ -94,6 +112,7 @@ mod test_helpers { #[cfg(test)] mod tests { use super::*; + use crate::sentence::{AisReportType, TalkerId, AisSentence}; const TEST_MESSAGES: [&[u8]; 8] = [ b"!AIVDM,1,1,,B,E>kb9O9aS@7PUh10dh19@;0Tah2cWrfP:l?M`00003vP100,0*01", @@ -108,9 +127,54 @@ mod tests { #[test] fn end_to_end() { - let mut parser = sentence::AisParser::new(); + let mut parser = AisParser::new(); for line in TEST_MESSAGES.iter() { parser.parse(line, true).unwrap(); } } + + #[test] + fn test_json_serialization() { + let mut parser = AisParser::new(); + let line = b"!AIVDM,1,1,,B,E>kb9O9aS@7PUh10dh19@;0Tah2cWrfP:l?M`00003vP100,0*01"; + + if let AisFragments::Complete(sentence) = parser.parse(line, true).unwrap() { + // Serialize the sentence to JSON + let json = serialize_to_json(&sentence).expect("Failed to serialize to JSON"); + println!("Serialized JSON: {}", json); + + // Deserialize back from JSON + let deserialized_sentence = deserialize_from_json(&json) + .expect("Failed to deserialize from JSON"); + + assert_eq!(sentence, deserialized_sentence); + } + } + + #[test] + fn test_serialize_deserialize() { + // Create a sample AisSentence struct + let original_sentence = AisSentence { + message: None, + talker_id: TalkerId::AI, + report_type: AisReportType::VDM, + num_fragments: 1, + fragment_number: 1, + message_id: Some(123), + channel: Some('A'), + data: vec![69, 62, 107, 98, 57, 79], // sample data; replace with real data if needed + fill_bit_count: 0, + message_type: 1, + }; + + // Serialize to JSON + let json_data = serialize_to_json(&original_sentence).expect("Serialization failed"); + + // Deserialize back to an AisSentence + let deserialized_sentence: AisSentence = deserialize_from_json(&json_data) + .expect("Deserialization failed"); + + // Check if the deserialized struct matches the original + assert_eq!(original_sentence, deserialized_sentence); + } } diff --git a/src/messages/addressed_safety_related.rs b/src/messages/addressed_safety_related.rs index 3cb7351..ed9b059 100644 --- a/src/messages/addressed_safety_related.rs +++ b/src/messages/addressed_safety_related.rs @@ -5,9 +5,9 @@ use crate::errors::Result; use nom::bits::{bits, complete::take as take_bits}; use nom::combinator::map; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Serialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize, Eq)] pub struct AddressedSafetyRelatedMessage { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/messages/aid_to_navigation_report.rs b/src/messages/aid_to_navigation_report.rs index ce09fae..7fdea24 100644 --- a/src/messages/aid_to_navigation_report.rs +++ b/src/messages/aid_to_navigation_report.rs @@ -7,9 +7,9 @@ use crate::errors::Result; use nom::bits::{bits, complete::take as take_bits}; use nom::combinator::map; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum NavaidType { ReferencePoint, Racon, @@ -85,7 +85,7 @@ impl NavaidType { } } -#[derive(Debug, PartialEq, Serialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct AidToNavigationReport { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/messages/assignment_mode_command.rs b/src/messages/assignment_mode_command.rs index c49d7fa..7879f69 100644 --- a/src/messages/assignment_mode_command.rs +++ b/src/messages/assignment_mode_command.rs @@ -5,9 +5,9 @@ use super::AisMessageType; use crate::errors::Result; use nom::bits::{bits, complete::take as take_bits}; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct AssignmentModeCommand { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/messages/base_station_report.rs b/src/messages/base_station_report.rs index 9a6b69a..b6076e2 100644 --- a/src/messages/base_station_report.rs +++ b/src/messages/base_station_report.rs @@ -8,9 +8,9 @@ use crate::errors::Result; use nom::bits::{bits, complete::take as take_bits}; use nom::combinator::map; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Serialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct BaseStationReport { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/messages/binary_acknowledge.rs b/src/messages/binary_acknowledge.rs index 19cb205..516724e 100644 --- a/src/messages/binary_acknowledge.rs +++ b/src/messages/binary_acknowledge.rs @@ -8,9 +8,9 @@ use nom::bits::{bits, complete::take as take_bits}; #[cfg(any(feature = "std", feature = "alloc"))] use nom::multi::many_m_n; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Acknowledgement { pub mmsi: u32, pub seq_num: u8, @@ -29,7 +29,7 @@ pub type AcknowledgementList = lib::std::vec::Vec; #[cfg(all(not(feature = "std"), not(feature = "alloc")))] pub type AcknowledgementList = lib::std::vec::Vec; -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct BinaryAcknowledge { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/messages/binary_addressed.rs b/src/messages/binary_addressed.rs index d4b7de3..c96af2b 100644 --- a/src/messages/binary_addressed.rs +++ b/src/messages/binary_addressed.rs @@ -6,7 +6,7 @@ use crate::lib; use nom::bits::{bits, complete::take as take_bits}; use nom::combinator::map; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; #[cfg(all(not(feature = "std"), not(feature = "alloc")))] const MAX_DATA_SIZE_BYTES: usize = 119; @@ -16,7 +16,7 @@ pub type MessageData = lib::std::vec::Vec; #[cfg(all(not(feature = "std"), not(feature = "alloc")))] pub type MessageData = lib::std::vec::Vec; -#[derive(Debug, PartialEq, Serialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize, Eq)] pub struct BinaryAddressedMessage { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/messages/binary_broadcast_message.rs b/src/messages/binary_broadcast_message.rs index 15e5eb6..8356865 100644 --- a/src/messages/binary_broadcast_message.rs +++ b/src/messages/binary_broadcast_message.rs @@ -4,7 +4,7 @@ use crate::errors::Result; use crate::lib; use nom::bits::{bits, complete::take as take_bits}; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; #[cfg(all(not(feature = "std"), not(feature = "alloc")))] const MAX_DATA_SIZE_BYTES: usize = 119; @@ -14,7 +14,7 @@ pub type MessageData = lib::std::vec::Vec; #[cfg(all(not(feature = "std"), not(feature = "alloc")))] pub type MessageData = lib::std::vec::Vec; -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct BinaryBroadcastMessage { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/messages/data_link_management_message.rs b/src/messages/data_link_management_message.rs index a7cdc6e..9c0cf53 100644 --- a/src/messages/data_link_management_message.rs +++ b/src/messages/data_link_management_message.rs @@ -8,9 +8,9 @@ use nom::bits::{bits, complete::take as take_bits}; #[cfg(any(feature = "std", feature = "alloc"))] use nom::multi::many_m_n; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct SlotReservation { pub offset: u16, pub num_slots: u8, @@ -41,7 +41,7 @@ pub type SlotReservationList = lib::std::vec::Vec; #[cfg(all(not(feature = "std"), not(feature = "alloc")))] pub type SlotReservationList = lib::std::vec::Vec; -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct DataLinkManagementMessage { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/messages/dgnss_broadcast_binary_message.rs b/src/messages/dgnss_broadcast_binary_message.rs index 60ca525..b6c915c 100644 --- a/src/messages/dgnss_broadcast_binary_message.rs +++ b/src/messages/dgnss_broadcast_binary_message.rs @@ -6,7 +6,7 @@ use crate::lib; use nom::bits::{bits, complete::take as take_bits}; use nom::combinator::map; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; #[cfg(all(not(feature = "std"), not(feature = "alloc")))] const MAX_DATA_SIZE_BYTES: usize = 119; @@ -16,7 +16,7 @@ pub type CorrectionData = lib::std::vec::Vec; #[cfg(all(not(feature = "std"), not(feature = "alloc")))] pub type CorrectionData = lib::std::vec::Vec; -#[derive(Debug, PartialEq, Serialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct DgnssBroadcastBinaryMessage { pub message_type: u8, pub repeat_indicator: u8, @@ -26,7 +26,7 @@ pub struct DgnssBroadcastBinaryMessage { pub payload: DifferentialCorrectionData, } -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct DifferentialCorrectionData { pub message_type: u8, pub station_id: u16, diff --git a/src/messages/extended_class_b_position_report.rs b/src/messages/extended_class_b_position_report.rs index 924d04a..1d9c65e 100644 --- a/src/messages/extended_class_b_position_report.rs +++ b/src/messages/extended_class_b_position_report.rs @@ -10,9 +10,9 @@ use crate::messages::types::ShipType; use nom::bits::{bits, complete::take as take_bits}; use nom::combinator::map; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Serialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct ExtendedClassBPositionReport { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/messages/interrogation.rs b/src/messages/interrogation.rs index 0176425..385c1a9 100644 --- a/src/messages/interrogation.rs +++ b/src/messages/interrogation.rs @@ -6,9 +6,9 @@ use crate::errors::Result; use crate::lib; use nom::bits::{bits, complete::take as take_bits}; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Message { pub message_type: u8, pub slot_offset: Option, @@ -42,7 +42,7 @@ pub type MessageList = lib::std::vec::Vec; #[cfg(all(not(feature = "std"), not(feature = "alloc")))] pub type MessageList = lib::std::vec::Vec; -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Station { pub mmsi: u32, pub messages: MessageList, @@ -74,7 +74,7 @@ pub type StationList = lib::std::vec::Vec; #[cfg(all(not(feature = "std"), not(feature = "alloc")))] pub type StationList = lib::std::vec::Vec; -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Interrogation { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/messages/long_range_ais_broadcast.rs b/src/messages/long_range_ais_broadcast.rs index 938d948..c6a10cb 100644 --- a/src/messages/long_range_ais_broadcast.rs +++ b/src/messages/long_range_ais_broadcast.rs @@ -7,9 +7,9 @@ use crate::errors::Result; use nom::bits::{bits, complete::take as take_bits}; use nom::combinator::map; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Serialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct LongRangeAisBroadcastMessage { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/messages/mod.rs b/src/messages/mod.rs index dff5c89..1d49167 100644 --- a/src/messages/mod.rs +++ b/src/messages/mod.rs @@ -2,10 +2,8 @@ use crate::errors::Result; use crate::lib; use crate::sentence::AisRawData; -use serde::Serialize; +use serde::{Deserialize, Serialize}; #[cfg(feature = "std")] -use std::fmt; - pub mod addressed_safety_related; pub mod aid_to_navigation_report; @@ -41,7 +39,7 @@ pub use parsers::message_type; use crate::lib::std::{format, vec, vec::Vec}; /// Contains all structured messages recognized by this crate -#[derive(Debug, PartialEq, Serialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub enum AisMessage { PositionReport(position_report::PositionReport), BaseStationReport(base_station_report::BaseStationReport), @@ -66,35 +64,6 @@ pub enum AisMessage { BinaryAddressedMessage(binary_addressed::BinaryAddressedMessage), } -#[cfg(feature = "std")] -impl fmt::Display for AisMessage { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - AisMessage::PositionReport(report) => write!(f, "PositionReport: {:?}", report), - AisMessage::BaseStationReport(report) => write!(f, "BaseStationReport: {:?}", report), - AisMessage::BinaryBroadcastMessage(message) => write!(f, "BinaryBroadcastMessage: {:?}", message), - AisMessage::Interrogation(interrogation) => write!(f, "Interrogation: {:?}", interrogation), - AisMessage::StaticAndVoyageRelatedData(data) => write!(f, "StaticAndVoyageRelatedData: {:?}", data), - AisMessage::DgnssBroadcastBinaryMessage(message) => write!(f, "DgnssBroadcastBinaryMessage: {:?}", message), - AisMessage::StandardClassBPositionReport(report) => write!(f, "StandardClassBPositionReport: {:?}", report), - AisMessage::ExtendedClassBPositionReport(report) => write!(f, "ExtendedClassBPositionReport: {:?}", report), - AisMessage::DataLinkManagementMessage(message) => write!(f, "DataLinkManagementMessage: {:?}", message), - AisMessage::AidToNavigationReport(report) => write!(f, "AidToNavigationReport: {:?}", report), - AisMessage::StaticDataReport(report) => write!(f, "StaticDataReport: {:?}", report), - AisMessage::UtcDateResponse(response) => write!(f, "UtcDateResponse: {:?}", response), - AisMessage::StandardAircraftPositionReport(report) => write!(f, "StandardAircraftPositionReport: {:?}", report), - AisMessage::AssignmentModeCommand(command) => write!(f, "AssignmentModeCommand: {:?}", command), - AisMessage::BinaryAcknowledgeMessage(message) => write!(f, "BinaryAcknowledgeMessage: {:?}", message), - AisMessage::UtcDateInquiry(inquiry) => write!(f, "UtcDateInquiry: {:?}", inquiry), - AisMessage::AddressedSafetyRelatedMessage(message) => write!(f, "AddressedSafetyRelatedMessage: {:?}", message), - AisMessage::SafetyRelatedBroadcastMessage(message) => write!(f, "SafetyRelatedBroadcastMessage: {:?}", message), - AisMessage::SafetyRelatedAcknowledgment(acknowledgment) => write!(f, "SafetyRelatedAcknowledgment: {:?}", acknowledgment), - AisMessage::LongRangeAisBroadcastMessage(message) => write!(f, "LongRangeAisBroadcastMessage: {:?}", message), - AisMessage::BinaryAddressedMessage(message) => write!(f, "BinaryAddressedMessage: {:?}", message), - } - } -} - /// Trait that describes specific types of AIS messages pub trait AisMessageType<'a>: Sized { /// The common name for the message type diff --git a/src/messages/navigation.rs b/src/messages/navigation.rs index 456e565..1024827 100644 --- a/src/messages/navigation.rs +++ b/src/messages/navigation.rs @@ -1,4 +1,4 @@ -use serde::Serialize; +use serde::{Serialize, Deserialize}; pub fn parse_speed_over_ground(data: u16) -> Option { match data { @@ -35,7 +35,7 @@ pub fn parse_heading(data: u16) -> Option { } } -#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] pub enum Accuracy { Unaugmented, Dgps, @@ -51,7 +51,7 @@ impl Accuracy { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct RateOfTurn { raw: i8, } @@ -90,7 +90,7 @@ impl RateOfTurn { } } -#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] pub enum ManeuverIndicator { NoSpecialManeuver, SpecialManeuver, diff --git a/src/messages/position_report.rs b/src/messages/position_report.rs index 6583b21..46d147f 100644 --- a/src/messages/position_report.rs +++ b/src/messages/position_report.rs @@ -7,9 +7,9 @@ use crate::errors::Result; use nom::bits::{bits, complete::take as take_bits}; use nom::combinator::map; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Serialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct PositionReport { pub message_type: u8, pub repeat_indicator: u8, @@ -80,7 +80,7 @@ fn parse_base(data: &[u8]) -> IResult<&[u8], PositionReport> { })(data) } -#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] pub enum NavigationStatus { UnderWayUsingEngine, AtAnchor, diff --git a/src/messages/radio_status.rs b/src/messages/radio_status.rs index c1131d3..34b2e61 100644 --- a/src/messages/radio_status.rs +++ b/src/messages/radio_status.rs @@ -3,15 +3,15 @@ use nom::bits::complete::take as take_bits; use nom::combinator::map; use nom::error::ErrorKind; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum RadioStatus { Sotdma(SotdmaMessage), Itdma(ItdmaMessage), } -#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] pub enum SyncState { UtcDirect, UtcIndirect, @@ -33,7 +33,7 @@ impl SyncState { } } -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum SubMessage { SlotOffset(i16), UtcHourAndMinute(u8, u8), @@ -76,7 +76,7 @@ impl SubMessage { } } -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct SotdmaMessage { pub sync_state: SyncState, pub slot_timeout: u8, @@ -99,7 +99,7 @@ impl SotdmaMessage { } } -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct ItdmaMessage { pub sync_state: SyncState, pub slot_increment: i16, diff --git a/src/messages/safety_related_acknowledgment.rs b/src/messages/safety_related_acknowledgment.rs index 85db1f0..83886b3 100644 --- a/src/messages/safety_related_acknowledgment.rs +++ b/src/messages/safety_related_acknowledgment.rs @@ -8,9 +8,9 @@ use nom::bits::{bits, complete::take as take_bits}; #[cfg(any(feature = "std", feature = "alloc"))] use nom::multi::many_m_n; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Acknowledgement { pub mmsi: u32, pub seq_num: u8, @@ -29,7 +29,7 @@ pub type AcknowledgementList = lib::std::vec::Vec; #[cfg(all(not(feature = "std"), not(feature = "alloc")))] pub type AcknowledgementList = lib::std::vec::Vec; -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct SafetyRelatedAcknowledge { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/messages/safety_related_broadcast.rs b/src/messages/safety_related_broadcast.rs index b1f1be8..ba4280e 100644 --- a/src/messages/safety_related_broadcast.rs +++ b/src/messages/safety_related_broadcast.rs @@ -5,9 +5,9 @@ use super::AisMessageType; use crate::errors::Result; use nom::bits::{bits, complete::take as take_bits}; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Serialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize, Eq)] pub struct SafetyRelatedBroadcastMessage { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/messages/standard_aircraft_position_report.rs b/src/messages/standard_aircraft_position_report.rs index 97e8719..27040e4 100644 --- a/src/messages/standard_aircraft_position_report.rs +++ b/src/messages/standard_aircraft_position_report.rs @@ -10,9 +10,9 @@ use crate::errors::Result; use nom::bits::{bits, complete::take as take_bits}; use nom::combinator::map; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Serialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct SARPositionReport { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/messages/standard_class_b_position_report.rs b/src/messages/standard_class_b_position_report.rs index 41f9ac2..f267dbd 100644 --- a/src/messages/standard_class_b_position_report.rs +++ b/src/messages/standard_class_b_position_report.rs @@ -8,9 +8,9 @@ use crate::errors::Result; use nom::bits::{bits, complete::take as take_bits}; use nom::combinator::map; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Serialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct StandardClassBPositionReport { pub message_type: u8, pub repeat_indicator: u8, @@ -43,7 +43,7 @@ impl<'a> AisMessageType<'a> for StandardClassBPositionReport { } } -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum CarrierSense { /// Class B SOTDMA unit Sotdma, diff --git a/src/messages/static_and_voyage_related_data.rs b/src/messages/static_and_voyage_related_data.rs index 5c29946..c5a343a 100644 --- a/src/messages/static_and_voyage_related_data.rs +++ b/src/messages/static_and_voyage_related_data.rs @@ -7,9 +7,9 @@ use crate::lib; use nom::bits::{bits, complete::take as take_bits}; use nom::combinator::map; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq,Serialize)] +#[derive(Debug, PartialEq,Serialize, Deserialize)] pub struct StaticAndVoyageRelatedData { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/messages/static_data_report.rs b/src/messages/static_data_report.rs index 09b76c5..9be0d08 100644 --- a/src/messages/static_data_report.rs +++ b/src/messages/static_data_report.rs @@ -7,9 +7,9 @@ use crate::lib; use nom::bits::{bits, complete::take as take_bits}; use nom::combinator::map; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct StaticDataReport { pub message_type: u8, pub repeat_indicator: u8, @@ -28,7 +28,7 @@ impl<'a> AisMessageType<'a> for StaticDataReport { } } -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] /// Static Data Report messages have two different sub-message types. /// The idea is that both get broadcast periodically. pub enum MessagePart { diff --git a/src/messages/types.rs b/src/messages/types.rs index ccfa594..91bdc68 100644 --- a/src/messages/types.rs +++ b/src/messages/types.rs @@ -1,11 +1,11 @@ //! Common data types -use serde::Serialize; +use serde::{Serialize, Deserialize}; /// Electronic Position Fixing Device type. This is the /// type of device used for determining the object's /// position. -#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] pub enum EpfdType { Gps, Glonass, @@ -36,7 +36,7 @@ impl EpfdType { } } -#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] pub enum ShipType { Reserved(u8), WingInGround, @@ -242,7 +242,7 @@ impl From for u8 { } } -#[derive(Default, Debug, PartialEq, Eq, Serialize)] +#[derive(Default, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum Dte { Ready, #[default] @@ -259,7 +259,7 @@ impl From for Dte { } } -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum AssignedMode { Autonomous, Assigned, diff --git a/src/messages/utc_date_inquiry.rs b/src/messages/utc_date_inquiry.rs index dbba3e2..0119314 100644 --- a/src/messages/utc_date_inquiry.rs +++ b/src/messages/utc_date_inquiry.rs @@ -3,9 +3,9 @@ use super::AisMessageType; use crate::errors::Result; use nom::bits::{bits, complete::take as take_bits}; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Eq, Serialize)] +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct UtcDateInquiry { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/messages/utc_date_response.rs b/src/messages/utc_date_response.rs index 93f22a7..146ed09 100644 --- a/src/messages/utc_date_response.rs +++ b/src/messages/utc_date_response.rs @@ -8,9 +8,9 @@ use crate::errors::Result; use nom::bits::{bits, complete::take as take_bits}; use nom::combinator::map; use nom::IResult; -use serde::Serialize; +use serde::{Serialize, Deserialize}; -#[derive(Debug, PartialEq, Serialize)] +#[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct UtcDateResponse { pub message_type: u8, pub repeat_indicator: u8, diff --git a/src/sentence.rs b/src/sentence.rs index 8ad2169..0f03aad 100644 --- a/src/sentence.rs +++ b/src/sentence.rs @@ -11,6 +11,8 @@ use nom::combinator::{map, map_res, opt, peek, verify}; use nom::number::complete::hex_u32; use nom::sequence::{delimited, terminated}; use nom::IResult; +use serde::{Serialize, Deserialize}; + pub const MAX_SENTENCE_SIZE_BYTES: usize = 384; @@ -19,7 +21,7 @@ pub type AisRawData = lib::std::vec::Vec; #[cfg(all(not(feature = "std"), not(feature = "alloc")))] pub type AisRawData = lib::std::vec::Vec; -#[derive(PartialEq, Eq, Debug)] +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] /// Represents the NMEA sentence type of an AIS message pub enum AisReportType { /// Report from another ship @@ -41,7 +43,7 @@ impl<'a> From<&'a [u8]> for AisReportType { } /// Talker ID for the AIS station -#[derive(PartialEq, Eq, Debug)] +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] pub enum TalkerId { /// NMEA 4.0 Base AIS station AB, @@ -84,7 +86,7 @@ impl<'a> From<&'a [u8]> for TalkerId { } } -#[derive(Debug, PartialEq)] +#[derive(Serialize, Deserialize, PartialEq, Debug)] pub enum AisFragments { Complete(AisSentence), Incomplete(AisSentence), @@ -108,7 +110,7 @@ impl From for Result { } } -#[derive(Debug, Default)] +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] pub struct AisParser { message_id: Option, fragment_number: u8, @@ -118,7 +120,11 @@ pub struct AisParser { impl AisParser { /// Creates a new `AisParser` instance pub fn new() -> Self { - Self::default() + Self { + message_id: None, + fragment_number: 0, + data: AisRawData::default(), + } } /// Parses `line` as an NMEA sentence, checking the checksum and returning an @@ -185,7 +191,7 @@ impl AisParser { } } -#[derive(Debug, PartialEq)] +#[derive(Serialize, Deserialize, PartialEq, Debug)] /// Represents an NMEA sentence parsed as AIS pub struct AisSentence { pub talker_id: TalkerId,