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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
//! This module defines [Word] and [HalfWord].

/// Describes the machine's base type. Every base operation occurs on this type.
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct Word(u64);

/// Describes a half-word. This type is the half of the size of [Word].
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct HalfWord(u32);

impl HalfWord {
    /// Creates a new half-word from its 32 bits value.
    pub const fn new(value: u32) -> Self {
        Self(value)
    }

    /// Returns a 32 bits value representing the half-word.
    pub const fn to_u32(&self) -> u32 { self.0 }

    /// Returns a 64 bits value representing the half-word. The 32 bits on the top (left) are always zeros.
    pub const fn to_u64(&self) -> u64 { self.0 as u64 }
}

impl Word {
    /// Creates a new word from its 64 bits value.
    pub const fn new(value: u64) -> Self {
        Self(value)
    }
    /// Creates a new word from its 64 bits value.
    pub const fn from_usize(value: usize) -> Self {
        Self(value as u64)
    }
    
    /// Create a native endian integer value from its representation as a byte array in big endian.
    pub const fn from_be_bytes(value: [u8; 8]) -> Self {
        Self::new(u64::from_be_bytes(value))
    }

    /// Creates a new word from two half-words.
    pub const fn merge(top: HalfWord, bottom: HalfWord) -> Self {
        Self(top.to_u64() << 32 | bottom.to_u64())
    }

    /// Returns a 64 bits value representing the word.
    pub const fn to_u64(&self) -> u64 { self.0 }
    
    /// Return the memory representation of this integer as a byte array in big-endian (network) byte order.
    pub const fn to_be_bytes(&self) -> [u8; 8] { self.0.to_be_bytes() }

    /// Returns two 32 bits half-words splitting the 64 bits word.
    pub const fn split(&self) -> [HalfWord; 2] {
        let top = (self.0 >> 32) as u32;
        let bottom = self.0 as u32;
        [HalfWord(top), HalfWord(bottom)]
    }

    /// Returns the 32 first left bits of the word.
    pub const fn top(&self) -> HalfWord {
        let [top, _] = self.split();
        top
    }

    /// Returns the 32 last right bits of the word.
    pub const fn bottom(&self) -> HalfWord {
        let [_, bottom] = self.split();
        bottom
    }
}

impl HalfWord {
    /// Merges the current [HalfWord] with another into a whole [Word].
    ///
    /// The current half-word is the top of the new word while `other` is the bottom.
    ///
    /// ### Example
    /// ```
    /// use osiris_data::data::atomic::{HalfWord, Word};
    ///
    /// let top = HalfWord::default();
    /// let bottom = HalfWord::default();
    ///
    /// let whole: Word = top.with(bottom);
    ///
    /// let [top, bottom] = whole.split();
    ///
    /// let whole = Word::merge(top, bottom);
    /// ```
    pub const fn with(self, other: HalfWord) -> Word {
        Word::merge(self, other)
    }
}