-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHex.mo
128 lines (117 loc) · 3.6 KB
/
Hex.mo
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
127
128
//https://github.com/aviate-labs/encoding.mo/blob/main/src/Hex.mo
import Array "mo:base/Array";
import Blob "mo:base/Blob";
import Char "mo:base/Char";
import Hash "mo:base/Hash";
import Iter "mo:base/Iter";
import Nat8 "mo:base/Nat8";
import Result "mo:base/Result";
import Text "mo:base/Text";
module {
private let base : Nat8 = 16;
private let hex : [Char] = [
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'a',
'b',
'c',
'd',
'e',
'f',
];
private func toLower(c : Char) : Char {
switch (c) {
case ('A') { 'a' };
case ('B') { 'b' };
case ('C') { 'c' };
case ('D') { 'd' };
case ('E') { 'e' };
case ('F') { 'f' };
case (_) { c };
};
};
public type Hex = Text;
// Checks whether two hex strings are equal.
public func equal(a : Hex, b : Hex) : Bool {
if (a.size() != b.size()) return false;
let a_ = Text.map(a, toLower);
let b_ = Text.map(b, toLower);
Text.equal(a_, b_);
};
// Hashes the given hex text.
// NOTE: assumes the text is valid hex: [0-9a-fA-F].
public func hash(h : Hex) : Hash.Hash {
switch (decode(h)) {
case (#err(_)) { assert (false); 0 };
case (#ok(r)) { Blob.hash(Blob.fromArray(r)) };
};
};
// Checks whether the given hex text is valid hex.
public func valid(h : Hex) : Bool {
for (c in h.chars()) {
for (i in hex.keys()) {
let h = hex[i];
if (h != c and h != toLower(c)) {
return false;
};
};
};
true;
};
// Converts a byte to its corresponding hexidecimal format.
public func encodeByte(n : Nat8) : Hex {
let c0 = hex[Nat8.toNat(n / base)];
let c1 = hex[Nat8.toNat(n % base)];
Char.toText(c0) # Char.toText(c1);
};
// Converts an array of bytes to their corresponding hexidecimal format.
public func encode(ns : [Nat8]) : Hex {
Array.foldRight<Nat8, Hex>(
ns,
"",
func(n : Nat8, acc : Hex) : Hex {
encodeByte(n) # acc;
},
);
};
// Converts the given hexadecimal character to its corresponding binary format.
// NOTE: a hexadecimal char is just an 4-bit natural number.
public func decodeChar(c : Char) : Result.Result<Nat8, Text> {
for (i in hex.keys()) {
let h = hex[i];
if (h == c or h == toLower(c)) {
return #ok(Nat8.fromNat(i));
};
};
#err("unexpected character: " # Char.toText(c));
};
// Converts the given hexidecimal text to its corresponding binary format.
public func decode(t : Hex) : Result.Result<[Nat8], Text> {
let t_ = if (t.size() % 2 == 0) { t } else { "0" # t };
let cs = Iter.toArray(t_.chars());
let ns = Array.init<Nat8>(t_.size() / 2, 0);
for (i in Iter.range(0, ns.size() - 1)) {
let j : Nat = i * 2;
switch (decodeChar(cs[j])) {
case (#err(e)) { return #err(e) };
case (#ok(x0)) {
switch (decodeChar(cs[j +1])) {
case (#err(e)) { return #err(e) };
case (#ok(x1)) {
ns[i] := x0 * base + x1;
};
};
};
};
};
#ok(Array.freeze(ns));
};
};