Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Construct PortableRegistry dynamically at runtime #164

Merged
merged 51 commits into from
Oct 7, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
8345a3c
WIP: allow constructing MetaTypes at runtime
ascjones Aug 11, 2022
3a14663
Remove fmt config options
ascjones Aug 11, 2022
1e03bd3
Add some docs
ascjones Aug 11, 2022
a68f28c
std feature String
ascjones Aug 11, 2022
da92e9d
fully qualified String
ascjones Aug 11, 2022
592736a
Fix features build
ascjones Aug 11, 2022
4500520
Generic string parameter for MetaType
ascjones Aug 15, 2022
a08ef8a
Remove license_template_path
ascjones Aug 15, 2022
3cacf78
Fmt
ascjones Aug 15, 2022
6476671
Fix fmt
ascjones Aug 15, 2022
6a1343b
Replace MetaFormString trait with cfg based string
ascjones Aug 16, 2022
42db0e3
Remove unused into
ascjones Aug 16, 2022
0c525c6
Fix more errors
ascjones Aug 16, 2022
7dfe55b
Now string types are the same across Meta/Portable, no longer necessa…
ascjones Aug 17, 2022
54ff5fc
Remove custom MetaType and TypeId
ascjones Aug 22, 2022
16e4e79
EXPERIMENT: make all type def fields public to allow construting Port…
ascjones Aug 22, 2022
c46186d
Rename test
ascjones Aug 22, 2022
5b47b1b
Fix up type ids in test
ascjones Aug 22, 2022
40b6047
Fix ui test
ascjones Aug 22, 2022
8255c99
*TEMPORARILY* pub registry for PortableType
ascjones Aug 23, 2022
79c19a9
add constructor for portableregistry
xermicus Aug 28, 2022
d8c3b5e
constructor for PortableType
xermicus Aug 28, 2022
0e4737f
implement remaining constructors for generic Form
xermicus Aug 28, 2022
8319875
make Type::new constructor public
xermicus Aug 28, 2022
ef4c3ee
make remaining constructor public
xermicus Aug 28, 2022
9e48542
add a new custom constructor for path
xermicus Sep 22, 2022
b900f54
Merge branch 'master' into aj/custom-meta-types
xermicus Sep 22, 2022
0b45a89
use new_custom in a test
xermicus Sep 22, 2022
6694dc0
Remove not required builder fn for MetaType
ascjones Sep 22, 2022
83a80ef
WIP propogate Form through builders
ascjones Oct 4, 2022
ae22be7
Fix up path builders
ascjones Oct 4, 2022
ababa57
More fixes
ascjones Oct 4, 2022
383399c
Fix up generated From impls
ascjones Oct 4, 2022
221c2f9
Fix up field builders
ascjones Oct 4, 2022
6caa3d6
Fix up field builder methods for MetaForm
ascjones Oct 4, 2022
a36540a
Rename constructor
ascjones Oct 4, 2022
b027ae8
Hide pub fields and add portable builder helper methods
ascjones Oct 4, 2022
1de0508
Fmt
ascjones Oct 4, 2022
f04d4ef
Explicity export PortableType
ascjones Oct 4, 2022
23c6cb9
Clippy
ascjones Oct 4, 2022
590bc58
Move PortableRegistry to own file, introduce PortableRegistryBuilder
ascjones Oct 5, 2022
b5b5a6f
Remove some stray `Str` type params
ascjones Oct 5, 2022
3c9d8dd
Implement PortableRegistryBuilder to manage ids
ascjones Oct 5, 2022
a2668a9
Default impl for PortableRegistryBuilder
ascjones Oct 5, 2022
220a59d
implement getter for registered types in PortableRegistryBuilder
xermicus Oct 6, 2022
07057ce
Rename new path constructor
ascjones Oct 7, 2022
07aaef8
Rename new_custom methods to new_portable
ascjones Oct 7, 2022
192d12c
Revert reordering of MetaForm
ascjones Oct 7, 2022
403c720
Move path construction back to MetaForm for non-breaking changes
ascjones Oct 7, 2022
1044c8d
Update path tests
ascjones Oct 7, 2022
c9149c2
TypeParameter::new_portable for non breaking change
ascjones Oct 7, 2022
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
Prev Previous commit
Next Next commit
Move PortableRegistry to own file, introduce PortableRegistryBuilder
  • Loading branch information
ascjones committed Oct 5, 2022
commit 590bc5857e13372de575fcb3f9b842f0664ecb8b
7 changes: 5 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ pub mod form;
mod impls;
pub mod interner;
mod meta_type;
mod portable;
mod registry;
mod ty;
mod utils;
Expand All @@ -347,10 +348,12 @@ pub use scale;

