#![allow(clippy::indexing_slicing)]
#[cfg(feature = "host")]
use rayon::prelude::*;
use crate::codec::value::Value;
use crate::error::CoreError;
use crate::runtime::type_string::TypeSpec;
use crate::runtime::{Runtime, StorageInfo};
pub const PARALLEL_THRESHOLD: usize = 64;
pub type DecodedPair = (Vec<Value>, Value);
#[cfg(feature = "host")]
fn run_indexed<T: Send>(
len: usize,
f: impl Fn(usize) -> Result<T, CoreError> + Sync,
) -> Result<Vec<T>, CoreError> {
if len >= PARALLEL_THRESHOLD {
(0..len).into_par_iter().map(&f).collect()
} else {
(0..len).map(f).collect()
}
}
#[cfg(not(feature = "host"))]
fn run_indexed<T: Send>(
len: usize,
f: impl Fn(usize) -> Result<T, CoreError> + Sync,
) -> Result<Vec<T>, CoreError> {
(0..len).map(f).collect()
}
impl Runtime {
pub fn decode_batch(
&self,
type_strings: &[String],
datas: &[Vec<u8>],
) -> Result<Vec<Value>, CoreError> {
if type_strings.len() != datas.len() {
return Err(CoreError::Codec(
"type_strings and datas must have the same length".into(),
));
}
let mut specs: Vec<TypeSpec> = Vec::with_capacity(type_strings.len());
let mut last: Option<(&str, TypeSpec)> = None;
for type_string in type_strings {
let spec = match &last {
Some((s, spec)) if *s == type_string.as_str() => spec.clone(),
_ => {
let spec = self.type_spec(type_string)?;
last = Some((type_string.as_str(), spec.clone()));
spec
}
};
specs.push(spec);
}
run_indexed(datas.len(), |i| {
self.decode_spec(&specs[i], &datas[i], true)
})
}
pub fn decode_map_page(
&self,
entry: &StorageInfo,
raw_keys: &[Vec<u8>],
raw_values: &[Vec<u8>],
fixed: usize,
) -> Result<Vec<DecodedPair>, CoreError> {
if raw_keys.len() != raw_values.len() {
return Err(CoreError::Codec(
"raw_keys and raw_values must have the same length".into(),
));
}
let value_spec = TypeSpec::Id(entry.value_type);
run_indexed(raw_keys.len(), |i| {
let params = self.decode_storage_key_params(entry, &raw_keys[i], fixed)?;
let value = self.decode_spec(&value_spec, &raw_values[i], true)?;
Ok((params, value))
})
}
pub fn decode_map_changes(
&self,
entry: &StorageInfo,
changes: &[(String, Option<String>)],
fixed: usize,
) -> Result<Vec<DecodedPair>, CoreError> {
let value_spec = TypeSpec::Id(entry.value_type);
let unhex = |s: &str| {
hex::decode(s.trim_start_matches("0x"))
.map_err(|e| CoreError::Codec(format!("bad hex in changes: {e}")))
};
let present: Vec<(&str, &str)> = changes
.iter()
.filter_map(|(k, v)| v.as_deref().map(|v| (k.as_str(), v)))
.collect();
run_indexed(present.len(), |i| {
let (key_hex, value_hex) = present[i];
let raw_key = unhex(key_hex)?;
let raw_value = unhex(value_hex)?;
let params = self.decode_storage_key_params(entry, &raw_key, fixed)?;
let value = self.decode_spec(&value_spec, &raw_value, true)?;
Ok((params, value))
})
}
}