Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d87ed12
Working on Encoder
colemancda May 12, 2019
a21d9d5
Working on Encoder
colemancda May 12, 2019
81f603c
Updated unit tests
colemancda May 13, 2019
6214116
Working on Encoder
colemancda May 13, 2019
26ee0ed
Added Integer extensions
colemancda May 13, 2019
a78db0a
Working on Decoder
colemancda May 13, 2019
4e0d338
Fixed encoder
colemancda May 13, 2019
7a92fc7
Updated unit tests
colemancda May 13, 2019
b78e174
Working on Decoder
colemancda May 13, 2019
5f6fda7
Updated `TLVNumericFormat`
colemancda May 13, 2019
7523d75
Updated unit tests
colemancda May 13, 2019
24731b7
Updated unit tests
colemancda May 13, 2019
2092b4f
Fixed encoding arrays
colemancda May 13, 2019
79fbb40
Updated unit tests
colemancda May 13, 2019
c97d973
Updated unit tests
colemancda May 13, 2019
a90d00c
Updated unit tests
colemancda May 13, 2019
6bc8dc3
Fixed compiler error
colemancda May 13, 2019
df79698
Optimized Unkeyed Encoding Container
colemancda May 13, 2019
4f3cdb1
Fixed Swift 4 compilation
colemancda May 13, 2019
82c6ce9
Fixed Swift 4 compilation
colemancda May 13, 2019
7383820
Updated unit tests
colemancda May 13, 2019
daccf75
Support Swift 5
colemancda May 13, 2019
9ba0f02
Updated Xcode schemes
colemancda May 13, 2019
6f1360d
Fixed Swift 4 compilation
colemancda May 13, 2019
01acf4e
Fixed Swift 4.2 compilation error
colemancda May 14, 2019
a35b0c0
Updated logging
colemancda May 14, 2019
ec2fb22
Working on Encoder
colemancda May 14, 2019
a894a26
Working on Decoder
colemancda May 14, 2019
5758c7e
Working on CodingKey
colemancda May 14, 2019
7c811a2
Updated logging
colemancda May 14, 2019
3c4ace6
Working on Coding Key
colemancda May 14, 2019
b62d05b
Fixed Swift 4 compilation
colemancda May 14, 2019
095c998
Updated unit tests
colemancda May 14, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:4.1
// swift-tools-version:5.0
import PackageDescription

let package = Package(name: "TLVCoding",
Expand All @@ -12,4 +12,4 @@ let package = Package(name: "TLVCoding",
.target(name: "TLVCoding", path: "./Sources"),
.testTarget(name: "TLVCodingTests", dependencies: ["TLVCoding"])
],
swiftLanguageVersions: [4])
swiftLanguageVersions: [.v5])
15 changes: 15 additions & 0 deletions Package@swift-4.1.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// swift-tools-version:4.1
import PackageDescription

let package = Package(name: "TLVCoding",
products: [
.library(
name: "TLVCoding",
targets: ["TLVCoding"]
)
],
targets: [
.target(name: "TLVCoding", path: "./Sources"),
.testTarget(name: "TLVCodingTests", dependencies: ["TLVCoding"])
],
swiftLanguageVersions: [4])
15 changes: 15 additions & 0 deletions Package@swift-4.2.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// swift-tools-version:4.2
import PackageDescription

let package = Package(name: "TLVCoding",
products: [
.library(
name: "TLVCoding",
targets: ["TLVCoding"]
)
],
targets: [
.target(name: "TLVCoding", path: "./Sources"),
.testTarget(name: "TLVCodingTests", dependencies: ["TLVCoding"])
],
swiftLanguageVersions: [.v4_2])
114 changes: 114 additions & 0 deletions Sources/CodingKey.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//
// CodingKey.swift
// TLVCoding
//
// Created by Alsey Coleman Miller on 5/12/19.
// Copyright © 2019 PureSwift. All rights reserved.
//

public protocol TLVCodingKey: CodingKey {

init?(code: TLVTypeCode)

var code: TLVTypeCode { get }
}

