-
Notifications
You must be signed in to change notification settings - Fork 10
SCALE
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.
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
This annotation is used to enable the autoregistration feature in case of a manual implementation of a reader/writer.
@AutoRegister(types = MyClass.class)
public class MyClassScaleReader implements ScaleReader<MyClass> {
@Override
public MyClass read(@NonNull InputStream stream, ScaleReader<?>... readers) throws IOException {
// ...
}
}
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
@ScaleWriter
public class MyModel<T> {
private Boolean someBool;
public Boolean getSomeBool() {
return someBool;
}
public void setSomeBool(Boolean someBool) {
this.someBool = someBool;
}
private Optional<T> someOption;
public Optional<T> getSomeOption() {
return someOption;
}
public void setSomeOption(Optional<T> someOption) {
this.someOption = someOption;
}
}
Readers/writers generated this way are marked with @AutoRegister automatically.
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.
@ScaleReader
public class MyModel<T> {
@Scale(OptionBool.class)
private Optional<Boolean> optionBool;
@Scale(CompactInteger.class)
private Integer compactInteger;
@Scale
private T obj;
@ScaleGeneric(
template = "Option<I32>",
types = {
@Scale(Option.class),
@Scale(I32.class)
})
private Optional<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)
}
)
private Map<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"),
}
)
private Map<Integer, Result<Boolean, String>> mapNames;
@Ignore
private String ignored;
}