1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
use core::str::from_utf8_unchecked as utf8;

#[derive(Copy, Clone, Default, PartialEq)]
pub struct Latitude(pub i32);

impl Latitude {
    pub fn degrees(self) -> u8 {
        (self.0.abs() / 100_00000) as u8
    }

    pub fn minutes(self) -> u8 {
        ((self.0.abs() / 100000) % 100) as u8
    }

    pub fn seconds(self) -> u8 {
        ((self.0.abs() / 1000) % 100) as u8
    }

    pub fn sub_seconds(self) -> u16 {
        (self.0.abs() % 1000) as u16
    }

    pub fn is_north(self) -> bool {
        self.0 >= 0
    }

    pub fn is_south(self) -> bool {
        self.0 < 0
    }
}

impl From<&[u8]> for Latitude {
    fn from(bytes: &[u8]) -> Self {
        if bytes.len() == 0 {
            return Self::default();
        }
        let mut s = bytes.split(|&b| b == b'.');
        let mut integer = 0i32;
        if let Some(field) = s.next() {
            integer = unsafe { utf8(field) }.parse().unwrap_or(0);
        }
        let mut decimal = 0i32;
        if let Some(field) = s.next() {
            decimal = unsafe { utf8(field) }.parse().unwrap_or(0);
        }
        Self(integer * 100000 + decimal)
    }
}

impl core::fmt::Display for Latitude {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        let direction = if self.0 >= 0 { "N" } else { "S" };
        let degrees = self.degrees();
        let minutes = self.minutes();
        let seconds = self.seconds();
        let sub_seconds = self.sub_seconds();
        write!(f, "{}{:02}°{:02}'{:02}\"{:03}", direction, degrees, minutes, seconds, sub_seconds)
    }
}

impl core::fmt::Debug for Latitude {
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        write!(f, "{}", self)
    }
}