gear_subxt/utils/
static_type.rs

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