Skip to content

Commit 9ec93bb

Browse files
committed
Added custom encoding and decoding factory. Better Compact and BigInt types
1 parent e7d7f1d commit 9ec93bb

18 files changed

+507
-414
lines changed

README.md

+11-11
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ Setup instructions:
3535
Add this to the dependency section of your `Package.swift` manifest:
3636

3737
```Swift
38-
.package(url: "https://github.com/tesseract-one/swift-scale-codec.git", from: "0.1.0")
38+
.package(url: "https://github.com/tesseract-one/swift-scale-codec.git", from: "0.2.0")
3939
```
4040

4141
- **CocoaPods:** Put this in your `Podfile`:
4242

4343
```Ruby
44-
pod 'ScaleCodec', '~> 0.1'
44+
pod 'ScaleCodec', '~> 0.2'
4545
```
4646

4747
## Usage Examples
@@ -66,7 +66,7 @@ assert(uint32 == UInt32.max)
6666

6767
#### Compact encoding
6868

69-
`UInt[8-64]` and `BigUInt` types can be encoded with compact encoding. This allows `BigUInt` to store values up to `2^536-1`.
69+
`UInt[8-64]`, `SUInt[128-512]` and `BigUInt` types can be encoded with compact encoding. This allows `BigUInt` to store values up to `2^536-1`.
7070

7171
ScaleCodec has special wrapper type `SCompact` which encodes and decodes values in this format and two helper methods.
7272

@@ -77,7 +77,7 @@ import ScaleCodec
7777

7878
let data = Data([0x07, 0x00, 0x00, 0x00, 0x00, 0x01])
7979

80-
let encoded = try SCALE.default.encode(compact: UInt64(1 << 32))
80+
let encoded = try SCALE.default.encode(UInt64(1 << 32), .compact)
8181
assert(encoded == data))
8282

8383
let compact = try SCALE.default.decode(UInt64.self, .compact, from: data)
@@ -100,15 +100,15 @@ let data = Data([
100100
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
101101
])
102102

103-
let encoded = try SCALE.default.encode(b128: BigUInt(2).pow(128) - 1)
103+
let encoded = try SCALE.default.encode(BigUInt(2).pow(128) - 1, .b128)
104104
assert(encoded == data))
105105

106106
let compact = try SCALE.default.decode(BigUInt.self, .b128, from: data)
107107
assert(compact == BigUInt(2).pow(128) - 1)
108108

