subxt_core/utils/
static_type.rs

1// Copyright 2019-2024 Parity Technologies (UK) Ltd.
2// This file is dual-licensed as Apache-2.0 or GPL-3.0.
3// see LICENSE for license details.
4
5use codec::{Decode, Encode};
6use scale_decode::{IntoVisitor, TypeResolver, Visitor, visitor::DecodeAsTypeResult};
7use scale_encode::EncodeAsType;
8
9use alloc::vec::Vec;
10
11/// If the type inside this implements [`Encode`], this will implement [`scale_encode::EncodeAsType`].
12/// If the type inside this implements [`Decode`], this will implement [`scale_decode::DecodeAsType`].
13///
14/// In either direction, we ignore any type information and just attempt to encode/decode statically
15/// via the [`Encode`] and [`Decode`] implementations. This can be useful as an adapter for types which
16/// do not implement [`scale_encode::EncodeAsType`] and [`scale_decode::DecodeAsType`] themselves, but
17/// it's best to avoid using it where possible as it will not take into account any type information,
18/// and is thus more likely to encode or decode incorrectly.
19#[derive(Debug, Encode, Decode, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
20pub struct Static<T>(pub T);
21
22impl<T: Encode> EncodeAsType for Static<T> {
23    fn encode_as_type_to<R: TypeResolver>(
24        &self,
25        _type_id: R::TypeId,
26        _types: &R,
27        out: &mut Vec<u8>,
28    ) -> Result<(), scale_encode::Error> {
29        self.0.encode_to(out);
30        Ok(())
31    }
32}
33
34pub struct StaticDecodeAsTypeVisitor<T, R>(core::marker::PhantomData<(T, R)>);
35
36impl<T: Decode, R: TypeResolver> Visitor for StaticDecodeAsTypeVisitor<T, R> {
37    type Value<'scale, 'info> = Static<T>;
38    type Error = scale_decode::Error;
39    type TypeResolver = R;
40
41    fn unchecked_decode_as_type<'scale, 'info>(
42        self,
43        input: &mut &'scale [u8],
44        _type_id: R::TypeId,
45        _types: &'info R,
46    ) -> DecodeAsTypeResult<Self, Result<Self::Value<'scale, 'info>, Self::Error>> {
47        use scale_decode::{Error, visitor::DecodeError};
48        let decoded = T::decode(input)
49            .map(Static)
50            .map_err(|e| Error::new(DecodeError::CodecError(e).into()));
51        DecodeAsTypeResult::Decoded(decoded)
52    }
53}
54
55impl<T: Decode> IntoVisitor for Static<T> {
56    type AnyVisitor<R: TypeResolver> = StaticDecodeAsTypeVisitor<T, R>;
57    fn into_visitor<R: TypeResolver>() -> StaticDecodeAsTypeVisitor<T, R> {
58        StaticDecodeAsTypeVisitor(core::marker::PhantomData)
59    }
60}
61
62// Make it easy to convert types into Static where required.
63impl<T> From<T> for Static<T> {
64    fn from(value: T) -> Self {
65        Static(value)
66    }
67}
68
69// Static<T> is just a marker type and should be as transparent as possible:
70impl<T> core::ops::Deref for Static<T> {
71    type Target = T;
72    fn deref(&self) -> &Self::Target {
73        &self.0
74    }
75}
76
77impl<T> core::ops::DerefMut for Static<T> {
78    fn deref_mut(&mut self) -> &mut Self::Target {
79        &mut self.0
80    }
81}