pub use self::{
meta_type::MetaType,
portable::{
PortableRegistry,
PortableRegistryBuilder,
},
registry::{
IntoPortable,
PortableRegistry,
PortableType,
Registry,
},
ty::*,
Expand Down
175 changes: 175 additions & 0 deletions src/portable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! The registry stores type definitions in a space-efficient manner.
//!
//! This is done by deduplicating common types in order to reuse their
//! definitions which otherwise can grow arbitrarily large. A type is uniquely
//! identified by its type identifier that is therefore used to refer to types
//! and their definitions.
//!
//! Types with the same name are uniquely identifiable by introducing
//! namespaces. The normal Rust namespace of a type is used, except for the Rust
//! prelude types that live in the so-called root namespace which is empty.

use crate::{
form::PortableForm,
prelude::{
fmt::Debug,
vec::Vec,
},
Registry,
Type,
};
use scale::Encode;

/// A read-only registry containing types in their portable form for serialization.
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(all(feature = "serde", feature = "decode"), derive(serde::Deserialize))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[derive(Clone, Debug, PartialEq, Eq, Encode)]
pub struct PortableRegistry {
types: Vec<PortableType>,
}

impl From<Registry> for PortableRegistry {
fn from(registry: Registry) -> Self {
PortableRegistry {
types: registry
.types()
.map(|(k, v)| {
PortableType {
id: k.id(),
ty: v.clone(),
}
})
.collect::<Vec<_>>(),
}
}
}

impl PortableRegistry {
/// Construct a new `PortableRegistry` from custom types.
pub fn new_from_types(types: Vec<PortableType>) -> Self {
Self { types }
}

/// Returns the type definition for the given identifier, `None` if no type found for that ID.
pub fn resolve(&self, id: u32) -> Option<&Type<PortableForm>> {
self.types.get(id as usize).map(|ty| ty.ty())
}

/// Returns all types with their associated identifiers.
pub fn types(&self) -> &[PortableType] {
&self.types
}
}

/// Represent a type in it's portable form.
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(all(feature = "serde", feature = "decode"), derive(serde::Deserialize))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[derive(Clone, Debug, PartialEq, Eq, Encode)]
pub struct PortableType {
#[codec(compact)]
id: u32,
#[cfg_attr(feature = "serde", serde(rename = "type"))]
ty: Type<PortableForm>,
}

impl PortableType {
/// Construct a custom `PortableType`.
pub fn new(id: u32, ty: Type<PortableForm>) -> Self {
Self { id, ty }
}

/// Returns the index of the [`PortableType`].
pub fn id(&self) -> u32 {
self.id
}

/// Returns the type of the [`PortableType`].
pub fn ty(&self) -> &Type<PortableForm> {
&self.ty
}
}

/// Construct a [`PortableRegistry`].
pub struct PortableRegistryBuilder {

}

#[cfg(test)]
mod tests {
use crate::{
build::*,
prelude::vec,
*,
};
use super::*;

#[test]
fn type_ids_are_sequential() {
let mut registry = Registry::new();
registry.register_type(&MetaType::new::<u32>());
registry.register_type(&MetaType::new::<bool>());
registry.register_type(&MetaType::new::<Option<(u32, bool)>>());

let readonly: PortableRegistry = registry.into();

assert_eq!(4, readonly.types().len());

for (expected, ty) in readonly.types().iter().enumerate() {
assert_eq!(expected as u32, ty.id());
}
}

#[test]
fn construct_portable_registry() {
let mut types = Vec::new();

let u32_type_id = types.len() as u32;
types.push(PortableType::new(
u32_type_id,
Type::new(Path::default(), vec![], TypeDefPrimitive::U32, vec![]),
));

let vec_u32_type_id = types.len() as u32;
types.push(PortableType::new(
vec_u32_type_id,
Type::new(
Path::default(),
vec![],
TypeDefSequence::new(u32_type_id.into()),
vec![],
),
));

let composite_type_id = types.len() as u32;
let composite = Type::builder_portable()
.path(Path::new_custom(vec!["MyStruct".into()]))
.composite(
Fields::named()
.field_portable(|f| f.name("primitive".into()).ty(u32_type_id))
.field_portable(|f| f.name("vec_of_u32".into()).ty(vec_u32_type_id))
.field_portable(|f| {
f.name("self_referential".into()).ty(composite_type_id)
}),
);
types.push(PortableType::new(composite_type_id, composite));

let _registry = PortableRegistry::new_from_types(types);
}
}

92 changes: 4 additions & 88 deletions src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ use crate::{
meta_type::MetaType,
Type,
};
use scale::Encode;

/// Convert the type definition into the portable form using a registry.
pub trait IntoPortable {
Expand Down Expand Up @@ -73,7 +72,7 @@ pub struct Registry {
/// The database where registered types reside.
///
/// The contents herein is used for serlialization.
types: BTreeMap<UntrackedSymbol<core::any::TypeId>, Type<PortableForm>>,
types: BTreeMap<UntrackedSymbol<TypeId>, Type<PortableForm>>,
}

impl Default for Registry {
Expand Down Expand Up @@ -145,77 +144,10 @@ impl Registry {
.map(|i| i.into_portable(self))
.collect::<Vec<_>>()
}
}

/// A read-only registry containing types in their portable form for serialization.
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(all(feature = "serde", feature = "decode"), derive(serde::Deserialize))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[derive(Clone, Debug, PartialEq, Eq, Encode)]
pub struct PortableRegistry {
types: Vec<PortableType>,
}

impl From<Registry> for PortableRegistry {
fn from(registry: Registry) -> Self {
PortableRegistry {
types: registry
.types
.iter()
.map(|(k, v)| {
PortableType {
id: k.id(),
ty: v.clone(),
}
})
.collect::<Vec<_>>(),
}
}
}

impl PortableRegistry {
/// Construct a new `PortableRegistry` from custom types.
pub fn new_from_types(types: Vec<PortableType>) -> Self {
Self { types }
}

/// Returns the type definition for the given identifier, `None` if no type found for that ID.
pub fn resolve(&self, id: u32) -> Option<&Type<PortableForm>> {
self.types.get(id as usize).map(|ty| ty.ty())
}

/// Returns all types with their associated identifiers.
pub fn types(&self) -> &[PortableType] {
&self.types
}
}

/// Represent a type in it's portable form.
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
#[cfg_attr(all(feature = "serde", feature = "decode"), derive(serde::Deserialize))]
#[cfg_attr(any(feature = "std", feature = "decode"), derive(scale::Decode))]
#[derive(Clone, Debug, PartialEq, Eq, Encode)]
pub struct PortableType {
#[codec(compact)]
id: u32,
#[cfg_attr(feature = "serde", serde(rename = "type"))]
ty: Type<PortableForm>,
}

impl PortableType {
/// Construct a custom `PortableType`.
pub fn new(id: u32, ty: Type<PortableForm>) -> Self {
Self { id, ty }
}

/// Returns the index of the [`PortableType`].
pub fn id(&self) -> u32 {
self.id
}

/// Returns the type of the [`PortableType`].
pub fn ty(&self) -> &Type<PortableForm> {
&self.ty
/// Returns an iterator over the types with their keys
pub fn types(&self) -> impl Iterator<Item = (&UntrackedSymbol<TypeId>, &Type<PortableForm>)> {
self.types.iter()
}
}

Expand All @@ -230,22 +162,6 @@ mod tests {
TypeInfo,
};

#[test]
fn readonly_type_ids() {
let mut registry = Registry::new();
registry.register_type(&MetaType::new::<u32>());
registry.register_type(&MetaType::new::<bool>());
registry.register_type(&MetaType::new::<Option<(u32, bool)>>());

let readonly: PortableRegistry = registry.into();

assert_eq!(4, readonly.types().len());

for (expected, ty) in readonly.types().iter().enumerate() {
assert_eq!(expected as u32, ty.id());
}
}

#[test]
fn recursive_struct_with_references() {
#[allow(unused)]
Expand Down
38 changes: 0 additions & 38 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use crate::{
string::String,
vec,
},
registry::PortableType,
*,
};
use core::marker::PhantomData;
Expand Down Expand Up @@ -364,40 +363,3 @@ fn basic_enum_with_index() {

assert_type!(IndexedRustEnum, ty);
}

#[test]
fn construct_portable_registry() {
let mut types = Vec::new();

let u32_type_id = types.len() as u32;
types.push(PortableType::new(
u32_type_id,
Type::new(Path::default(), vec![], TypeDefPrimitive::U32, vec![]),
));

let vec_u32_type_id = types.len() as u32;
types.push(PortableType::new(
vec_u32_type_id,
Type::new(
Path::default(),
vec![],
TypeDefSequence::new(u32_type_id.into()),
vec![],
),
));

let composite_type_id = types.len() as u32;
let composite = Type::builder_portable()
.path(Path::new_custom(vec!["MyStruct".into()]))
.composite(
Fields::named()
.field_portable(|f| f.name("primitive".into()).ty(u32_type_id))
.field_portable(|f| f.name("vec_of_u32".into()).ty(vec_u32_type_id))
.field_portable(|f| {
f.name("self_referential".into()).ty(composite_type_id)
}),
);
types.push(PortableType::new(composite_type_id, composite));

let _registry = PortableRegistry::new_from_types(types);
}