forked from argotorg/fe
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstring.fe
More file actions
114 lines (102 loc) · 3.15 KB
/
Copy pathstring.fe
File metadata and controls
114 lines (102 loc) · 3.15 KB
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
use super::ops::Eq
use super::num::IntDowncast
/// Fixed-size string utilities.
///
/// `String<N>` values are represented as a packed word and are left-padded with zero bytes.
/// The "effective length" of a string is defined as the number of bytes after removing leading
/// zero-padding from its `N`-byte representation.
impl<const N: usize> String<N> {
/// Returns the fixed-width byte representation of this string (including padding).
pub const fn as_bytes(self) -> [u8; N] {
let raw: u256 = self as u256
let width_bits: u256 = (N * 8) as u256
let mask: u256 = (1 << width_bits) - 1
let word: u256 = raw & mask
let mut out: [u8; N] = [0; N]
let mut i: usize = 0
while i < N {
let shift: u256 = ((N - 1 - i) * 8) as u256
out[i] = (word >> shift).downcast_truncate()
i += 1
}
out
}
/// Constructs a `String<N>` from its fixed-width byte representation (including padding).
pub const fn from_bytes(_ bytes: [u8; N]) -> Self {
let mut word: u256 = 0
let mut i: usize = 0
while i < N {
word = (word << 8) + (bytes[i] as u256)
i += 1
}
word as Self
}
/// Returns the effective (unpadded) length in bytes.
pub const fn len(self) -> usize {
let bytes: [u8; N] = self.as_bytes()
let mut i: usize = 0
while i < N {
if bytes[i] != 0 {
return N - i
}
i += 1
}
0
}
}
/// Concatenates two fixed-size strings using their effective (unpadded) lengths.
///
/// The result is left-padded with zeros to fill `OUT` bytes.
///
/// If `a.len() + b.len() > OUT`, the result is truncated on the right (i.e. it
/// keeps as much of `a` as possible, then as much of `b` as fits).
pub const fn concat<const A: usize, const B: usize, const OUT: usize>(
_ a: String<A>,
_ b: String<B>,
) -> String<OUT> {
let a_bytes: [u8; A] = a.as_bytes()
let b_bytes: [u8; B] = b.as_bytes()
let a_len: usize = a.len()
let b_len: usize = b.len()
let mut a_take: usize = a_len
if a_take > OUT {
a_take = OUT
}
let mut b_take: usize = b_len
if a_take + b_take > OUT {
b_take = OUT - a_take
}
let used: usize = a_take + b_take
let mut out: [u8; OUT] = [0; OUT]
let dst_base: usize = OUT - used
let a_src_base: usize = A - a_len
let b_src_base: usize = B - b_len
let mut i: usize = 0
while i < a_take {
out[dst_base + i] = a_bytes[a_src_base + i]
i += 1
}
let mut j: usize = 0
while j < b_take {
out[dst_base + a_take + j] = b_bytes[b_src_base + j]
j += 1
}
String::from_bytes(out)
}
impl<const N: usize> Eq for String<N> {
const fn eq(self, _ other: String<N>) -> bool {
let a: [u8; N] = self.as_bytes()
let b: [u8; N] = other.as_bytes()
let mut i: usize = 0
while i < N {
if a[i] != b[i] {
return false
}
i += 1
}
true
}
const fn ne(self, _ other: String<N>) -> bool {
!self.eq(other)
}
}