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}
33
34pub fn data_id_len(s: &str) -> anyhow::Result<DataIdLen> {
35 match s {
36 _ if s.len() > 65 &&
37 s.bytes().take(64).all(|x| x.is_ascii_hexdigit()) &&
38 s.find(':') == Some(64) &&
39 s[65..].parse::<usize>().is_ok() =>
40 {
41 let mut hash = [0u8; 32];
42 for (i, c) in s.as_bytes()[..64].chunks(2).enumerate() {
43 hash[i] = u8::from_str_radix(std::str::from_utf8(c)?, 16)?;
44 }
45 Ok(DataIdLen::HashLen(hash, s[65..].parse::<usize>().expect("see above")))
46 },
47 _ => Ok(DataIdLen::Data(blob(s)?)),
48 }
49}
50
51#[allow(dead_code)]
52#[derive(Clone, Debug)]
53pub enum DataId {
54 Hash([u8; 32]),
55 Data(Vec<u8>),
56}
57
58#[allow(dead_code)]
59#[allow(clippy::len_without_is_empty)]
60impl DataId {
61 pub fn hash(&self) -> [u8; 32] {
62 match self {
63 DataId::Hash(hash) => *hash,
64 DataId::Data(data) => hash_raw(data),
65 }
66 }
67 pub fn len(&self) -> Option<usize> {
68 match self {
69 DataId::Hash(_) => None,
70 DataId::Data(data) => Some(data.len()),
71 }
72 }
73 pub fn data(&self) -> Option<&[u8]> {
74 match self {
75 DataId::Hash(..) => None,
76 DataId::Data(ref data) => Some(data),
77 }
78 }
79}
80
81#[allow(dead_code)]
82pub fn data_id(s: &str) -> anyhow::Result<DataId> {
83 match s {
84 _ if s.len() == 64 && s.bytes().all(|x| x.is_ascii_hexdigit()) => {
85 let mut hash = [0u8; 32];
86 for (i, c) in s.as_bytes().chunks(2).enumerate() {
87 hash[i] = u8::from_str_radix(std::str::from_utf8(c)?, 16)?;
88 }
89 Ok(DataId::Hash(hash))
90 },
91 _ => Ok(DataId::Data(blob(s)?)),
92 }
93}
94
95pub fn blob(s: &str) -> anyhow::Result<Blob> {
96 match s {
97 _ if (s.starts_with("./") || s.starts_with("/")) && std::path::Path::new(s).exists() =>
98 Ok(std::fs::read(s)?),
99 _ if s.starts_with("0x") &&
100 s.len() % 2 == 0 &&
101 s.bytes().skip(2).all(|x| x.is_ascii_hexdigit()) =>
102 {
103 let mut inner = Vec::with_capacity((s.len() - 2) / 2);
104 for c in s.as_bytes()[2..].chunks(2) {
105 inner.push(u8::from_str_radix(std::str::from_utf8(c)?, 16)?);
106 }
107 Ok(inner)
108 },
109 _ => Ok(s.as_bytes().to_vec()),
110 }
111}
112
113pub fn gas(s: &str) -> anyhow::Result<u64> {
114 if s == "max" {
115 Ok(u64::MAX)
116 } else {
117 Ok(s.parse::<u64>()?)
118 }
119}
120
121pub fn memo(s: &str) -> anyhow::Result<Memo> {
122 match s {
123 _ if s.len() == MEMO_LEN * 2 && s.bytes().all(|x| x.is_ascii_hexdigit()) => {
124 let mut inner = Memo::default();
125 for (i, c) in s.as_bytes().chunks(2).enumerate() {
126 inner[i] = u8::from_str_radix(std::str::from_utf8(c)?, 16)?;
127 }
128 Ok(inner)
129 },
130 _ if s.len() <= MEMO_LEN => {
131 let mut inner = Memo::default();
132 inner.0[..s.len()].copy_from_slice(s.as_bytes());
133 Ok(inner)
134 },
135 _ => Err(anyhow::anyhow!("Memo too long")),
136 }
137}
138
139pub fn service_id(s: &str) -> anyhow::Result<ServiceId> {
140 Ok(ServiceId::from_str_radix(s, 16)?)
141}