1use jam_std_common::hash_raw;
2use jam_types::{Memo, ServiceId, MEMO_LEN};
3
4pub type Blob = Vec<u8>;
5
6#[derive(Clone, Debug)]
7#[allow(clippy::len_without_is_empty)]
8pub enum DataIdLen {
9 HashLen([u8; 32], usize),
10 Data(Vec<u8>),
11}
12
13impl DataIdLen {
14 pub fn hash(&self) -> [u8; 32] {
15 match self {
16 DataIdLen::HashLen(hash, _) => *hash,
17 DataIdLen::Data(data) => hash_raw(data),
18 }
19 }
20 pub fn len(&self) -> usize {
21 match self {
22 DataIdLen::HashLen(_, l) => *l,
23 DataIdLen::Data(data) => data.len(),
24 }
25 }
26 pub fn data(&self) -> Option<&[u8]> {
27 match self {
28 DataIdLen::HashLen(..) => None,
29 DataIdLen::Data(ref data) => Some(data),
30 }
31 }
32 pub fn into_data(self) -> Option<Vec<u8>> {
33 match self {
34 DataIdLen::HashLen(..) => None,
35 DataIdLen::Data(d) => Some(d),
36 }
37 }
38}
39
40pub fn data_id_len(s: &str) -> anyhow::Result<DataIdLen> {
41 match s {
42 _ if s.starts_with("0x") &&
43 s.len() > 67 &&
44 s.bytes().skip(2).take(64).all(|x| x.is_ascii_hexdigit()) &&
45 s.find(':') == Some(66) &&
46 s[67..].parse::<usize>().is_ok() =>
47 {
48 let mut hash = [0u8; 32];
49 for (i, c) in s.as_bytes()[2..66].chunks(2).enumerate() {
50 hash[i] = u8::from_str_radix(std::str::from_utf8(c)?, 16)?;
51 }
52 Ok(DataIdLen::HashLen(hash, s[67..].parse::<usize>().expect("see above")))
53 },
54 _ if s.len() > 65 &&
55 s.bytes().take(64).all(|x| x.is_ascii_hexdigit()) &&
56 s.find(':') == Some(64) &&
57 s[65..].parse::<usize>().is_ok() =>
58 {
59 let mut hash = [0u8; 32];
60 for (i, c) in s.as_bytes()[..64].chunks(2).enumerate() {
61 hash[i] = u8::from_str_radix(std::str::from_utf8(c)?, 16)?;
62 }
63 Ok(DataIdLen::HashLen(hash, s[65..].parse::<usize>().expect("see above")))
64 },
65 _ => Ok(DataIdLen::Data(blob(s)?)),
66 }
67}
68
69#[allow(dead_code)]
70#[derive(Clone, Debug)]
71pub enum DataId {
72 Hash([u8; 32]),
73 Data(Vec<u8>),
74}
75
76#[allow(dead_code)]
77#[allow(clippy::len_without_is_empty)]
78impl DataId {
79 pub fn hash(&self) -> [u8; 32] {
80 match self {
81 DataId::Hash(hash) => *hash,
82 DataId::Data(data) => hash_raw(data),
83 }
84 }
85 pub fn len(&self) -> Option<usize> {
86 match self {
87 DataId::Hash(_) => None,
88 DataId::Data(data) => Some(data.len()),
89 }
90 }
91 pub fn data(&self) -> Option<&[u8]> {
92 match self {
93 DataId::Hash(..) => None,
94 DataId::Data(ref data) => Some(data),
95 }
96 }
97}
98
99pub fn data_id(s: &str) -> anyhow::Result<DataId> {
100 match s {
101 _ if s.len() == 64 && s.bytes().all(|x| x.is_ascii_hexdigit()) => {
102 let mut hash = [0u8; 32];
103 for (i, c) in s.as_bytes().chunks(2).enumerate() {
104 hash[i] = u8::from_str_radix(std::str::from_utf8(c)?, 16)?;
105 }
106 Ok(DataId::Hash(hash))
107 },
108 _ if s.starts_with("0x") &&
109 s.len() == 66 &&
110 s.bytes().skip(2).all(|x| x.is_ascii_hexdigit()) =>
111 {
112 let mut hash = [0u8; 32];
113 for (i, c) in s.as_bytes().chunks(2).skip(1).enumerate() {
114 hash[i] = u8::from_str_radix(std::str::from_utf8(c)?, 16)?;
115 }
116 Ok(DataId::Hash(hash))
117 },
118 _ => Ok(DataId::Data(blob(s)?)),
119 }
120}
121
122pub fn blob(s: &str) -> anyhow::Result<Blob> {
123 match s {
124 _ if std::path::Path::new(s).exists() => Ok(std::fs::read(s)?),
125 _ if s.starts_with("0x") &&
126 s.len() % 2 == 0 &&
127 s.bytes().skip(2).all(|x| x.is_ascii_hexdigit()) =>
128 {
129 let mut inner = Vec::with_capacity((s.len() - 2) / 2);
130 for c in s.as_bytes()[2..].chunks(2) {
131 inner.push(u8::from_str_radix(std::str::from_utf8(c)?, 16)?);
132 }
133 Ok(inner)
134 },
135 _ => Ok(s.as_bytes().to_vec()),
136 }
137}
138
139pub fn gas(s: &str) -> anyhow::Result<u64> {
140 if s == "max" {
141 Ok(u64::MAX)
142 } else {
143 Ok(s.parse::<u64>()?)
144 }
145}
146
147pub fn memo(s: &str) -> anyhow::Result<Memo> {
148 match s {
149 _ if s.len() == MEMO_LEN * 2 && s.bytes().all(|x| x.is_ascii_hexdigit()) => {
150 let mut inner = Memo::default();
151 for (i, c) in s.as_bytes().chunks(2).enumerate() {
152 inner[i] = u8::from_str_radix(std::str::from_utf8(c)?, 16)?;
153 }
154 Ok(inner)
155 },
156 _ if s.len() <= MEMO_LEN => {
157 let mut inner = Memo::default();
158 inner.0[..s.len()].copy_from_slice(s.as_bytes());
159 Ok(inner)
160 },
161 _ => Err(anyhow::anyhow!("Memo too long")),
162 }
163}
164
165pub fn service_id(s: &str) -> anyhow::Result<ServiceId> {
166 Ok(ServiceId::from_str_radix(s, 16)?)
167}