public extension TLVCodingKey {

init?(intValue: Int) {

guard intValue <= Int(UInt8.max),
intValue >= Int(UInt8.min)
else { return nil }

self.init(code: TLVTypeCode(rawValue: UInt8(intValue)))
}

var intValue: Int? {
return Int(code.rawValue)
}
}

public extension TLVCodingKey where Self: RawRepresentable, Self.RawValue == TLVTypeCode.RawValue {

init?(code: TLVTypeCode) {
self.init(rawValue: code.rawValue)
}

var code: TLVTypeCode {
return TLVTypeCode(rawValue: rawValue)
}
}

#if swift(>=4.2)
public extension TLVCodingKey where Self: CaseIterable, Self: RawRepresentable, Self.RawValue == TLVTypeCode.RawValue {

init?(stringValue: String) {

guard let value = Self.allCases.first(where: { $0.stringValue == stringValue })
else { return nil }

self = value
}
}
#endif

internal extension TLVTypeCode {

init? <K: CodingKey> (codingKey: K) {

if let tlvCodingKey = codingKey as? TLVCodingKey {

self = tlvCodingKey.code

} else if let intValue = codingKey.intValue {

guard intValue <= Int(UInt8.max),
intValue >= Int(UInt8.min)
else { return nil }

self.init(rawValue: UInt8(intValue))

} else if MemoryLayout<K>.size == MemoryLayout<UInt8>.size,
Mirror(reflecting: codingKey).displayStyle == .enum {

self.init(rawValue: unsafeBitCast(codingKey, to: UInt8.self))

} else {

return nil
}
}
}

internal extension Sequence where Element == CodingKey {

/// KVC path string for current coding path.
var path: String {
return reduce("", { $0 + "\($0.isEmpty ? "" : ".")" + $1.stringValue })
}
}

internal extension CodingKey {

static var sanitizedName: String {

let rawName = String(reflecting: self)
#if swift(>=5.0)
var elements = rawName.split(separator: ".")
#else
var elements = rawName.components(separatedBy: ".")
#endif
guard elements.count > 2
else { return rawName }
elements.removeFirst()
#if swift(>=5.0)
elements.removeAll { $0.contains("(unknown context") }
#else
while let index = elements.index(where: { $0.contains("(unknown context") }) {
elements.remove(at: index)
}
#endif
return elements.reduce("", { $0 + ($0.isEmpty ? "" : ".") + $1 })
}
}
100 changes: 100 additions & 0 deletions Sources/Data.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//
// Data.swift
// TLVCoding
//
// Created by Alsey Coleman Miller on 5/12/19.
// Copyright © 2019 PureSwift. All rights reserved.
//

import Foundation

internal extension Data {

#if swift(>=5.0) || (swift(>=4.2) && XCODE)
func subdataNoCopy(in range: Range<Int>) -> Data {

// stored in heap, can reuse buffer
if count > Data.inlineBufferSize {

#if swift(>=5.0)
return withUnsafeBytes { (buffer: UnsafeRawBufferPointer) in
Data(bytesNoCopy: UnsafeMutableRawPointer(mutating: buffer.baseAddress!.advanced(by: range.lowerBound)),
count: range.count,
deallocator: .none)
}
#else
return withUnsafeBytes {
Data(bytesNoCopy: UnsafeMutableRawPointer(mutating: $0.advanced(by: range.lowerBound)),
count: range.count,
deallocator: .none)
}
#endif

} else {

// stored in stack, must copy
return subdata(in: range)
}
}
#elseif swift(>=4.2)
func subdataNoCopy(in range: Range<Int>) -> Data {

return withUnsafeBytes {
Data(bytesNoCopy: UnsafeMutableRawPointer(mutating: $0.advanced(by: range.lowerBound)),
count: range.count,
deallocator: .none)
}
}
#elseif swift(>=4.0)
func subdataNoCopy(in range: CountableRange<Int>) -> Data {

let pointer = withUnsafeBytes { UnsafeMutableRawPointer(mutating: $0).advanced(by: range.lowerBound) }
return Data(bytesNoCopy: pointer, count: range.count, deallocator: .none)
}

/// Returns a new copy of the data in a specified range.
func subdata(in range: CountableRange<Int>) -> Data {
return Data(self[range])
}
#endif

func suffixNoCopy(from index: Int) -> Data {

return subdataNoCopy(in: index ..< count)
}

func suffixCheckingBounds(from start: Int) -> Data {

if count > start {

return Data(suffix(from: start))

} else {

return Data()
}
}
}

