bittensor_core/codec/
batch.rs1#![allow(clippy::indexing_slicing)]
13
14#[cfg(feature = "host")]
15use rayon::prelude::*;
16
17use crate::codec::value::Value;
18use crate::error::CoreError;
19use crate::runtime::type_string::TypeSpec;
20use crate::runtime::{Runtime, StorageInfo};
21
22pub const PARALLEL_THRESHOLD: usize = 64;
24
25pub type DecodedPair = (Vec<Value>, Value);
27
28#[cfg(feature = "host")]
32fn run_indexed<T: Send>(
33 len: usize,
34 f: impl Fn(usize) -> Result<T, CoreError> + Sync,
35) -> Result<Vec<T>, CoreError> {
36 if len >= PARALLEL_THRESHOLD {
37 (0..len).into_par_iter().map(&f).collect()
38 } else {
39 (0..len).map(f).collect()
40 }
41}
42
43#[cfg(not(feature = "host"))]
44fn run_indexed<T: Send>(
45 len: usize,
46 f: impl Fn(usize) -> Result<T, CoreError> + Sync,
47) -> Result<Vec<T>, CoreError> {
48 (0..len).map(f).collect()
49}
50
51impl Runtime {
52 pub fn decode_batch(
56 &self,
57 type_strings: &[String],
58 datas: &[Vec<u8>],
59 ) -> Result<Vec<Value>, CoreError> {
60 if type_strings.len() != datas.len() {
61 return Err(CoreError::Codec(
62 "type_strings and datas must have the same length".into(),
63 ));
64 }
65 let mut specs: Vec<TypeSpec> = Vec::with_capacity(type_strings.len());
66 let mut last: Option<(&str, TypeSpec)> = None;
67 for type_string in type_strings {
68 let spec = match &last {
69 Some((s, spec)) if *s == type_string.as_str() => spec.clone(),
70 _ => {
71 let spec = self.type_spec(type_string)?;
72 last = Some((type_string.as_str(), spec.clone()));
73 spec
74 }
75 };
76 specs.push(spec);
77 }
78 run_indexed(datas.len(), |i| {
79 self.decode_spec(&specs[i], &datas[i], true)
80 })
81 }
82
83 pub fn decode_map_page(
87 &self,
88 entry: &StorageInfo,
89 raw_keys: &[Vec<u8>],
90 raw_values: &[Vec<u8>],
91 fixed: usize,
92 ) -> Result<Vec<DecodedPair>, CoreError> {
93 if raw_keys.len() != raw_values.len() {
94 return Err(CoreError::Codec(
95 "raw_keys and raw_values must have the same length".into(),
96 ));
97 }
98 let value_spec = TypeSpec::Id(entry.value_type);
99 run_indexed(raw_keys.len(), |i| {
100 let params = self.decode_storage_key_params(entry, &raw_keys[i], fixed)?;
101 let value = self.decode_spec(&value_spec, &raw_values[i], true)?;
102 Ok((params, value))
103 })
104 }
105
106 pub fn decode_map_changes(
112 &self,
113 entry: &StorageInfo,
114 changes: &[(String, Option<String>)],
115 fixed: usize,
116 ) -> Result<Vec<DecodedPair>, CoreError> {
117 let value_spec = TypeSpec::Id(entry.value_type);
118 let unhex = |s: &str| {
119 hex::decode(s.trim_start_matches("0x"))
120 .map_err(|e| CoreError::Codec(format!("bad hex in changes: {e}")))
121 };
122 let present: Vec<(&str, &str)> = changes
123 .iter()
124 .filter_map(|(k, v)| v.as_deref().map(|v| (k.as_str(), v)))
125 .collect();
126 run_indexed(present.len(), |i| {
127 let (key_hex, value_hex) = present[i];
128 let raw_key = unhex(key_hex)?;
129 let raw_value = unhex(value_hex)?;
130 let params = self.decode_storage_key_params(entry, &raw_key, fixed)?;
131 let value = self.decode_spec(&value_spec, &raw_value, true)?;
132 Ok((params, value))
133 })
134 }
135}