Skip to content

Commit

Permalink
Remove use of IUO for Encoder/Decoder State
Browse files Browse the repository at this point in the history
  • Loading branch information
kdubb committed Feb 6, 2023
1 parent 0f69226 commit 16eebb4
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 36 deletions.
25 changes: 12 additions & 13 deletions Sources/PotentASN1/ASN1Decoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,23 +97,22 @@ public struct ASN1DecoderTransform: InternalDecoderTransform, InternalValueDeser

static func decode(_ value: ASN1, decoder: IVD) throws -> Any? {

if decoder.state == nil {
decoder.state = try SchemaState(initial: decoder.options.schema)
}
let state = try decoder.state ?? SchemaState(initial: decoder.options.schema)
decoder.state = state

let keep = zip(decoder.state.keyStack, decoder.codingPath).prefix { $0.0.stringValue == $0.1.stringValue }.count
let keep = zip(state.keyStack, decoder.codingPath).prefix { $0.0.stringValue == $0.1.stringValue }.count

let drop = decoder.state.count - keep
decoder.state.removeLast(count: drop)
let drop = state.count - keep
state.removeLast(count: drop)

for key in decoder.codingPath[decoder.state.count...] {
guard let container = decoder.state.container(forCodingPath: decoder.state.keyStack) else {
for key in decoder.codingPath[state.count...] {
guard let container = state.container(forCodingPath: state.keyStack) else {
fatalError("container should already be cached")
}
try decoder.state.step(into: container, key: key)
try state.step(into: container, key: key)
}

return try decoder.state.decode(value)
return try state.decode(value)
}

public static func intercepts(_ type: Decodable.Type) -> Bool {
Expand Down Expand Up @@ -600,7 +599,7 @@ public struct ASN1DecoderTransform: InternalDecoderTransform, InternalValueDeser
return nil
}

decoder.state.save(container: UnkeyedContainer(backing: collection), forCodingPath: decoder.codingPath)
decoder.state?.save(container: UnkeyedContainer(backing: collection), forCodingPath: decoder.codingPath)

return collection
}
Expand All @@ -613,7 +612,7 @@ public struct ASN1DecoderTransform: InternalDecoderTransform, InternalValueDeser
return nil
}

decoder.state.save(container: KeyedContainer(backing: structure), forCodingPath: decoder.codingPath)
decoder.state?.save(container: KeyedContainer(backing: structure), forCodingPath: decoder.codingPath)

return structure
}
Expand Down Expand Up @@ -643,7 +642,7 @@ extension SchemaState {
case badValue(Any, SchemaError.Context)
}