#if swift(>=5.0) || (swift(>=4.2) && XCODE)
private extension Data {

/// Size of the inline buffer for `Foundation.Data` used in Swift 5.
///
/// Used to determine wheather data is stored on stack or in heap.
static var inlineBufferSize: Int {

// Keep up to date
// https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/Data.swift#L621
#if arch(x86_64) || arch(arm64) || arch(s390x) || arch(powerpc64) || arch(powerpc64le)
typealias Buffer = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) //len //enum
#elseif arch(i386) || arch(arm)
typealias Buffer = (UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8)
#endif

return MemoryLayout<Buffer>.size
}
}
#endif
118 changes: 118 additions & 0 deletions Sources/DataConvertible.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
//
// DataConvertible.swift
// TLVCoding
//
// Created by Alsey Coleman Miller on 5/12/19.
// Copyright © 2019 PureSwift. All rights reserved.
//

import Foundation

/// Can be converted into data.
internal protocol DataConvertible {

/// Append data representation into buffer.
static func += <T: DataContainer> (data: inout T, value: Self)

/// Length of value when encoded into data.
var dataLength: Int { get }
}

extension Data {

/// Initialize data with contents of value.
@inline(__always)
init <T: DataConvertible> (_ value: T) {
self.init(capacity: value.dataLength)
self += value
}

init <T: Sequence> (_ sequence: T) where T.Element: DataConvertible {

let dataLength = sequence.reduce(0, { $0 + $1.dataLength })
self.init(capacity: dataLength)
sequence.forEach { self += $0 }
}
}

// MARK: - UnsafeDataConvertible

/// Internal Data casting protocol
internal protocol UnsafeDataConvertible: DataConvertible { }

extension UnsafeDataConvertible {

var dataLength: Int {
return MemoryLayout<Self>.size
}

/// Append data representation into buffer.
static func += <T: DataContainer> (data: inout T, value: Self) {
#if swift(>=4.2)
withUnsafePointer(to: value) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout<Self>.size) {
data.append($0, count: MemoryLayout<Self>.size)
}
}
#else
var value = value
withUnsafePointer(to: &value) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout<Self>.size) {
data.append($0, count: MemoryLayout<Self>.size)
}
}
#endif
}
}

extension UInt16: UnsafeDataConvertible { }
extension UInt32: UnsafeDataConvertible { }
extension UInt64: UnsafeDataConvertible { }

// MARK: - DataContainer

/// Data container type.
internal protocol DataContainer: RandomAccessCollection where Self.Index == Int {

subscript(index: Int) -> UInt8 { get }

subscript(range: Range<Int>) -> Slice<Self> { get }

mutating func append(_ newElement: UInt8)

mutating func append(_ pointer: UnsafePointer<UInt8>, count: Int)

mutating func append <C: Collection> (contentsOf bytes: C) where C.Element == UInt8

#if swift(>=4.2)
static func += (lhs: inout Self, rhs: UInt8)
static func += <C: Collection> (lhs: inout Self, rhs: C) where C.Element == UInt8
#endif
}

extension DataContainer {

#if swift(>=4.2)
#else
static func += (lhs: inout Self, rhs: UInt8) {
lhs.append(rhs)
}

static func += <C: Collection> (lhs: inout Self, rhs: C) where C.Element == UInt8 {
lhs.append(contentsOf: rhs)
}
#endif

mutating func append <T: DataConvertible> (_ value: T) {
self += value
}
}

extension Data: DataContainer {

#if swift(>=4.2)
static func += (lhs: inout Data, rhs: UInt8) {
lhs.append(rhs)
}
#endif
}
Loading