Skip to content
Ishinka edited this page May 9, 2022 · 2 revisions

This is a Java implementation of the Substrate SCALE Codec.

The SCALE (Simple Concatenated Aggregate Little-Endian) Codec is a lightweight, efficient, binary serialization and deserialization codec.

SCALE is used in many different ways:

  • serialization of parameters in RPC methods and subscriptions;
  • deserialization of results in RPC methods and subscriptions;
  • serialization of parameters in transactions;
  • serialization of keys in storage items;
  • deserialization values of storage items.

This component includes abstractions for (de-)serialization entities from/to SCALE and tools which help to generate corresponding (de-)serializers, which we call scale readers and scale writers.

Registries

Scale readers and writers are stored in two corresponding registries ScaleReaderRegistry and ScaleWriterRegistry. These registries are singletons implementing the following methods:

  • register() used for reader/writer registration
  • resolve() resolves a previously registered reader/writer by a class
  • registerAnnotatedFrom() to automatically register all the readers/writers marked by @AutoRegister annotation.

By default registries come with support for the following types:

  • Boolean
  • Byte
  • Short
  • Integer
  • Long
  • BigInteger
  • Optional
  • Result
  • String
  • List
  • Void

Annotations

@AutoRegister

This annotation is used to enable the autoregistration feature in case of a manual implementation of a reader/writer.

@AutoRegister(types = MyClass.class)
publicclassMyClassScaleReaderimplementsScaleReader<MyClass> {
@OverridepublicMyClassread(@NonNullInputStreamstream, ScaleReader<?>... readers) throwsIOException {
// ...
}
}

@ScaleReader, @ScaleWriter

The @ScaleReader, @ScaleWriter annotations are used to automatically generate SCALE readers/writers for models marked with it. If the proper readers/writers can be resolved from the registries using the types of the fields, then no extra annotations are needed.

@ScaleReader@ScaleWriterpublicclassMyModel<T> {
privateBooleansomeBool;
publicBooleangetSomeBool() {
returnsomeBool;
}
publicvoidsetSomeBool(BooleansomeBool) {
this.someBool = someBool;
} privateOptional<T> someOption;
publicOptional<T> getSomeOption() {
returnsomeOption;
}
publicvoidsetSomeOption(Optional<T> someOption) {
this.someOption = someOption;
}
}

Readers/writers generated this way are marked with @AutoRegister automatically.

@Scale, @ScaleGeneric, @Ignore

The @Scale, @ScaleGeneric and @Ignore annotations are used on a model's fields to provide hints for the automatic generation of readers/writers.

  • @Scale specifies a particular reader/writer that will be resolved from the registry for a marked field. If used without arguments, the type of the marked field is used.
  • @ScaleGeneric specifies particular readers/writers for the fields with generic types.
  • @Ignore tells the generator to skip the marked field during the SCALE encoding/decoding process.
@ScaleReaderpublicclassMyModel<T> {
@Scale(OptionBool.class)
privateOptional<Boolean> optionBool;
@Scale(CompactInteger.class)
privateIntegercompactInteger;
@ScaleprivateTobj;
@ScaleGeneric(
template = "Option<I32>",
types = {
@Scale(Option.class),
@Scale(I32.class)
})
privateOptional<Integer> optionI32;
@ScaleGeneric(
template = "Map<Vec<?>, Result<OptionBool, String>>",
types = {
@Scale(Map.class),
@Scale(Vec.class),
@Scale(ScaleType.OptionBool.class),
@Scale(Result.class),
@Scale(String.class)
}
)
privateMap<List<T>, Result<Optional<Boolean>, String>> mapTypes;
@ScaleGeneric(
template = "map<int, result>",
types = {
@Scale(value = Map.class, name = "map"),
@Scale(value = ScaleType.I32.class, name = "int"),
@Scale(name = "result"),
}
)
privateMap<Integer, Result<Boolean, String>> mapNames;
@IgnoreprivateStringignored; }

Clone this wiki locally