osiris_data/data/
identification.rs

1//! This module provides ways to identify chunks of memory.
2//!
3//! It defines the trait [Identifier] and structs [Address], [Area] and [Cursor].
4
5use std::hash::{Hash, Hasher};
6
7use crate::data::atomic::Word;
8
9/// A trait which means a type can transform into an `usize`.
10pub trait Identifier: Hash {
11    fn to_usize(&self) -> usize;
12}
13
14/// Describes an address in memory.
15///
16/// Addresses are 64 bits wide.
17#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd)]
18pub struct Address(u64);
19
20impl Address {
21    /// Creates a new [Address] from an [u64].
22    ///
23    /// ```
24    /// use osiris_data::data::identification::Address;
25    /// assert_eq!(Address::new(0), Address::default())
26    /// ```
27    pub const fn new(value: u64) -> Self {
28        Self(value)
29    }
30
31    /// Gets the address value as an [u64].
32    pub const fn to_u64(&self) -> u64 { self.0 }
33
34    /// Creates a new [Address] from a [Word].
35    pub const fn from_word(word: Word) -> Self { Self::new(word.to_u64()) }
36
37    /// Creates a new [Address] from any [Identifier].
38    pub fn from<T: Identifier>(identifier: T) -> Self { Self::new(identifier.to_usize() as u64) }
39
40    /// Gets the address value as a machine's [Word] to manipulate it with memory.
41    pub const fn to_word(&self) -> Word { Word::new(self.0) }
42
43    /// Increment the address value.
44    pub fn increment(&mut self) {
45        self.0 += 1;
46    }
47
48    /// Returns a new Address with an offset.
49    pub fn offset(&self, offset: u64) -> Address { Address(self.0 + offset) }
50}
51
52impl Hash for Address {
53    fn hash<H: Hasher>(&self, state: &mut H) {
54        state.write(&self.0.to_be_bytes());
55    }
56}
57
58impl Identifier for Address {
59    /// Gets the address value as an usize.
60    fn to_usize(&self) -> usize { self.to_u64() as usize }
61}
62
63/// A pointer to a region in memory.
64#[derive(Copy, Clone, Eq, PartialEq)]
65pub struct Area {
66    start: Address,
67    len: usize,
68    count: usize,
69}
70
71impl Area {
72    /// Creates a new area with specified item size (how many 64 bits values describes one element of the area).
73    pub fn new(start: Address, item_size: usize, item_count: usize) -> Self {
74        Self { start, len: item_size, count: item_count }
75    }
76
77    /// A one-sized cell area.
78    pub fn region(start: Address, count: usize) -> Self { Self::new(start, 1, count) }
79
80    /// Returns an area enclosing the specified addresses.
81    pub fn from(start: Address, end: Address) -> Self {
82        if start > end {
83            panic!("start > end")
84        }
85        Self::new(start, 1, end.to_usize() - start.to_usize())
86    }
87
88    /// Returns the number of [Address]es distinguished in this area.
89    pub fn count(&self) -> usize { self.count }
90
91    /// Returns the number of [Word]s contained in this area.
92    pub fn size(&self) -> usize { self.offset(self.count) }
93
94    /// Returns true if the size of the area is 0.
95    pub fn is_null(&self) -> bool { self.size() == 0 }
96
97    /// Returns the first [Address] of this area.
98    pub fn start(&self) -> Address { self.start }
99
100    /// Returns the last [Address] of this area.
101    pub fn end(&self) -> Address { self.start.offset(self.size() as u64) }
102
103    /// Bounds the specified address inside the area, so it is always a valid pointer to this area.
104    pub fn constraint(&self, pointer: Address) -> Address {
105        match pointer {
106            Address(addr) if addr < self.start.to_u64() => self.start,
107            Address(addr) if addr > self.end().to_u64() => self.end(),
108            address => address
109        }
110    }
111
112    /// Returns the offset of the `index`-th element.
113    pub fn offset(&self, index: usize) -> usize { self.len * index }
114
115    /// Returns the next constrained address following `cursor`.
116    pub fn next_address(&self, cursor: Address) -> Address {
117        let cursor = cursor.offset(self.offset(1) as u64);
118        self.constraint(cursor)
119    }
120}
121
122impl Hash for Area {
123    fn hash<H: Hasher>(&self, state: &mut H) {
124        state.write(&self.to_usize().to_be_bytes())
125    }
126}
127
128impl Identifier for Area {
129    /// Gets the address value as an usize.
130    fn to_usize(&self) -> usize { self.offset(0) }
131}
132
133/// A managed foreach-pointer to a region in memory.
134#[derive(Copy, Clone, Eq, PartialEq)]
135pub struct Cursor {
136    /// The [Area] the [Cursor] points to.
137    pub area: Area,
138    pointer: Address,
139}
140
141impl Cursor {
142    /// Creates a new cursor pointing at the `area` start.
143    pub fn new(area: Area) -> Self {
144        Self { area, pointer: area.start }
145    }
146    
147    /// Return the next address in the area.
148    pub fn next(&self) -> Address { self.area.next_address(self.pointer) }
149    
150    /// Returns the address currently pointed by the cursor.
151    pub fn current(&self) -> Address { self.pointer }
152
153    /// Sets the internal pointer to the next address in the area.
154    pub fn advance(&mut self) {
155        self.pointer = self.next();
156    }
157
158    /// Sets the internal pointer to the area start address.
159    pub fn reset(&mut self) { self.pointer = self.area.start; }
160}
161
162impl Hash for Cursor {
163    fn hash<H: Hasher>(&self, state: &mut H) {
164        state.write(&self.to_usize().to_be_bytes())
165    }
166}
167
168impl Identifier for Cursor {
169    /// Gets the current address value as an usize.
170    fn to_usize(&self) -> usize { self.current().to_usize() }
171}