use super::*;
use alloc::borrow::ToOwned;
use sp_core::{ConstU32, Get};
type ConstU32Max = ConstU32<{ u32::MAX }>;
pub type UnboundedBytes = BoundedBytesString<BytesKind, ConstU32Max>;
pub type BoundedBytes<S> = BoundedBytesString<BytesKind, S>;
pub type UnboundedString = BoundedBytesString<StringKind, ConstU32Max>;
pub type BoundedString<S> = BoundedBytesString<StringKind, S>;
trait Kind {
fn signature() -> String;
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BytesKind;
impl Kind for BytesKind {
fn signature() -> String {
String::from("bytes")
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct StringKind;
impl Kind for StringKind {
fn signature() -> String {
String::from("string")
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct BoundedBytesString<K, S> {
data: Vec<u8>,
_phantom: PhantomData<(K, S)>,
}
impl<K: Kind, S: Get<u32>> Clone for BoundedBytesString<K, S> {
fn clone(&self) -> Self {
Self {
data: self.data.clone(),
_phantom: PhantomData,
}
}
}
impl<K, S: Get<u32>> BoundedBytesString<K, S> {
pub fn as_bytes(&self) -> &[u8] {
&self.data
}
pub fn as_str(&self) -> Result<&str, sp_std::str::Utf8Error> {
sp_std::str::from_utf8(&self.data)
}
}
impl<K: Kind, S: Get<u32>> Codec for BoundedBytesString<K, S> {
fn read(reader: &mut Reader) -> MayRevert<Self> {
let mut inner_reader = reader.read_pointer()?;
let array_size: usize = inner_reader
.read::<U256>()
.map_err(|_| RevertReason::read_out_of_bounds("length"))?
.try_into()
.map_err(|_| RevertReason::value_is_too_large("length"))?;
if array_size > S::get() as usize {
return Err(RevertReason::value_is_too_large("length").into());
}
let range = inner_reader.move_cursor(array_size)?;
let data = inner_reader
.input
.get(range)
.ok_or_else(|| RevertReason::read_out_of_bounds(K::signature()))?;
let bytes = Self {
data: data.to_owned(),
_phantom: PhantomData,
};
Ok(bytes)
}
fn write(writer: &mut Writer, value: Self) {
let value: Vec<_> = value.into();
let length = value.len();
let chunks = length / 32;
let padded_size = match length % 32 {
0 => chunks * 32,
_ => (chunks + 1) * 32,
};
let mut value = value.to_vec();
value.resize(padded_size, 0);
writer.write_pointer(
Writer::new()
.write(U256::from(length))
.write_raw_bytes(&value)
.build(),
);
}
fn has_static_size() -> bool {
false
}
fn signature() -> String {
K::signature()
}
}
impl<K, S> From<BoundedBytesString<K, S>> for Vec<u8> {
fn from(value: BoundedBytesString<K, S>) -> Self {
value.data
}
}
impl<K, S> From<Vec<u8>> for BoundedBytesString<K, S> {
fn from(value: Vec<u8>) -> Self {
Self {
data: value,
_phantom: PhantomData,
}
}
}
impl<K, S> From<&[u8]> for BoundedBytesString<K, S> {
fn from(value: &[u8]) -> Self {
Self {
data: value.to_vec(),
_phantom: PhantomData,
}
}
}
impl<K, S, const N: usize> From<[u8; N]> for BoundedBytesString<K, S> {
fn from(value: [u8; N]) -> Self {
Self {
data: value.to_vec(),
_phantom: PhantomData,
}
}
}
impl<K, S, const N: usize> From<&[u8; N]> for BoundedBytesString<K, S> {
fn from(value: &[u8; N]) -> Self {
Self {
data: value.to_vec(),
_phantom: PhantomData,
}
}
}
impl<K, S> TryFrom<BoundedBytesString<K, S>> for String {
type Error = alloc::string::FromUtf8Error;
fn try_from(value: BoundedBytesString<K, S>) -> Result<Self, Self::Error> {
alloc::string::String::from_utf8(value.data)
}
}
impl<K, S> From<&str> for BoundedBytesString<K, S> {
fn from(value: &str) -> Self {
Self {
data: value.as_bytes().into(),
_phantom: PhantomData,
}
}
}
impl<K, S> From<String> for BoundedBytesString<K, S> {
fn from(value: String) -> Self {
Self {
data: value.as_bytes().into(),
_phantom: PhantomData,
}
}
}