Skip to content

Commit

Permalink
Remove EncodedData replacing with Array<UInt8> (#20)
Browse files Browse the repository at this point in the history
* Replace `EncodedData` with `Array<UInt8>`.
* Update documentation after replacing `EncodedData` with `Array<UInt8>`.
* Change signature of StorageContainerReaderWriter.write from `write(_ storageContainer: StorageContainer, to buffer: UnsafeMutableRawBufferPointer) -> Int` to `convert(_ storageContainer: StorageContainer) -> [UInt8]`.
* Renamed EncodedDataNegativeTests to BinaryDecoderByteArrayTests.
* Adjust binary format alignment decreasing padding.
  • Loading branch information
tonystone authored Apr 20, 2019
1 parent c4da3fb commit ba9ec3f
Show file tree
Hide file tree
Showing 48 changed files with 631 additions and 3,383 deletions.
5 changes: 0 additions & 5 deletions .jazzy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@ custom_categories:
children:
- BinaryEncoder
- BinaryDecoder
- EncodedData
- name: EncodedData Transformation
children:
- Array
- Data
- name: Supplemental Information
children:
- Binary Format
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ All significant changes to this project will be documented in this file.

## [1.0.0-beta.5](https://github.com/stickytools/sticky-encoding/tree/1.0.0-beta.5)

#### Removed
- Simplified the interface removing the `EncodedData` type replacing it with straight `Array<UInt8>`.

#### Added
- Changed return type of `BinaryEncoder.encode` from `EncodedData` to `Array<UInt8>`.
- Changed parameter type of `BinaryDecoder.decode` from `EncodedData` to `Array<UInt8>`.
- Moving binary conversion into decode/encode stage to improve error recovery on invalid binary input.

## [1.0.0-beta.4](https://github.com/stickytools/sticky-encoding/tree/1.0.0-beta.4)
Expand All @@ -17,7 +22,7 @@ All significant changes to this project will be documented in this file.
- Added support to/from `Swift.Data` to `EncodedData`.

#### Changed
- Changed EncodedData `var bytes: [UInt8]` to `Array<UInt8>(_ encodedData: EncodedDate)` constructor.
- Changed EncodedData `var bytes: [UInt8]` to `Array<UInt8>(_ bytes: EncodedDate)` constructor.

## [1.0.0-beta.2](https://github.com/stickytools/sticky-encoding/tree/1.0.0-beta.2)

Expand Down
30 changes: 8 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ of the BinaryEncoder and call `encode`.
```Swift
let string = "You can encode single values of any type."

let encoded = try encoder.encode(string)
let bytes = try encoder.encode(string)
```
Basic structs and classes can also be encoded.
```Swift
Expand All @@ -66,7 +66,7 @@ Basic structs and classes can also be encoded.

let employee = Employee(first: "John", last: "Doe", employeeNumber: 2345643)

let encodedData = try encoder.encode(employee)
let bytes = try encoder.encode(employee)
```
As well as Complex types with sub classes.

Expand All @@ -81,32 +81,19 @@ To create an instance of a BinaryDecoder:
To decode, you pass the Type of object to create, and an instance of encoded data representing that type.
```Swift
let employee = try decoder.decode(Employee.self, from: encodedData)
let employee = try decoder.decode(Employee.self, from: bytes)
```

### EncodedData
### Encoded Data

The `BinaryEncoder.encode` method returns a type called `EncodedData` (likewise `BinaryDecoder.decode` accepts an `EncodedData` instance). This type is the direct connection between raw memory and a type that can be converted to and from a `Codable` object.
The `BinaryEncoder.encode` method returns type `Array<UInt8>` (likewise `BinaryDecoder.decode` accepts an `Array<UInt8>` instance).

StickyEncoding uses this intermediate representation so that it can support many use cases from direct byte conversion to writing/reading directly to/from raw memory.

When encoding of an object, the intermediate representation has already been
encoded down to a form that can be rapidly written to memory.
`[Array<UInt8>` is easily converted to other types such as `Swift.Data` for passing to Foundation methods to store and load data from file.
```Swift
let encodedData = try encoder.encode(employee)
let bytes = try encoder.encode(employee)

// Write the bytes directly to a file.
FileManager.default.createFile(atPath: "employee.bin", contents: Data(encodedData))
```
There are use cases that require writing to a buffer or socket in which case StickyEncoding offers a direct write method so that an intermediate structure (byte array) does not have to be created first.
```Swift
let encodedData = try encoder.encode(employee)

// Allocate byte aligned raw memory to hold the binary encoded data.
let buffer = UnsafeMutableRawBufferPointer.allocate(byteCount: encodedData.byteCount, alignment: MemoryLayout<UInt8>.alignment)

// Write the encoded data directly to the raw memory.
encodedData.write(to: buffer)
FileManager.default.createFile(atPath: "employee.bin", contents: Data(bytes))
```

## Sources and Binaries
Expand All @@ -126,7 +113,6 @@ You can find the latest sources and binaries on [github](https://github.com/stic

> Note: for a instructions on how to build and test StickyEncoding for contributing please see the [Contributing Guide](CONTRIBUTING.md).

## Installation

### Swift Package Manager
Expand Down
5 changes: 0 additions & 5 deletions Sources/Documentation/Abstracts/EncodedData Transformation.md

This file was deleted.

3 changes: 0 additions & 3 deletions Sources/Documentation/Abstracts/Encoding & Decoding.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,3 @@ Encoding is done using a `BinaryEncoder` instance and will encode any `Encodable
Decoding is done using a `BinaryDecoder` instance and can decode any `Decodable` type that was previously encoded using the `BinaryEncoder`. Of course you can declare `Encodable` or `Decodable` conformance by using `Codable` as well.

StickyEncoding creates a compact binary format that represents the encoded object or data type. You can read more about the format in the document [Binary Format](Sources/Documentation/Sections/Binary&#32;Format.md).

To facilitate many use cases, StickyEncoding encodes the data to an instance of `EncodedData`. EncodedData contains a binary format suitable
for writing directly to memory, disk, or into a byte array. Or in the case of decoding, the format facilitates rapid decoding to Swift instances.
Binary file modified Sources/Documentation/Sections/Binary Format Diagram.cddz
Binary file not shown.
4 changes: 1 addition & 3 deletions Sources/Documentation/Sections/Binary Format.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
# Binary Format

The internal binary representation of the encoded data consists of a series of **Elements** each containing a **Header** section followed by a **Container**. The Element is essentially a wrapper around a Container defining it's type and size in bytes. The format was designed to be as compact and efficient as possible at storing the simplest to the most complex structures that can be encoded.
The internal binary representation of the encoded data consists of a series of **Elements** each containing a **Header** section followed by a **Container**. The Element is essentially a wrapper around a Container defining it's type. The format was designed to be as compact and efficient as possible at storing the simplest to the most complex structures that can be encoded.

![Binary Format Container Header](Binary-Format-Container-Header.png)

The Header of each Element contains a 32 bit integer representing the container type followed by a 32 integer containing the total number of bytes stored in the Container section of this Element.

## Containers
Each Container formats it's data based on the requirements of that container. There are 3 container types that can be stored corresponding to the `Encoder` and `Decoder` protocol return types for the functions `singleValueContainer()`, `unkeyedContainer()`, and `container(keyedBy:)`. An Element is created in response to each call to any one of these functions.

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions Sources/StickyEncoding/BinaryDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import Foundation
///
/// To decode, you pass the Type of object to create, and an instance of encoded data representing that type.
/// ```
/// let employee = try decoder.decode(Employee.self, from: encodedData)
/// let employee = try decoder.decode(Employee.self, from: bytes)
/// ```
///
open class BinaryDecoder {
Expand Down Expand Up @@ -60,9 +60,9 @@ open class BinaryDecoder {
/// - throws: `DecodingError.dataCorrupted` if values requested from the payload are corrupted, or if the given data is not valid.
/// - throws: An error if any value throws an error during decoding.
///
open func decode<T : Decodable>(_ type: T.Type, from encodedData: EncodedData) throws -> T {
open func decode<T : Decodable>(_ type: T.Type, from bytes: [UInt8]) throws -> T {

let storage = try StorageContainerReader.read(from: encodedData.buffer)
let storage = try StorageContainerReader.convert(bytes)

return try T.init(from: _BinaryDecoder(codingPath: [], rootStorage: storage, userInfo: self.userInfo))
}
Expand Down
17 changes: 6 additions & 11 deletions Sources/StickyEncoding/BinaryEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import Foundation
/// ```
/// let string = "You can encode single values of any type."
///
/// let encoded = try encoder.encode(string)
/// let bytes = try encoder.encode(string)
/// ```
/// Basic structs and classes can also be encoded.
/// ```
Expand All @@ -57,7 +57,7 @@ import Foundation
///
/// let employee = Employee(first: "John", last: "Doe", employeeNumber: 2345643)
///
/// let encodedData = try encoder.encode(employee)
/// let bytes = try encoder.encode(employee)
/// ```
/// As well as Complex types with sub classes.
///
Expand All @@ -84,20 +84,15 @@ open class BinaryEncoder {
///
/// - throws: An error if any value throws an error during encoding.
///
open func encode<T: Encodable>(_ value: T) throws -> EncodedData {
open func encode<T: Encodable>(_ value: T) throws -> [UInt8] {
let encoder = _BinaryEncoder(codingPath: [], userInfo: self.userInfo)

try value.encode(to: encoder)

if let storage = encoder.rootStorage.value {
var bytes = Array<UInt8>(repeating: 0, count: StorageContainerWriter.byteCount(storage))
guard let storage = encoder.rootStorage.value
else { return [] }

bytes.withUnsafeMutableBytes { (buffer) -> Void in
StorageContainerWriter.write(storage, to: buffer)
}
return EncodedData(bytes)
}
return EncodedData()
return StorageContainerWriter.convert(storage)
}

// MARK: Getting contextual information
Expand Down
Loading

0 comments on commit ba9ec3f

Please sign in to comment.