Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ The format is based on [Keep a Changelog].

[Keep a Changelog]: http://keepachangelog.com/en/1.0.0/

## 0.12.1 (2025-11-12)

- Add `map_ids()` functions to `RuntimeApiInfo`, `StorageInfo` and `ViewFunctionInfo` to make translating the `TypeId` parameter simpler.
This adds a `'static` bound to `StorageInfo` type IDs, but it is not expected that this will break anything as this is already the case for `u32` and `LookupName` IDs (and is required in many other places).

## 0.12.0 (2025-11-10)

- Bump to scale-info-legacy 0.3.0.
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "frame-decode"
version = "0.12.0"
version = "0.12.1"
edition = "2024"
description = "Decode extrinsics and storage from Substrate based chains"
license = "Apache-2.0"
Expand Down
39 changes: 38 additions & 1 deletion src/methods/runtime_api_type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use super::Entry;
use crate::utils::Either;
use alloc::borrow::Cow;
use alloc::borrow::ToOwned;
use alloc::string::String;
use alloc::string::{String, ToString};
use alloc::vec::Vec;

/// This can be implemented for anything capable of providing Runtime API type information.
/// It is implemented for newer versions of frame-metadata (V15 and above).
Expand Down Expand Up @@ -93,6 +94,42 @@ impl<'info, TypeId: Clone + 'static> RuntimeApiInfo<'info, TypeId> {
output_id: self.output_id,
}
}

/// Map the type IDs in this [`RuntimeApiInfo`], returning a new one or bailing early with an error if something goes wrong.
/// This also takes ownership of the [`RuntimeApiInfo`], turning the lifetime to static.
pub fn map_ids<NewTypeId: Clone, E, F: FnMut(TypeId) -> Result<NewTypeId, E>>(
self,
mut f: F,
) -> Result<RuntimeApiInfo<'static, NewTypeId>, E> {
let new_output_id = f(self.output_id)?;
let mut new_inputs = Vec::with_capacity(self.inputs.len());

match self.inputs {
Cow::Borrowed(inputs) => {
for input in inputs {
new_inputs.push(RuntimeApiInput {
// We always have to allocate if inputs is borrowed:
name: Cow::Owned(input.name.to_string()),
id: f(input.id.clone())?,
});
}
}
Cow::Owned(inputs) => {
for input in inputs {
new_inputs.push(RuntimeApiInput {
// If inputs is owned, we only allocate if name is borrowed:
name: Cow::Owned(input.name.into_owned()),
id: f(input.id.clone())?,
});
}
}
}

Ok(RuntimeApiInfo {
inputs: Cow::Owned(new_inputs),
output_id: new_output_id,
})
}
}

/// Information about a specific input value to a Runtime API.
Expand Down
25 changes: 24 additions & 1 deletion src/methods/storage_type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ pub struct StorageInfo<'info, TypeId: Clone> {
pub default_value: Option<Cow<'info, [u8]>>,
}

impl<'info, TypeId: Clone> StorageInfo<'info, TypeId> {
impl<'info, TypeId: Clone + 'static> StorageInfo<'info, TypeId> {
/// Take ownership of this [`StorageInfo`], turning any lifetimes to `'static`.
pub fn into_owned(self) -> StorageInfo<'static, TypeId> {
StorageInfo {
Expand All @@ -140,6 +140,29 @@ impl<'info, TypeId: Clone> StorageInfo<'info, TypeId> {
default_value: self.default_value.map(|v| Cow::Owned(v.into_owned())),
}
}

/// Map the type IDs in this [`StorageInfo`], returning a new one or bailing early with an error if something goes wrong.
/// This also takes ownership of the [`StorageInfo`], turning the lifetime to static.
pub fn map_ids<NewTypeId: Clone, E, F: FnMut(TypeId) -> Result<NewTypeId, E>>(
self,
mut f: F,
) -> Result<StorageInfo<'static, NewTypeId>, E> {
let new_value_id = f(self.value_id)?;
let mut new_keys = Vec::with_capacity(self.keys.len());

for k in self.keys.iter() {
new_keys.push(StorageKeyInfo {
hasher: k.hasher,
key_id: f(k.key_id.clone())?,
});
}

Ok(StorageInfo {
keys: Cow::Owned(new_keys),
value_id: new_value_id,
default_value: self.default_value.map(|d| Cow::Owned(d.into_owned())),
})
}
}

/// Information about a single key within a storage entry.
Expand Down
40 changes: 39 additions & 1 deletion src/methods/view_function_type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use super::Entry;
use crate::utils::Either;
use alloc::borrow::Cow;
use alloc::borrow::ToOwned;
use alloc::string::String;
use alloc::string::{String, ToString};
use alloc::vec::Vec;

/// This is implemented for anything capable of providing information about view functions
/// (primarily metadata V16 and onwards).
Expand Down Expand Up @@ -96,6 +97,43 @@ impl<'info, TypeId: Clone> ViewFunctionInfo<'info, TypeId> {
output_id: self.output_id,
}
}

/// Map the type IDs in this [`ViewFunctionInfo`], returning a new one or bailing early with an error if something goes wrong.
/// This also takes ownership of the [`ViewFunctionInfo`], turning the lifetime to static.
pub fn map_ids<NewTypeId: Clone, E, F: FnMut(TypeId) -> Result<NewTypeId, E>>(
self,
mut f: F,
) -> Result<ViewFunctionInfo<'static, NewTypeId>, E> {
let new_output_id = f(self.output_id)?;
let mut new_inputs = Vec::with_capacity(self.inputs.len());

match self.inputs {
Cow::Borrowed(inputs) => {
for input in inputs {
new_inputs.push(ViewFunctionInput {
// We always have to allocate if inputs is borrowed:
name: Cow::Owned(input.name.to_string()),
id: f(input.id.clone())?,
});
}
}
Cow::Owned(inputs) => {
for input in inputs {
new_inputs.push(ViewFunctionInput {
// If inputs is owned, we only allocate if name is borrowed:
name: Cow::Owned(input.name.into_owned()),
id: f(input.id.clone())?,
});
}
}
}

Ok(ViewFunctionInfo {
query_id: self.query_id,
inputs: Cow::Owned(new_inputs),
output_id: new_output_id,
})
}
}

/// Information about a specific input value to a View Function.
Expand Down
Loading