Skip to content

Commit

Permalink
Decoder optimization & cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
DimaRU committed Feb 1, 2024
1 parent 4c5ad06 commit 3461e93
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 70 deletions.
41 changes: 9 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

![Build](https://github.com/DimaRU/CDRCodable/workflows/Build/badge.svg)

A [OMG Common Data Representation (CDR)](https://www.omg.org/spec/DDS-XTypes/) encoder and decoder for Swift `Codable` types.
A [OMG Common Data Representation (CDR)](https://www.omg.org/spec/DDS-XTypes/) (PLAIN_CDR) encoder and decoder for Swift `Codable` types.

Now can be used with [FastRTPSSwift](https://github.com/DimaRU/FastRTPSSwift), a Swift wrapper for eProsima [FastDDS](https://github.com/eProsima/Fast-DDS) library.

Expand Down Expand Up @@ -40,20 +40,9 @@ let value = try! decoder.decode([Int16].self, from: data)
Add the CDRCodable package to your target dependencies in `Package.swift`:

```swift
import PackageDescription

let package = Package(
name: "YourProject",
dependencies: [
.package(
url: "https://github.com/DimaRU/CDRCodable",
from: "1.0.0"
),
]
)
.package(url: "https://github.com/DimaRU/CDRCodable", from: "1.0.0"),
```

Then run the `swift build` command to build your project.

## Supported IDL types

Expand Down Expand Up @@ -83,10 +72,11 @@ Static size arrays is not supported by CDRCodable directly and needed custom cod
### 3. Sequences
CDRCodable supports sequences, which map between Swift Array and C++ std::vector container. The following table represents how the map between Swift, C++11 and IDL and is handled.

| Swift | C++11 | IDL |
| --------------- | ------------------------- | ----------------------------- |
| Swift | C++11 | IDL |
| ---------------- | ------------------------- | ----------------------------- |
| `Data` | `std::vector<uint8_t>` | `sequence<octet>` |
| `Array<Int8>` | `std::vector<char>` | `sequence<char>` |
| `Array<UInt8>` or `Data` | `std::vector<uint8_t>` | `sequence<octet>` |
| `Array<UInt8>` | `std::vector<uint8_t>` | `sequence<octet>` |
| `Array<Int16>` | `std::vector<int16_t>` | `sequence<short>` |
| `Array<UInt16>` | `std::vector<uint16_t>` | `sequence<unsigned short>` |
| `Array<Int32>` | `std::vector<int32_t>` | `sequence<long>` |
Expand All @@ -100,19 +90,6 @@ CDRCodable supports sequences, which map between Swift Array and C++ std::vector
| `Array<String>` | `std::vector<std::string>`| `sequence<string>` |


| Array\<Int8> | std::vector\<char> | sequence\<char> |
| Array\<UInt8> or Data | std::vector\<uint8\_t> | sequence\<octet> |
| Array\<Int16> | std::vector\<int16\_t> | sequence\<short> |
| Array\<UInt16> | std::vector\<uint16\_t> | sequence\<unsigned short> |
| Array\<Int32> | std::vector\<int32\_t> | sequence\<long> |
| Array\<UInt32> | std::vector\<uint32\_t> | sequence\<unsigned long> |
| Array\<Int64> | std::vector\<int64\_t> | sequence\<long long> |
| Array\<UInt64> | std::vector\<uint64\_t> | sequence\<unsigned long long> |
| Array\<Float> | std::vector\<float> | sequence\<float> |
| Array\<Double> | std::vector\<double> | sequence\<double> |
| Array\<Float80> | std::vector\<long double> | sequence\<long double> |
| Array\<Bool> | std::vector\<bool> | sequence\<boolean> |
| Array\<String> | std::vector\<std::string> | sequence\<string> |

### 4. Enumerations

Expand Down Expand Up @@ -209,7 +186,7 @@ enum ControlUnion: Codable {
case IntMenu(intMenu: UInt32)

init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
var container = try decoder.singleValueContainer()
let selector = try container.decode(UInt32.self)
switch selector {
case 0:
Expand Down Expand Up @@ -308,7 +285,7 @@ Example:
IDL definition:

```IDL
struct TridentControlTarget
struct ControlTarget
{
string id;
Expand All @@ -320,7 +297,7 @@ struct TridentControlTarget
```

```Swift
struct TridentControlTarget: Codable
struct ControlTarget: Codable
{
let id: String

Expand Down
16 changes: 8 additions & 8 deletions Sources/CDRCodable/Decoder/CDRDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ final public class CDRDecoder {
final class DataStore {
let data: Data
var index: Data.Index
var getCodingPath: () -> [CodingKey]
var codingPath: [CodingKey] = []

init(data: Data) {
self.data = data
self.index = self.data.startIndex
self.getCodingPath = { [] }
}
}

Expand All @@ -70,7 +70,7 @@ extension _CDRDecoder: Decoder {
func container<Key>(keyedBy type: Key.Type) -> KeyedDecodingContainer<Key> where Key : CodingKey {
precondition(self.container == nil)

let container = KeyedContainer<Key>(dataStore: self.dataStore, codingPath: self.codingPath, userInfo: self.userInfo)
let container = KeyedContainer<Key>(dataStore: dataStore, codingPath: codingPath, userInfo: userInfo)
self.container = container

return KeyedDecodingContainer(container)
Expand All @@ -79,7 +79,7 @@ extension _CDRDecoder: Decoder {
func unkeyedContainer() throws -> UnkeyedDecodingContainer {
precondition(self.container == nil)

let container = try UnkeyedContainer(data: self.dataStore, codingPath: self.codingPath, userInfo: self.userInfo)
let container = try UnkeyedContainer(dataStore: dataStore, codingPath: codingPath, userInfo: userInfo)
self.container = container

return container
Expand All @@ -88,15 +88,15 @@ extension _CDRDecoder: Decoder {
func singleValueContainer() -> SingleValueDecodingContainer {
precondition(self.container == nil)

let container = SingleValueContainer(data: self.dataStore, codingPath: self.codingPath, userInfo: self.userInfo)
let container = SingleValueContainer(dataStore: dataStore, codingPath: codingPath, userInfo: userInfo)
self.container = container

return container
}
}

protocol _CDRDecodingContainer {
var codingPath: [CodingKey] { get set }
var codingPath: [CodingKey] { get }
var userInfo: [CodingUserInfoKey : Any] { get }
var dataStore: DataStore { get }
}
Expand All @@ -114,7 +114,7 @@ extension DataStore {
func checkDataEnd(_ length: Int) throws {
let nextIndex = index.advanced(by: length)
guard nextIndex <= data.endIndex else {
let context = DecodingError.Context(codingPath: getCodingPath(), debugDescription: "Unexpected end of data")
let context = DecodingError.Context(codingPath: codingPath, debugDescription: "Unexpected end of data")
throw DecodingError.dataCorrupted(context)
}
}
Expand Down Expand Up @@ -162,7 +162,7 @@ extension DataStore {
index = index.advanced(by: length)
}
guard let string = String(data: data[index..<index.advanced(by: length - 1)], encoding: .utf8) else {
let context = DecodingError.Context(codingPath: getCodingPath(), debugDescription: "Couldn't decode string with UTF-8 encoding")
let context = DecodingError.Context(codingPath: codingPath, debugDescription: "Couldn't decode string with UTF-8 encoding")
throw DecodingError.dataCorrupted(context)
}
return string
Expand Down
14 changes: 6 additions & 8 deletions Sources/CDRCodable/Decoder/KeyedDecodingContainer.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import Foundation

extension _CDRDecoder {
final class KeyedContainer<Key> where Key: CodingKey {
var dataStore: DataStore
var codingPath: [CodingKey]
var userInfo: [CodingUserInfoKey: Any]
var allKeys: [Key] = []
struct KeyedContainer<Key> where Key: CodingKey {
let dataStore: DataStore
let codingPath: [CodingKey]
let userInfo: [CodingUserInfoKey: Any]
let allKeys: [Key] = []

func nestedCodingPath(forKey key: CodingKey) -> [CodingKey] {
return self.codingPath + [key]
Expand All @@ -15,9 +15,7 @@ extension _CDRDecoder {
self.codingPath = codingPath
self.userInfo = userInfo
self.dataStore = dataStore
self.dataStore.getCodingPath = {
self.codingPath
}
self.dataStore.codingPath = codingPath
}
}
}
Expand Down
16 changes: 7 additions & 9 deletions Sources/CDRCodable/Decoder/SingleValueDecodingContainer.swift
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import Foundation

extension _CDRDecoder {
final class SingleValueContainer {
var codingPath: [CodingKey]
var userInfo: [CodingUserInfoKey: Any]
var dataStore: DataStore
struct SingleValueContainer {
let codingPath: [CodingKey]
let userInfo: [CodingUserInfoKey: Any]
let dataStore: DataStore

init(data: DataStore, codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) {
init(dataStore: DataStore, codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) {
self.codingPath = codingPath
self.userInfo = userInfo
self.dataStore = data
self.dataStore.getCodingPath = {
self.codingPath
}
self.dataStore = dataStore
self.dataStore.codingPath = codingPath
}
}
}
Expand Down
19 changes: 9 additions & 10 deletions Sources/CDRCodable/Decoder/UnkeyedDecodingContainer.swift
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import Foundation

extension _CDRDecoder {
final class UnkeyedContainer {
var codingPath: [CodingKey]
var userInfo: [CodingUserInfoKey: Any]
var dataStore: DataStore
struct UnkeyedContainer {
let codingPath: [CodingKey]
let userInfo: [CodingUserInfoKey: Any]
let dataStore: DataStore

init(data: DataStore, codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) throws {
init(dataStore: DataStore, codingPath: [CodingKey], userInfo: [CodingUserInfoKey : Any]) throws {
self.codingPath = codingPath
self.userInfo = userInfo
self.dataStore = data
self.dataStore.getCodingPath = {
self.codingPath
}
self.dataStore = dataStore

self.dataStore.codingPath = codingPath
count = Int(try dataStore.read(UInt32.self))
}

Expand All @@ -29,7 +28,7 @@ extension _CDRDecoder.UnkeyedContainer: UnkeyedDecodingContainer {
return true
}

func decode<T>(_ type: T.Type) throws -> T where T : Decodable {
mutating func decode<T>(_ type: T.Type) throws -> T where T : Decodable {
defer { self.currentIndex += 1 }
let decoder = _CDRDecoder(dataStore: self.dataStore, userInfo: userInfo)
let value = try T(from: decoder)
Expand Down
3 changes: 0 additions & 3 deletions Tests/CDRCodableTests/CDRCodableRoundTripTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ class CDRCodableRoundTripTests: XCTestCase {
struct RovTemperature: Codable, Equatable {
let temperature: RovTemperature_
let id: String

var key: String { return id }
}

let example = RovTemperature(temperature: RovTemperature_(header: RovHeader(stamp: RovTime(sec: 0,
Expand All @@ -80,5 +78,4 @@ class CDRCodableRoundTripTests: XCTestCase {
let dataBack = try! encoder.encode(value)
XCTAssertEqual(dataBack, data)
}

}

0 comments on commit 3461e93

Please sign in to comment.