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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! This module provides ways to identify chunks of memory.
//! 
//! It defines the trait [Identifier] and structs [Address], [Area] and [Cursor].

use std::hash::{Hash, Hasher};

use crate::data::atomic::Word;

/// A trait which means a type can transform into an `usize`.
pub trait Identifier: Hash {
    fn to_usize(&self) -> usize;
}

/// Describes an address in memory.
///
/// Addresses are 64 bits wide.
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct Address(u64);

impl Address {
    /// Creates a new [Address] from an [u64].
    ///
    /// ```
    /// use osiris_data::data::identification::Address;
    /// assert_eq!(Address::new(0), Address::default())
    /// ```
    pub const fn new(value: u64) -> Self {
        Self(value)
    }

    /// Gets the address value as an [u64].
    pub const fn to_u64(&self) -> u64 { self.0 }

    /// Creates a new [Address] from a [Word].
    pub const fn from_word(word: Word) -> Self { Self::new(word.to_u64()) }
    
    /// Creates a new [Address] from any [Identifier].
    pub fn from<T: Identifier>(identifier: T) -> Self { Self::new(identifier.to_usize() as u64) }

    /// Gets the address value as a machine's [Word] to manipulate it with memory.
    pub const fn to_word(&self) -> Word { Word::new(self.0) }

    /// Increment the address value.
    pub fn increment(&mut self) {
        self.0 += 1;
    }

    /// Returns a new Address with an offset.
    pub fn offset(&self, offset: u64) -> Address { Address(self.0 + offset) }
}

impl Hash for Address {
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write(&self.0.to_be_bytes());
    }
}

impl Identifier for Address {
    /// Gets the address value as an [usize].
    fn to_usize(&self) -> usize { self.to_u64() as usize }
}

/// A pointer to a region in memory.
#[derive(Copy, Clone)]
pub struct Area {
    start: Address,
    len: usize,
    count: usize,
}

impl Area {
    /// Creates a new area with specified item size (how many 64 bits values describes one element of the area).
    pub fn new(start: Address, item_size: usize, item_count: usize) -> Self {
        Self { start, len: item_size, count: item_count }
    }

    /// A one-sized cell area.
    pub fn region(start: Address, count: usize) -> Self { Self::new(start, 1, count) }
    pub fn from(start: Address, end: Address) -> Self {
        if start > end {
            panic!("start > end")
        }
        Self::new(start, 1, end.to_usize() - start.to_usize())
    }

    pub fn count(&self) -> usize { self.count }
    pub fn size(&self) -> usize { self.offset(self.count) }
    pub fn is_null(&self) -> bool { self.size() == 0 }
    pub fn start(&self) -> Address { self.start }
    pub fn end(&self) -> Address { self.start.offset(self.size() as u64) }

    pub fn constraint(&self, pointer: Address) -> Address {
        match pointer {
            Address(addr) if addr < self.start.to_u64() => self.start,
            Address(addr) if addr > self.end().to_u64() => self.end(),
            address => address
        }
    }

    pub fn offset(&self, index: usize) -> usize { self.len * index }
    
    pub fn next_address(&self, cursor: Address) -> Address {
        let cursor = cursor.offset(self.offset(1) as u64);
        self.constraint(cursor)
    }
    
}

/// A managed foreach-pointer to a region in memory.
/// 
/// TODO
#[derive(Copy, Clone)]
pub struct Cursor {
    pub area: Area,
    pub pointer: Address,
}

impl Cursor {
    /// Return the next address in the area.
    pub fn next(&self) -> Address { self.area.next_address(self.pointer) }
    
    /// Return the next address in the area.
    pub fn advance(&mut self) { 
        self.pointer = self.next();
    }
}