109109
// without helper methods
110110
// let encoded = try SCALE.default.encode(SUInt256(BigUInt(2).pow(128) - 1))
111-
// let compact = try SCALE.default.decode(SUInt256.self, from: data).value
111+
// let compact = try SCALE.default.decode(SUInt256.self, from: data).int
112112
```
113113

114114
#### Data fixed encoding
@@ -120,7 +120,7 @@ import ScaleCodec
120120

121121
let data = Data([0x07, 0x00, 0x00, 0x00, 0x00, 0x01]
122122

123-
let encoded = try SCALE.default.encoder().encode(data, fixed: 6).output
123+
let encoded = try SCALE.default.encoder().encode(data, .fixed(6)).output
124124
assert(encoded == data))
125125

126126
let decoded = try SCALE.default.decoder(data: encoded).decode(Data.self, .fixed(6))
@@ -152,7 +152,7 @@ import ScaleCodec
152152

153153
let array: [UInt32] = [1, 2, 3, 4, 5]
154154

155-
let data = try SCALE.default.encode(array, fixed: 5)
155+
let data = try SCALE.default.encode(array, .fixed(5))
156156

157157
let decoded: [UInt32] = try SCALE.default.decode(.fixed(5), from: data)
158158

@@ -223,8 +223,8 @@ enum Test: ScaleCodable {
223223

224224
func encode(in encoder: ScaleEncoder) throws {
225225
switch self {
226-
case .A(let str): try encoder.encode(enumCaseId: 0).encode(str)
227-
case .B(let int, let str): try encoder.encode(enumCaseId: 1).encode(compact: int).encode(str)
226+
case .A(let str): try encoder.encode(0, .enumCaseId).encode(str)
227+
case .B(let int, let str): try encoder.encode(1, .enumCaseId).encode(int, .compact).encode(str)
228228
}
229229
}
230230
}
@@ -263,7 +263,7 @@ struct Test: ScaleCodable, Equatable {
263263
func encode(in encoder: ScaleEncoder) throws {
264264
try encoder
265265
.encode(var1)
266-
.encode(compact: var2)
266+
.encode(var2, .compact)
267267
.encode(var3.map { SCompact($0) })
268268
}
269269
}

ScaleCodec.podspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'ScaleCodec'
3-
s.version = '0.1.1'
3+
s.version = '0.2.0'
44
s.summary = 'SCALE codec implementation for Swift language'
55

66
s.description = <<-DESC

Sources/ScaleCodec/Array.swift

+60-79
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ extension Array: ScaleContainerEncodable {
1111
public typealias EElement = Element
1212

1313
public func encode(in encoder: ScaleEncoder, writer: @escaping (EElement, ScaleEncoder) throws -> Void) throws {
14-
try encoder.encode(compact: UInt32(count))
14+
try encoder.encode(UInt32(count), .compact)
1515
for element in self {
1616
try writer(element, encoder)
1717
}
@@ -36,96 +36,77 @@ extension Array: ScaleEncodable where Element: ScaleEncodable {}
3636

3737
extension Array: ScaleDecodable where Element: ScaleDecodable {}
3838

39-
extension ScaleDecoder {
40-
public func decode<T: ScaleDecodable>(_ type: [T].Type, _ fixed: ScaleFixedTypeMarker) throws -> [T] {
41-
return try self.decode(fixed)
42-
}
39+
public protocol ScaleArrayInitializable {
40+
associatedtype IElement
4341

44-
public func decode<T>(
45-
_ type: [T].Type, _ fixed: ScaleFixedTypeMarker,
46-
reader: @escaping (ScaleDecoder) throws -> T
47-
) throws -> [T] {
48-
return try self.decode(fixed, reader: reader)
49-
}
42+
init(array: [IElement])
43+
}
44+
45+
extension Array: ScaleArrayInitializable {
46+
public typealias IElement = Element
5047

51-
public func decode<T>(
52-
_ fixed: ScaleFixedTypeMarker,
53-
reader: @escaping (ScaleDecoder) throws -> T
54-
) throws -> [T] {
55-
guard case .fixed(let size) = fixed else { fatalError() } // Compiler error silencing.
56-
var values = Array<T>()
57-
values.reserveCapacity(Int(size))
58-
for _ in 0..<size {
59-
try values.append(reader(self))
60-
}
61-
return values
48+
public init(array: [IElement]) {
49+
self.init(array)
6250
}
51+
}
52+
53+
public protocol ScaleArrayConvertible {
54+
associatedtype CElement
55+
56+
var asArray: [CElement] { get }
57+
}
58+
59+
extension Array: ScaleArrayConvertible {
60+
public typealias CElement = Element
6361

64-
public func decode<T: ScaleDecodable>(_ fixed: ScaleFixedTypeMarker) throws -> [T] {
65-
try self.decode(fixed) { decoder in try decoder.decode() }
62+
public var asArray: [CElement] { return self }
63+
}
64+
65+
extension ScaleCustomDecoderFactory where T: ScaleArrayInitializable, T.IElement: ScaleDecodable {
66+
public static func fixed(_ size: UInt) -> ScaleCustomDecoderFactory {
67+
.fixed(size) { decoder in try decoder.decode() }
6668
}
6769
}
6870

69-
extension ScaleEncoder {
70-
@discardableResult
71-
public func encode<T: ScaleEncodable>(_ values: [T], fixed: UInt) throws -> ScaleEncoder {
72-
try self.encode(values, fixed: fixed) { val, enc in try enc.encode(val) }
73-
return self
71+
extension ScaleCustomDecoderFactory where T: ScaleArrayInitializable {
72+
public static func fixed(
73+
_ size: UInt, _ reader: @escaping (ScaleDecoder) throws -> T.IElement
74+
) -> ScaleCustomDecoderFactory {
75+
ScaleCustomDecoderFactory { decoder in
76+
var values = Array<T.IElement>()
77+
values.reserveCapacity(Int(size))
78+
for _ in 0..<size {
79+
try values.append(reader(decoder))
80+
}
81+
return T(array: values)
82+
}
7483
}
75-
76-
@discardableResult
77-
public func encode<T>(
78-
_ values: [T], fixed: UInt,
79-
writer: @escaping (T, ScaleEncoder) throws -> Void
80-
) throws -> ScaleEncoder {
81-
guard values.count == fixed else {
82-
throw SEncodingError.invalidValue(
83-
values, SEncodingError.Context(
84-
path: self.path,
85-
description: "Wrong value count \(values.count) expected \(fixed)"
84+
}
85+
86+
extension ScaleCustomEncoderFactory where T: ScaleArrayConvertible {
87+
public static func fixed(
88+
_ size: UInt, writer: @escaping (T.CElement, ScaleEncoder) throws -> Void
89+
) -> ScaleCustomEncoderFactory {
90+
ScaleCustomEncoderFactory { encoder, conv in
91+
let values = conv.asArray
92+
guard values.count == size else {
93+
throw SEncodingError.invalidValue(
94+
values, SEncodingError.Context(
95+
path: encoder.path,
96+
description: "Wrong value count \(values.count) expected \(size)"
97+
)
8698
)
87-
)
88-
}
89-
for val in values {
90-
try writer(val, self)
99+
}
100+
for val in values {
101+
try writer(val, encoder)
102+
}
103+
return encoder
91104
}
92-
return self
93105
}
94106
}
95107

96-
extension SCALE {
97-
public func decode<T: ScaleDecodable>(
98-
_ type: [T].Type, _ fixed: ScaleFixedTypeMarker, from data: Data
99-
) throws -> [T] {
100-
return try self.decode(fixed, from: data)
101-
}
102-
103-
public func decode<T>(
104-
_ type: [T].Type, _ fixed: ScaleFixedTypeMarker, from data: Data,
105-
reader: @escaping (ScaleDecoder) throws -> T
106-
) throws -> [T] {
107-
return try self.decode(fixed, from: data, reader: reader)
108-
}
109-
110-
public func decode<T: ScaleDecodable>(_ fixed: ScaleFixedTypeMarker, from data: Data) throws -> [T] {
111-
return try self.decoder(data: data).decode(fixed)
112-
}
113-
114-
public func decode<T>(
115-
_ fixed: ScaleFixedTypeMarker, from data: Data,
116-
reader: @escaping (ScaleDecoder) throws -> T
117-
) throws -> [T] {
118-
return try self.decoder(data: data).decode(fixed, reader: reader)
119-
}
120-
121-
public func encode<T: ScaleEncodable>(_ values: [T], fixed: UInt) throws -> Data {
122-
return try self.encoder().encode(values, fixed: fixed).output
123-
}
124-
125-
public func encode<T>(
126-
_ values: [T], fixed: UInt,
127-
writer: @escaping (T, ScaleEncoder) throws -> Void
128-
) throws -> Data {
129-
return try self.encoder().encode(values, fixed: fixed, writer: writer).output
108+
extension ScaleCustomEncoderFactory where T: ScaleArrayConvertible, T.CElement: ScaleEncodable {
109+
public static func fixed(_ size: UInt) -> ScaleCustomEncoderFactory {
110+
.fixed(size) { val, enc in try enc.encode(val) }
130111
}
131112
}

0 commit comments

Comments
 (0)