chainql_core/
hex.rs

1use std::{borrow::Borrow, ops::Deref};
2
3use jrsonnet_evaluator::{
4	function::builtin,
5	runtime_error,
6	typed::{CheckType, ComplexValType, Typed, ValType},
7	Result, Val,
8};
9
10use crate::ensure;
11
12#[derive(Eq, Ord, PartialEq, PartialOrd)]
13#[repr(transparent)]
14pub struct Hex(pub Vec<u8>);
15impl Hex {
16	pub fn encode_str(str: &str) -> Self {
17		Self(str.as_bytes().into())
18	}
19}
20impl Typed for Hex {
21	const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);
22
23	fn into_untyped(typed: Self) -> Result<Val> {
24		Ok(Val::Str(to_hex(&typed.0).into()))
25	}
26
27	fn from_untyped(untyped: Val) -> Result<Self> {
28		Self::TYPE.check(&untyped)?;
29		let str = untyped.as_str().expect("is string");
30		Ok(Self(from_hex(&str)?))
31	}
32}
33impl Borrow<[u8]> for Hex {
34	fn borrow(&self) -> &[u8] {
35		&self.0
36	}
37}
38impl Deref for Hex {
39	type Target = [u8];
40
41	fn deref(&self) -> &Self::Target {
42		self.0.as_slice()
43	}
44}
45
46/// Convert an array of bytes to a hex string.
47pub fn to_hex(data: &[u8]) -> String {
48	let mut out = vec![0; data.len() * 2 + 2];
49	out[0] = b'0';
50	out[1] = b'x';
51	hex::encode_to_slice(data, &mut out[2..]).expect("size is correct");
52	String::from_utf8(out).expect("hex is utf-8 compatible")
53}
54
55/// Convert a hex string to a vector of bytes.
56pub fn from_hex(data: &str) -> Result<Vec<u8>> {
57	ensure!(data.starts_with("0x"), "string doesn't starts with 0x");
58	let out = hex::decode(&data.as_bytes()[2..])
59		.map_err(|e| runtime_error!("failed to decode hex: {e}"))?;
60	Ok(out)
61}
62
63/// Convert an array of bytes to a hex string.
64///
65/// This function is passed to Jsonnet and is callable from the code.
66///
67/// # Example
68///
69/// ```text
70/// cql.toHex([0, 0, 0, 2, 16, 62, 200, 1]) == "0x00000002103ec801"
71/// ```
72#[builtin]
73pub fn builtin_to_hex(data: Vec<u8>) -> Result<Hex> {
74	Ok(Hex(data))
75}
76
77/// Convert a hex string to a vector of bytes.
78///
79/// This function is passed to Jsonnet and is callable from the code.
80///
81/// # Example
82///
83/// ```text
84/// cql.fromHex("0x00000002103ec801") == [0, 0, 0, 2, 16, 62, 200, 1]
85/// ```
86#[builtin]
87pub fn builtin_from_hex(data: Hex) -> Vec<u8> {
88	data.0
89}