Skip to content

Commit

Permalink
wip encoder/decoder
Browse files Browse the repository at this point in the history
  • Loading branch information
waahm7 committed Nov 20, 2024
1 parent 49f0563 commit b74e2a3
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 17 deletions.
126 changes: 109 additions & 17 deletions Source/AwsCommonRuntimeKit/crt/CBOR.swift
Original file line number Diff line number Diff line change
@@ -1,40 +1,132 @@
import AwsCCommon
// SPDX-License-Identifier: Apache-2.0.
import Foundation
import AwsCCommon

public struct CBOREncoder {
public class CBOREncoder {
var rawValue: OpaquePointer

public init() {
// TODO: Try init?
rawValue = aws_cbor_encoder_new(allocator.rawValue)!
}

public func encode(value: CBORType) {
public func encode(_ value: CBORType) {
switch value {
case .uint64(let value): aws_cbor_encoder_write_uint(self.rawValue, value)
case .int(let value): {
let value = value > 0 ? value : -1 - value
aws_cbor_encoder_write_uint(self.rawValue, UInt64(value))
}
case .int(let value):
do {
if value >= 0 {
aws_cbor_encoder_write_uint(self.rawValue, UInt64(value))
} else {
aws_cbor_encoder_write_negint(self.rawValue, UInt64(-1 - value))
}
}
case .double(let value): aws_cbor_encoder_write_float(self.rawValue, value)
// case .bytes(let value):
// case .text(let value):
case .array(let values):
do {
aws_cbor_encoder_write_array_start(self.rawValue, values.count)
for value in values {
encode(value)
}
}
case .bool(let value): aws_cbor_encoder_write_bool(self.rawValue, value)
case .bytes(let value):
do {
value.withAWSByteCursorPointer { cursor in
aws_cbor_encoder_write_bytes(self.rawValue, cursor.pointee)
}
}
//case .cbor_break: aws_cbor_encoder_write_break(self.rawValue)

Check warning on line 39 in Source/AwsCommonRuntimeKit/crt/CBOR.swift

View workflow job for this annotation

GitHub Actions / lint

Comment Spacing Violation: Prefer at least one space after slashes for comments (comment_spacing)
case .map(let values):
do {
aws_cbor_encoder_write_map_start(self.rawValue, values.count)
for (key, value) in values {
encode(.text(key))
encode(value)
}
}
case .null: aws_cbor_encoder_write_null(self.rawValue)
case .text(let value):
do {
value.withByteCursor { cursor in
aws_cbor_encoder_write_text(self.rawValue, cursor)
}
}
case .timestamp(let value):
do {
// tag 1 means epoch based timestamp
aws_cbor_encoder_write_tag(self.rawValue, 1)
aws_cbor_encoder_write_float(self.rawValue, value.timeIntervalSince1970)
}
case .undefined: aws_cbor_encoder_write_undefined(self.rawValue)
}
}

public func getEncoded() -> Data {
aws_cbor_encoder_get_encoded_data(self.rawValue).toData()
}

deinit {
aws_cbor_encoder_destroy(rawValue)
}
}

public enum CBORType: Equatable {
case uint64(value: UInt64)
case int(value: Int64) // NegInt?
case double(value: Double) // float 32 or 64?
// case bytes(value: [uint8])
// case text(value: String)
// case timestamp(value: xyz)
// TODO: More types
// TODO: How to handle map and other stuff?
case uint64(_ value: UInt64)
case int(_ value: Int64)
case double(_ value: Double)
case bytes(_ value: Data)
case text(_ value: String)
case array(_ value: [CBORType])
case map(_ value: [String: CBORType])
case timestamp(_ value: Date)
case bool(_ value: Bool)
case null
case undefined
//case cbor_break

Check warning on line 86 in Source/AwsCommonRuntimeKit/crt/CBOR.swift

View workflow job for this annotation

GitHub Actions / lint

Comment Spacing Violation: Prefer at least one space after slashes for comments (comment_spacing)
// ask if they need unbounded arrays, map, text, bytes
}

public class CBORDecoder {
var rawValue: OpaquePointer
// Keep a reference to data to make it outlive the decoder
let data: Data

public init(data: Data) {
// TODO: Try init?
self.data = data
rawValue = self.data.withAWSByteCursorPointer {
aws_cbor_decoder_new(allocator.rawValue, $0.pointee)!
}
}

public func decodeNext() throws -> CBORType {
var cbor_type: aws_cbor_type = AWS_CBOR_TYPE_UNKNOWN
guard aws_cbor_decoder_peek_type(self.rawValue, &cbor_type) == AWS_OP_SUCCESS else {
throw CommonRunTimeError.crtError(.makeFromLastError())
}
switch cbor_type {
case AWS_CBOR_TYPE_UINT:
do {
var out_value: UInt64 = 0
guard
aws_cbor_decoder_pop_next_unsigned_int_val(self.rawValue, &out_value)
== AWS_OP_SUCCESS
else {
throw CommonRunTimeError.crtError(.makeFromLastError())
}
return .uint64(out_value)
}
default:
fatalError("invalid cbor decode type")
}
}

public func hasNext() -> Bool {
aws_cbor_decoder_get_remaining_length(self.rawValue) != 0
}

deinit {
aws_cbor_decoder_destroy(rawValue)
}
}
5 changes: 5 additions & 0 deletions Source/AwsCommonRuntimeKit/crt/Utilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ extension TimeInterval {
}

extension aws_byte_cursor {

func toData() -> Data {
Data(bytesNoCopy: self.ptr, count: self.len, deallocator: .none)
}

func toString() -> String {
if self.len == 0 {
return ""
Expand Down
29 changes: 29 additions & 0 deletions Test/AwsCommonRuntimeKitTests/crt/CBOR.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0.

import XCTest
import AwsCCommon
@testable import AwsCommonRuntimeKit

class CBORTests: XCBaseTestCase {

func testCBOREncode() async throws {
let uintValue: CBORType = .uint64(100)

// encode the values
let encoder = CBOREncoder()
encoder.encode(uintValue)
let encoded = encoder.getEncoded();

print(encoded)

let decoder = CBORDecoder(data: encoded)
while decoder.hasNext() {
let value = try! decoder.decodeNext()
XCTAssertEqual(value, .uint64(100))

}

}

}

0 comments on commit b74e2a3

Please sign in to comment.