mutating func decode(_ value: ASN1) throws -> Any? {
func decode(_ value: ASN1) throws -> Any? {

for possibleState in currentPossibleStates {

Expand Down
25 changes: 12 additions & 13 deletions Sources/PotentASN1/ASN1Encoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,20 +94,19 @@ public struct ASN1EncoderTransform: InternalEncoderTransform, InternalValueSeria

static func encode(_ value: Any?, encoder: IVE) throws -> ASN1 {

if encoder.state == nil {
encoder.state = try SchemaState(initial: encoder.options.schema)
}
let state = try encoder.state ?? SchemaState(initial: encoder.options.schema)
encoder.state = state

let keep = zip(encoder.state.keyStack, encoder.codingPath).prefix { $0.0.stringValue == $0.1.stringValue }.count
let keep = zip(state.keyStack, encoder.codingPath).prefix { $0.0.stringValue == $0.1.stringValue }.count

let drop = encoder.state.count - keep
encoder.state.removeLast(count: drop)
let drop = state.count - keep
state.removeLast(count: drop)

for key in encoder.codingPath[encoder.state.count...] {
try encoder.state.step(into: encoder.container(depth: encoder.state.count), key: key)
for key in encoder.codingPath[state.count...] {
try state.step(into: encoder.container(depth: state.count), key: key)
}

return try encoder.state.encode(value)
return try state.encode(value)
}

public static func intercepts(_ type: Encodable.Type) -> Bool {
Expand Down Expand Up @@ -230,7 +229,7 @@ extension SchemaState {
case badValue(Any, SchemaError.Context)
}

mutating func encode(_ value: Any?) throws -> ASN1 {
func encode(_ value: Any?) throws -> ASN1 {

guard let encoded = try tryEncode(value) else {
let stateOptions = currentPossibleStates.map { $0.description }.joined(separator: " or ")
Expand All @@ -240,7 +239,7 @@ extension SchemaState {
return encoded
}

private mutating func tryEncode(_ value: Any?) throws -> ASN1? {
private func tryEncode(_ value: Any?) throws -> ASN1? {

for possibleState in currentPossibleStates {

Expand Down Expand Up @@ -599,7 +598,7 @@ extension SchemaState {


case .implicit(let tag, in: let tagClass, let implicitSchema):
var implicitSchemaState = try SchemaState(initial: implicitSchema)
let implicitSchemaState = try SchemaState(initial: implicitSchema)
let encoded: ASN1
if let taggedValue = value as? Tagged {
guard taggedValue.tag == tag else {
Expand All @@ -620,7 +619,7 @@ extension SchemaState {


case .explicit(let tag, in: let tagClass, let explicitSchema):
var explicitSchemaState = try SchemaState(initial: explicitSchema)
let explicitSchemaState = try SchemaState(initial: explicitSchema)
let encoded: ASN1
if let taggedValue = value as? Tagged {
guard taggedValue.tag == tag else {
Expand Down
3 changes: 1 addition & 2 deletions Sources/PotentASN1/Schema.swift
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,7 @@ public indirect enum Schema: Equatable, Hashable {
guard defaultValue != nil else {
return nil
}
var schemaState = try SchemaState(initial: unwrapDirectives)
return try schemaState.encode(nil)
return try SchemaState(initial: unwrapDirectives).encode(nil)
}

public var unwrapDirectives: Schema {
Expand Down
12 changes: 6 additions & 6 deletions Sources/PotentASN1/SchemaState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import PotentCodables
///
/// - Note: For internal use only.
///
public struct SchemaState {
public class SchemaState {

public enum SchemaError: Error {

Expand Down Expand Up @@ -77,7 +77,7 @@ public struct SchemaState {
var currentKey: CodingKey { keyStack.last! }
var currentPossibleStates: [State] { stateStack.last! }

mutating func removeLast(count: Int = 1) {
func removeLast(count: Int = 1) {
stateStack.removeLast(count)
keyStack.removeLast(count)
}
Expand All @@ -86,7 +86,7 @@ public struct SchemaState {
return containers[codingPath.map(\.stringValue)] ?? nil
}

mutating func save(container: Any?, forCodingPath codingPath: [CodingKey]) {
func save(container: Any?, forCodingPath codingPath: [CodingKey]) {
containers[codingPath.map(\.stringValue)] = container
}

Expand All @@ -100,18 +100,18 @@ public struct SchemaState {
return nil
}

mutating func save(scope container: KeyedContainer, forCodingPath codingPath: [CodingKey]) {
func save(scope container: KeyedContainer, forCodingPath codingPath: [CodingKey]) {
let path = codingPath.map(\.stringValue)
guard !scopes.keys.contains(path) else { return }

scopes[path] = Scope(container: container)
}

mutating func removeScope(forCodingPath codingPath: [CodingKey]) {
func removeScope(forCodingPath codingPath: [CodingKey]) {
scopes.removeValue(forKey: codingPath.map(\.stringValue))
}

mutating func step(into container: Any?, key: CodingKey) throws {
func step(into container: Any?, key: CodingKey) throws {
guard let currentPossibleStates = stateStack.last else { return }

if let keyed = container as? KeyedContainer {
Expand Down
2 changes: 1 addition & 1 deletion Sources/PotentCodables/ValueDecoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ public class InternalValueDecoder<Value, Transform>: Decoder where Transform: In

public let options: Transform.Options

public var state: Transform.State!
public var state: Transform.State?

/// The path to the current point in encoding.
public fileprivate(set) var codingPath: [CodingKey]
Expand Down
2 changes: 1 addition & 1 deletion Sources/PotentCodables/ValueEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public class InternalValueEncoder<Value, Transform>: Encoder where Transform: In
/// Options set on the top-level encoder.
public let options: Transform.Options

public var state: Transform.State!
public var state: Transform.State?

/// The path to the current point in encoding.
public fileprivate(set) var codingPath: [CodingKey]
Expand Down

0 comments on commit 16eebb4

Please sign in to comment.