Skip to content

Commit 92f9631

Browse files
authored
Add a couple of to and from string functions (#84)
1 parent 92ae781 commit 92f9631

File tree

2 files changed

+276
-6
lines changed

2 files changed

+276
-6
lines changed

swiftnav-sys/build.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ fn main() {
9595
.allowlist_var("GAL_WEEK_TO_GPS_WEEK")
9696
.allowlist_var("GLO_EPOCH_WN")
9797
.allowlist_var("GLO_EPOCH_TOW")
98+
.allowlist_var("SID_STR_LEN_MAX")
9899
.allowlist_type("constellation_t")
99100
.allowlist_type("code_t")
100101
.allowlist_type("gnss_signal_t")
@@ -109,12 +110,14 @@ fn main() {
109110
.allowlist_function("code_to_constellation")
110111
.allowlist_function("constellation_to_sat_count")
111112
.allowlist_function("constellation_to_string")
113+
.allowlist_function("constellation_string_to_enum")
112114
.allowlist_function("code_to_sig_count")
113115
.allowlist_function("code_to_chip_count")
114116
.allowlist_function("code_to_chip_rate")
115117
.allowlist_function("sid_to_carr_freq")
116118
.allowlist_function("code_string_to_enum")
117119
.allowlist_function("code_to_string")
120+
.allowlist_function("sid_to_string")
118121
.allowlist_var("NUM_SATS_GPS")
119122
.allowlist_var("NUM_SATS_SBAS")
120123
.allowlist_var("NUM_SATS_GLO")

swiftnav/src/signal.rs

Lines changed: 273 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use std::borrow::Cow;
1717
use std::error::Error;
1818
use std::ffi;
1919
use std::fmt;
20+
use std::str::FromStr;
2021

2122
/// GNSS satellite constellations
2223
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
@@ -78,6 +79,7 @@ impl Constellation {
7879
unsafe { swiftnav_sys::constellation_to_sat_count(*self as swiftnav_sys::constellation_t) }
7980
}
8081

82+
/// Get the human readable name of the constellation.
8183
pub fn to_str(&self) -> Cow<'static, str> {
8284
let c_str = unsafe {
8385
ffi::CStr::from_ptr(swiftnav_sys::constellation_to_string(
@@ -88,6 +90,22 @@ impl Constellation {
8890
}
8991
}
9092

93+
impl FromStr for Constellation {
94+
type Err = InvalidConstellation;
95+
fn from_str(s: &str) -> Result<Self, Self::Err> {
96+
let c_str = ffi::CString::new(s).map_err(|_| InvalidConstellation(-1))?;
97+
let constellation = unsafe { swiftnav_sys::constellation_string_to_enum(c_str.as_ptr()) };
98+
99+
Self::from_constellation_t(constellation)
100+
}
101+
}
102+
103+
impl fmt::Display for Constellation {
104+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105+
write!(f, "{}", self.to_str())
106+
}
107+
}
108+
91109
impl std::convert::TryFrom<u8> for Constellation {
92110
type Error = InvalidConstellation;
93111
fn try_from(value: u8) -> Result<Constellation, InvalidConstellation> {
@@ -348,17 +366,13 @@ impl Code {
348366
}
349367
}
350368

351-
/// Attempts to make a [`Code`] from a string
352-
pub fn from_c_str(s: &ffi::CStr) -> Result<Code, InvalidCode> {
353-
Self::from_code_t(unsafe { swiftnav_sys::code_string_to_enum(s.as_ptr()) })
354-
}
355-
369+
/// Get the human readable name of the code.
356370
pub fn to_str(&self) -> Cow<'static, str> {
357371
let c_str = unsafe { ffi::CStr::from_ptr(swiftnav_sys::code_to_string(self.to_code_t())) };
358372
c_str.to_string_lossy()
359373
}
360374

361-
/// Gets the corresponding [`Constellation`]
375+
/// Gets the corresponding [`Constellation`]
362376
pub fn to_constellation(&self) -> Constellation {
363377
Constellation::from_constellation_t(unsafe {
364378
swiftnav_sys::code_to_constellation(self.to_code_t())
@@ -406,6 +420,22 @@ impl Code {
406420
}
407421
}
408422

423+
impl FromStr for Code {
424+
type Err = InvalidCode;
425+
fn from_str(s: &str) -> Result<Self, Self::Err> {
426+
let c_str = ffi::CString::new(s).map_err(|_| InvalidCode(-1))?;
427+
let code = unsafe { swiftnav_sys::code_string_to_enum(c_str.as_ptr()) };
428+
429+
Self::from_code_t(code)
430+
}
431+
}
432+
433+
impl fmt::Display for Code {
434+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435+
write!(f, "{}", self.to_str())
436+
}
437+
}
438+
409439
impl std::convert::TryFrom<u8> for Code {
410440
type Error = InvalidCode;
411441
fn try_from(value: u8) -> Result<Code, InvalidCode> {
@@ -485,6 +515,30 @@ impl GnssSignal {
485515
pub fn carrier_frequency(&self) -> f64 {
486516
unsafe { swiftnav_sys::sid_to_carr_freq(self.0) }
487517
}
518+
519+
/// Makes the human readable signal name
520+
pub fn to_str(&self) -> String {
521+
let mut raw_str = [0; swiftnav_sys::SID_STR_LEN_MAX as usize + 1];
522+
523+
unsafe {
524+
let n_bytes = swiftnav_sys::sid_to_string(
525+
raw_str.as_mut_ptr(),
526+
raw_str.len() as i32 - 1,
527+
self.to_gnss_signal_t(),
528+
);
529+
raw_str[n_bytes as usize] = 0;
530+
531+
let str = ffi::CStr::from_ptr(raw_str.as_ptr());
532+
533+
str.to_string_lossy().to_string()
534+
}
535+
}
536+
}
537+
538+
impl fmt::Display for GnssSignal {
539+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
540+
write!(f, "{}", self.to_str())
541+
}
488542
}
489543

490544
#[cfg(test)]
@@ -995,4 +1049,217 @@ mod tests {
9951049
}
9961050
}
9971051
}
1052+
1053+
#[test]
1054+
fn constellation_strings() {
1055+
assert_eq!(Constellation::Gps.to_str(), "GPS");
1056+
assert_eq!(Constellation::Sbas.to_str(), "SBAS");
1057+
assert_eq!(Constellation::Glo.to_str(), "GLO");
1058+
assert_eq!(Constellation::Bds.to_str(), "BDS");
1059+
assert_eq!(Constellation::Qzs.to_str(), "QZS");
1060+
assert_eq!(Constellation::Gal.to_str(), "GAL");
1061+
1062+
assert_eq!(Constellation::from_str("GPS").unwrap(), Constellation::Gps);
1063+
assert_eq!(
1064+
Constellation::from_str("SBAS").unwrap(),
1065+
Constellation::Sbas
1066+
);
1067+
assert_eq!(Constellation::from_str("GLO").unwrap(), Constellation::Glo);
1068+
assert_eq!(Constellation::from_str("BDS").unwrap(), Constellation::Bds);
1069+
assert_eq!(Constellation::from_str("QZS").unwrap(), Constellation::Qzs);
1070+
assert_eq!(Constellation::from_str("GAL").unwrap(), Constellation::Gal);
1071+
1072+
{
1073+
let result = Constellation::from_str("Bad String");
1074+
assert!(result.is_err());
1075+
assert_eq!(result.unwrap_err(), InvalidConstellation(-1));
1076+
}
1077+
{
1078+
let result = Constellation::from_str("Nul\0String");
1079+
assert!(result.is_err());
1080+
assert_eq!(result.unwrap_err(), InvalidConstellation(-1));
1081+
}
1082+
{
1083+
let result = Constellation::from_str("💩💩💩💩");
1084+
assert!(result.is_err());
1085+
assert_eq!(result.unwrap_err(), InvalidConstellation(-1));
1086+
}
1087+
}
1088+
1089+
#[test]
1090+
fn code_strings() {
1091+
assert_eq!(Code::GpsL1ca.to_str(), "GPS L1CA");
1092+
assert_eq!(Code::GpsL2cm.to_str(), "GPS L2CM");
1093+
assert_eq!(Code::SbasL1ca.to_str(), "SBAS L1");
1094+
assert_eq!(Code::GloL1of.to_str(), "GLO L1OF");
1095+
assert_eq!(Code::GloL2of.to_str(), "GLO L2OF");
1096+
assert_eq!(Code::GpsL1p.to_str(), "GPS L1P");
1097+
assert_eq!(Code::GpsL2p.to_str(), "GPS L2P");
1098+
assert_eq!(Code::GpsL2cl.to_str(), "GPS L2CL");
1099+
assert_eq!(Code::GpsL2cx.to_str(), "GPS L2C");
1100+
assert_eq!(Code::GpsL5i.to_str(), "GPS L5I");
1101+
assert_eq!(Code::GpsL5q.to_str(), "GPS L5Q");
1102+
assert_eq!(Code::GpsL5x.to_str(), "GPS L5");
1103+
assert_eq!(Code::Bds2B1.to_str(), "BDS B1");
1104+
assert_eq!(Code::Bds2B2.to_str(), "BDS B2");
1105+
assert_eq!(Code::GalE1b.to_str(), "GAL E1B");
1106+
assert_eq!(Code::GalE1c.to_str(), "GAL E1C");
1107+
assert_eq!(Code::GalE1x.to_str(), "GAL E1");
1108+
assert_eq!(Code::GalE6b.to_str(), "GAL E6B");
1109+
assert_eq!(Code::GalE6c.to_str(), "GAL E6C");
1110+
assert_eq!(Code::GalE6x.to_str(), "GAL E6");
1111+
assert_eq!(Code::GalE7i.to_str(), "GAL E5bI");
1112+
assert_eq!(Code::GalE7q.to_str(), "GAL E5bQ");
1113+
assert_eq!(Code::GalE7x.to_str(), "GAL E5b");
1114+
assert_eq!(Code::GalE8i.to_str(), "GAL E8I");
1115+
assert_eq!(Code::GalE8q.to_str(), "GAL E8Q");
1116+
assert_eq!(Code::GalE8x.to_str(), "GAL E8");
1117+
assert_eq!(Code::GalE5i.to_str(), "GAL E5aI");
1118+
assert_eq!(Code::GalE5q.to_str(), "GAL E5aQ");
1119+
assert_eq!(Code::GalE5x.to_str(), "GAL E5a");
1120+
assert_eq!(Code::GloL1p.to_str(), "GLO L1P");
1121+
assert_eq!(Code::GloL2p.to_str(), "GLO L2P");
1122+
assert_eq!(Code::QzsL1ca.to_str(), "QZS L1CA");
1123+
assert_eq!(Code::QzsL1ci.to_str(), "QZS L1CI");
1124+
assert_eq!(Code::QzsL1cq.to_str(), "QZS L1CQ");
1125+
assert_eq!(Code::QzsL1cx.to_str(), "QZS L1CX");
1126+
assert_eq!(Code::QzsL2cm.to_str(), "QZS L2CM");
1127+
assert_eq!(Code::QzsL2cl.to_str(), "QZS L2CL");
1128+
assert_eq!(Code::QzsL2cx.to_str(), "QZS L2C");
1129+
assert_eq!(Code::QzsL5i.to_str(), "QZS L5I");
1130+
assert_eq!(Code::QzsL5q.to_str(), "QZS L5Q");
1131+
assert_eq!(Code::QzsL5x.to_str(), "QZS L5");
1132+
assert_eq!(Code::SbasL5i.to_str(), "SBAS L5I");
1133+
assert_eq!(Code::SbasL5q.to_str(), "SBAS L5Q");
1134+
assert_eq!(Code::SbasL5x.to_str(), "SBAS L5");
1135+
assert_eq!(Code::Bds3B1ci.to_str(), "BDS3 B1CI");
1136+
assert_eq!(Code::Bds3B1cq.to_str(), "BDS3 B1CQ");
1137+
assert_eq!(Code::Bds3B1cx.to_str(), "BDS3 B1C");
1138+
assert_eq!(Code::Bds3B5i.to_str(), "BDS3 B5I");
1139+
assert_eq!(Code::Bds3B5q.to_str(), "BDS3 B5Q");
1140+
assert_eq!(Code::Bds3B5x.to_str(), "BDS3 B5");
1141+
assert_eq!(Code::Bds3B7i.to_str(), "BDS3 B7I");
1142+
assert_eq!(Code::Bds3B7q.to_str(), "BDS3 B7Q");
1143+
assert_eq!(Code::Bds3B7x.to_str(), "BDS3 B7");
1144+
assert_eq!(Code::Bds3B3i.to_str(), "BDS3 B3I");
1145+
assert_eq!(Code::Bds3B3q.to_str(), "BDS3 B3Q");
1146+
assert_eq!(Code::Bds3B3x.to_str(), "BDS3 B3");
1147+
assert_eq!(Code::GpsL1ci.to_str(), "GPS L1CI");
1148+
assert_eq!(Code::GpsL1cq.to_str(), "GPS L1CQ");
1149+
assert_eq!(Code::GpsL1cx.to_str(), "GPS L1C");
1150+
assert_eq!(Code::AuxGps.to_str(), "GPS AUX");
1151+
assert_eq!(Code::AuxSbas.to_str(), "SBAS AUX");
1152+
assert_eq!(Code::AuxGal.to_str(), "GAL AUX");
1153+
assert_eq!(Code::AuxQzs.to_str(), "QZS AUX");
1154+
assert_eq!(Code::AuxBds.to_str(), "BDS AUX");
1155+
1156+
assert_eq!(Code::from_str("GPS L1CA").unwrap(), Code::GpsL1ca);
1157+
assert_eq!(Code::from_str("GPS L2CM").unwrap(), Code::GpsL2cm);
1158+
assert_eq!(Code::from_str("SBAS L1").unwrap(), Code::SbasL1ca);
1159+
assert_eq!(Code::from_str("GLO L1OF").unwrap(), Code::GloL1of);
1160+
assert_eq!(Code::from_str("GLO L2OF").unwrap(), Code::GloL2of);
1161+
assert_eq!(Code::from_str("GPS L1P").unwrap(), Code::GpsL1p);
1162+
assert_eq!(Code::from_str("GPS L2P").unwrap(), Code::GpsL2p);
1163+
assert_eq!(Code::from_str("GPS L2CL").unwrap(), Code::GpsL2cl);
1164+
assert_eq!(Code::from_str("GPS L2C").unwrap(), Code::GpsL2cx);
1165+
assert_eq!(Code::from_str("GPS L5I").unwrap(), Code::GpsL5i);
1166+
assert_eq!(Code::from_str("GPS L5Q").unwrap(), Code::GpsL5q);
1167+
assert_eq!(Code::from_str("GPS L5").unwrap(), Code::GpsL5x);
1168+
assert_eq!(Code::from_str("BDS B1").unwrap(), Code::Bds2B1);
1169+
assert_eq!(Code::from_str("BDS B2").unwrap(), Code::Bds2B2);
1170+
assert_eq!(Code::from_str("GAL E1B").unwrap(), Code::GalE1b);
1171+
assert_eq!(Code::from_str("GAL E1C").unwrap(), Code::GalE1c);
1172+
assert_eq!(Code::from_str("GAL E1").unwrap(), Code::GalE1x);
1173+
assert_eq!(Code::from_str("GAL E6B").unwrap(), Code::GalE6b);
1174+
assert_eq!(Code::from_str("GAL E6C").unwrap(), Code::GalE6c);
1175+
assert_eq!(Code::from_str("GAL E6").unwrap(), Code::GalE6x);
1176+
assert_eq!(Code::from_str("GAL E5bI").unwrap(), Code::GalE7i);
1177+
assert_eq!(Code::from_str("GAL E5bQ").unwrap(), Code::GalE7q);
1178+
assert_eq!(Code::from_str("GAL E5b").unwrap(), Code::GalE7x);
1179+
assert_eq!(Code::from_str("GAL E8I").unwrap(), Code::GalE8i);
1180+
assert_eq!(Code::from_str("GAL E8Q").unwrap(), Code::GalE8q);
1181+
assert_eq!(Code::from_str("GAL E8").unwrap(), Code::GalE8x);
1182+
assert_eq!(Code::from_str("GAL E5aI").unwrap(), Code::GalE5i);
1183+
assert_eq!(Code::from_str("GAL E5aQ").unwrap(), Code::GalE5q);
1184+
assert_eq!(Code::from_str("GAL E5a").unwrap(), Code::GalE5x);
1185+
assert_eq!(Code::from_str("GLO L1P").unwrap(), Code::GloL1p);
1186+
assert_eq!(Code::from_str("GLO L2P").unwrap(), Code::GloL2p);
1187+
assert_eq!(Code::from_str("QZS L1CA").unwrap(), Code::QzsL1ca);
1188+
assert_eq!(Code::from_str("QZS L1CI").unwrap(), Code::QzsL1ci);
1189+
assert_eq!(Code::from_str("QZS L1CQ").unwrap(), Code::QzsL1cq);
1190+
assert_eq!(Code::from_str("QZS L1CX").unwrap(), Code::QzsL1cx);
1191+
assert_eq!(Code::from_str("QZS L2CM").unwrap(), Code::QzsL2cm);
1192+
assert_eq!(Code::from_str("QZS L2CL").unwrap(), Code::QzsL2cl);
1193+
assert_eq!(Code::from_str("QZS L2C").unwrap(), Code::QzsL2cx);
1194+
assert_eq!(Code::from_str("QZS L5I").unwrap(), Code::QzsL5i);
1195+
assert_eq!(Code::from_str("QZS L5Q").unwrap(), Code::QzsL5q);
1196+
assert_eq!(Code::from_str("QZS L5").unwrap(), Code::QzsL5x);
1197+
assert_eq!(Code::from_str("SBAS L5I").unwrap(), Code::SbasL5i);
1198+
assert_eq!(Code::from_str("SBAS L5Q").unwrap(), Code::SbasL5q);
1199+
assert_eq!(Code::from_str("SBAS L5").unwrap(), Code::SbasL5x);
1200+
assert_eq!(Code::from_str("BDS3 B1CI").unwrap(), Code::Bds3B1ci);
1201+
assert_eq!(Code::from_str("BDS3 B1CQ").unwrap(), Code::Bds3B1cq);
1202+
assert_eq!(Code::from_str("BDS3 B1C").unwrap(), Code::Bds3B1cx);
1203+
assert_eq!(Code::from_str("BDS3 B5I").unwrap(), Code::Bds3B5i);
1204+
assert_eq!(Code::from_str("BDS3 B5Q").unwrap(), Code::Bds3B5q);
1205+
assert_eq!(Code::from_str("BDS3 B5").unwrap(), Code::Bds3B5x);
1206+
assert_eq!(Code::from_str("BDS3 B7I").unwrap(), Code::Bds3B7i);
1207+
assert_eq!(Code::from_str("BDS3 B7Q").unwrap(), Code::Bds3B7q);
1208+
assert_eq!(Code::from_str("BDS3 B7").unwrap(), Code::Bds3B7x);
1209+
assert_eq!(Code::from_str("BDS3 B3I").unwrap(), Code::Bds3B3i);
1210+
assert_eq!(Code::from_str("BDS3 B3Q").unwrap(), Code::Bds3B3q);
1211+
assert_eq!(Code::from_str("BDS3 B3").unwrap(), Code::Bds3B3x);
1212+
assert_eq!(Code::from_str("GPS L1CI").unwrap(), Code::GpsL1ci);
1213+
assert_eq!(Code::from_str("GPS L1CQ").unwrap(), Code::GpsL1cq);
1214+
assert_eq!(Code::from_str("GPS L1C").unwrap(), Code::GpsL1cx);
1215+
assert_eq!(Code::from_str("GPS AUX").unwrap(), Code::AuxGps);
1216+
assert_eq!(Code::from_str("SBAS AUX").unwrap(), Code::AuxSbas);
1217+
assert_eq!(Code::from_str("GAL AUX").unwrap(), Code::AuxGal);
1218+
assert_eq!(Code::from_str("QZS AUX").unwrap(), Code::AuxQzs);
1219+
assert_eq!(Code::from_str("BDS AUX").unwrap(), Code::AuxBds);
1220+
1221+
{
1222+
let result = Code::from_str("Bad String");
1223+
assert!(result.is_err());
1224+
assert_eq!(result.unwrap_err(), InvalidCode(-1));
1225+
}
1226+
{
1227+
let result = Code::from_str("Nul\0String");
1228+
assert!(result.is_err());
1229+
assert_eq!(result.unwrap_err(), InvalidCode(-1));
1230+
}
1231+
{
1232+
let result = Code::from_str("💩💩💩💩");
1233+
assert!(result.is_err());
1234+
assert_eq!(result.unwrap_err(), InvalidCode(-1));
1235+
}
1236+
}
1237+
1238+
#[test]
1239+
fn signal_strings() {
1240+
assert_eq!(
1241+
GnssSignal::new(1, Code::GpsL1ca).unwrap().to_str(),
1242+
"GPS L1CA 1"
1243+
);
1244+
assert_eq!(
1245+
GnssSignal::new(32, Code::GpsL1ca).unwrap().to_str(),
1246+
"GPS L1CA 32"
1247+
);
1248+
assert_eq!(
1249+
GnssSignal::new(1, Code::GalE5x).unwrap().to_str(),
1250+
"GAL E5a 1"
1251+
);
1252+
assert_eq!(
1253+
GnssSignal::new(32, Code::GalE5x).unwrap().to_str(),
1254+
"GAL E5a 32"
1255+
);
1256+
assert_eq!(
1257+
GnssSignal::new(1, Code::Bds2B1).unwrap().to_str(),
1258+
"BDS B1 1"
1259+
);
1260+
assert_eq!(
1261+
GnssSignal::new(32, Code::Bds2B1).unwrap().to_str(),
1262+
"BDS B1 32"
1263+
);
1264+
}
9981265
}

0 commit comments

Comments
 (0)