Skip to content

Commit

Permalink
YAML support JSON output and preferred string style
Browse files Browse the repository at this point in the history
  • Loading branch information
kdubb committed Jun 5, 2024
1 parent 0537566 commit 82fd696
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 72 deletions.
16 changes: 16 additions & 0 deletions Sources/PotentYAML/YAMLEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ public class YAMLEncoder: ValueEncoder<YAML, YAMLEncoderTransform>, EncodesToStr

/// Produce YAML with dictionary keys sorted in lexicographic order.
public static let sortedKeys = OutputFormatting(rawValue: 1 << 1)

/// Produce JSON compatible output.
public static let json = OutputFormatting(rawValue: 1 << 2)
}

/// The strategy to use for encoding `Date` values.
Expand Down Expand Up @@ -90,6 +93,9 @@ public class YAMLEncoder: ValueEncoder<YAML, YAMLEncoderTransform>, EncodesToStr
/// The preferred output style for sequences and mappings. Defaults to `.any`.
public var preferredCollectionStyle: YAML.CollectionStyle = .any

/// The preferred output style for strings. Defaults to `.any`.
public var preferredStringStyle: YAML.StringStyle = .any

/// The strategy to use in encoding dates. Defaults to `.deferredToDate`.
public var dateEncodingStrategy: DateEncodingStrategy = .deferredToDate

Expand All @@ -104,6 +110,7 @@ public class YAMLEncoder: ValueEncoder<YAML, YAMLEncoderTransform>, EncodesToStr
outputFormatting: outputFormatting,
keyEncodingStrategy: keyEncodingStrategy,
preferredCollectionStyle: preferredCollectionStyle,
preferredStringStyle: preferredStringStyle,
userInfo: userInfo
)
}
Expand Down Expand Up @@ -131,6 +138,7 @@ public struct YAMLEncoderTransform: InternalEncoderTransform, InternalValueSeria
public let outputFormatting: YAMLEncoder.OutputFormatting
public let keyEncodingStrategy: KeyEncodingStrategy
public let preferredCollectionStyle: YAML.CollectionStyle
public let preferredStringStyle: YAML.StringStyle
public let userInfo: [CodingUserInfoKey: Any]
}

Expand Down Expand Up @@ -373,8 +381,12 @@ public struct YAMLEncoderTransform: InternalEncoderTransform, InternalValueSeria
if options.outputFormatting.contains(.pretty) {
writingOptions.insert(.pretty)
}
if options.outputFormatting.contains(.json) {
writingOptions.insert(.json)
}
return try YAMLSerialization.data(from: value,
preferredCollectionStyle: options.preferredCollectionStyle,
preferredStringStyle: options.preferredStringStyle,
options: writingOptions)
}

Expand All @@ -386,8 +398,12 @@ public struct YAMLEncoderTransform: InternalEncoderTransform, InternalValueSeria
if options.outputFormatting.contains(.pretty) {
writingOptions.insert(.pretty)
}
if options.outputFormatting.contains(.json) {
writingOptions.insert(.json)
}
return try YAMLSerialization.string(from: value,
preferredCollectionStyle: options.preferredCollectionStyle,
preferredStringStyle: options.preferredStringStyle,
options: writingOptions)
}

Expand Down
7 changes: 6 additions & 1 deletion Sources/PotentYAML/YAMLSerialization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,17 @@ public enum YAMLSerialization {

public static let sortedKeys = WritingOptions(rawValue: 1 << 0)
public static let pretty = WritingOptions(rawValue: 1 << 1)
public static let json = WritingOptions(rawValue: 1 << 3)
}

public static func data(from yaml: YAML,
preferredCollectionStyle: YAML.CollectionStyle = .any,
preferredStringStyle: YAML.StringStyle = .any,
options: WritingOptions = []) throws -> Data {
guard
let data = try string(from: yaml,
preferredCollectionStyle: preferredCollectionStyle,
preferredStringStyle: preferredStringStyle,
options: options).data(using: .utf8)
else {
throw DecodingError
Expand All @@ -94,12 +97,14 @@ public enum YAMLSerialization {

public static func string(from yaml: YAML,
preferredCollectionStyle: YAML.CollectionStyle = .any,
preferredStringStyle: YAML.StringStyle = .any,
options: WritingOptions = []) throws -> String {

var output = String()

try YAMLWriter.write([yaml],
preferredCollectionStyle: preferredCollectionStyle,
preferredStyles: (preferredCollectionStyle, preferredStringStyle),
json: options.contains(.json),
pretty: options.contains(.pretty),
width: options.contains(.pretty) ? .normal : .infinite,
sortedKeys: options.contains(.sortedKeys)) {
Expand Down
128 changes: 57 additions & 71 deletions Sources/PotentYAML/YAMLWriter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,14 @@ internal struct YAMLWriter {
case infinite
}

let emitter: OpaquePointer
let sortedKeys: Bool
let preferredCollectionStyle: YAML.CollectionStyle
let preferredStringStyle: YAML.StringStyle

static func write(_ documents: YAML.Sequence,
preferredCollectionStyle: YAML.CollectionStyle = .block,
preferredStyles: (collection: YAML.CollectionStyle, string: YAML.StringStyle) = (.block, .plain),
json: Bool = false,
pretty: Bool = true,
width: Width = .normal,
sortedKeys: Bool = false,
Expand All @@ -51,7 +57,13 @@ internal struct YAMLWriter {

try withUnsafePointer(to: writer) { writerPtr in

var flags: UInt32 = pretty ? FYECF_MODE_PRETTY.rawValue : FYECF_DEFAULT.rawValue
var flags =
switch (pretty, json) {
case (true, true): FYECF_MODE_JSON.rawValue
case (true, false): FYECF_MODE_PRETTY.rawValue
case (false, true): FYECF_MODE_JSON_ONELINE.rawValue
default: FYECF_DEFAULT.rawValue
}

switch width {
case .normal:
Expand All @@ -74,83 +86,68 @@ internal struct YAMLWriter {
}
defer { fy_emitter_destroy(emitter) }

emit(emitter: emitter, type: FYET_STREAM_START)
let writer = YAMLWriter(
emitter: emitter,
sortedKeys: sortedKeys,
preferredCollectionStyle: preferredStyles.collection,
preferredStringStyle: preferredStyles.string
)

return try writer.emit(documents: documents)
}
}

private func emit(documents: [YAML]) throws {

try documents.forEach {
emit(emitter: emitter, type: FYET_DOCUMENT_START, args: 0, 0, 0)
emit(type: FYET_STREAM_START)

try emit(emitter: emitter,
value: $0,
preferredCollectionStyle: preferredCollectionStyle,
sortedKeys: sortedKeys)
for document in documents {
emit(type: FYET_DOCUMENT_START, args: 0, 0, 0)

emit(emitter: emitter, type: FYET_DOCUMENT_END)
}
try emit(value: document)

emit(emitter: emitter, type: FYET_STREAM_END)
emit(type: FYET_DOCUMENT_END)
}

emit(type: FYET_STREAM_END)
}

private static func emit(emitter: OpaquePointer,
value: YAML,
preferredCollectionStyle: YAML.CollectionStyle,
sortedKeys: Bool) throws {
private func emit(value: YAML) throws {

switch value {
case .null(anchor: let anchor):
emit(emitter: emitter, scalar: "null", style: FYSS_PLAIN, anchor: anchor, tag: nil)
emit(scalar: "null", style: FYSS_PLAIN, anchor: anchor, tag: nil)

case .string(let string, style: let style, tag: let tag, anchor: let anchor):
let scalarStyle = fy_scalar_style(rawValue: style.rawValue)
emit(emitter: emitter, scalar: string, style: scalarStyle, anchor: anchor, tag: tag?.rawValue)
let stringStyle = style != .any ? style : preferredStringStyle
let scalarStyle = fy_scalar_style(rawValue: stringStyle.rawValue)
emit(scalar: string, style: scalarStyle, anchor: anchor, tag: tag?.rawValue)

case .integer(let integer, anchor: let anchor):
emit(emitter: emitter, scalar: integer.value, style: FYSS_PLAIN, anchor: anchor, tag: nil)
emit(scalar: integer.value, style: FYSS_PLAIN, anchor: anchor, tag: nil)

case .float(let float, anchor: let anchor):
emit(emitter: emitter, scalar: float.value, style: FYSS_PLAIN, anchor: anchor, tag: nil)
emit(scalar: float.value, style: FYSS_PLAIN, anchor: anchor, tag: nil)

case .bool(let bool, anchor: let anchor):
emit(emitter: emitter, scalar: bool ? "true" : "false", style: FYSS_PLAIN, anchor: anchor, tag: nil)
emit(scalar: bool ? "true" : "false", style: FYSS_PLAIN, anchor: anchor, tag: nil)

case .sequence(let sequence, style: let style, tag: let tag, anchor: let anchor):
try emit(emitter: emitter,
sequence: sequence,
style: style,
preferredStyle: preferredCollectionStyle,
sortedKeys: sortedKeys,
anchor: anchor,
tag: tag)
try emit(sequence: sequence, style: style, anchor: anchor, tag: tag)

case .mapping(let mapping, style: let style, tag: let tag, anchor: let anchor):
try emit(emitter: emitter,
mapping: mapping,
style: style,
preferredStyle: preferredCollectionStyle,
sortedKeys: sortedKeys,
anchor: anchor,
tag: tag)
try emit(mapping: mapping, style: style, anchor: anchor, tag: tag)

case .alias(let alias):
emit(emitter: emitter, alias: alias)
emit(alias: alias)

}
}

private static func emit(
emitter: OpaquePointer,
mapping: YAML.Mapping,
style: YAML.CollectionStyle,
preferredStyle: YAML.CollectionStyle,
sortedKeys: Bool,
anchor: String?,
tag: YAML.Tag?
) throws {
private func emit(mapping: YAML.Mapping, style: YAML.CollectionStyle, anchor: String?, tag: YAML.Tag?) throws {
emit(
emitter: emitter,
type: FYET_MAPPING_START,
args: style.nodeStyle(preferred: preferredStyle).rawValue,
args: style.nodeStyle(preferred: preferredCollectionStyle).rawValue,
anchor.varArg,
(tag?.rawValue).varArg
)
Expand All @@ -161,36 +158,26 @@ internal struct YAMLWriter {
}
}
try mapping.forEach { entry in
try emit(emitter: emitter, value: entry.key, preferredCollectionStyle: preferredStyle, sortedKeys: sortedKeys)
try emit(emitter: emitter, value: entry.value, preferredCollectionStyle: preferredStyle, sortedKeys: sortedKeys)
try emit(value: entry.key)
try emit(value: entry.value)
}
emit(emitter: emitter, type: FYET_MAPPING_END)
emit(type: FYET_MAPPING_END)
}

private static func emit(
emitter: OpaquePointer,
sequence: [YAML],
style: YAML.CollectionStyle,
preferredStyle: YAML.CollectionStyle,
sortedKeys: Bool,
anchor: String?,
tag: YAML.Tag?
) throws {
private func emit(sequence: [YAML], style: YAML.CollectionStyle, anchor: String?, tag: YAML.Tag?) throws {
emit(
emitter: emitter,
type: FYET_SEQUENCE_START,
args: style.nodeStyle(preferred: preferredStyle).rawValue,
args: style.nodeStyle(preferred: preferredCollectionStyle).rawValue,
anchor.varArg,
(tag?.rawValue).varArg
)
try sequence.forEach { element in
try emit(emitter: emitter, value: element, preferredCollectionStyle: preferredStyle, sortedKeys: sortedKeys)
try emit(value: element)
}
emit(emitter: emitter, type: FYET_SEQUENCE_END)
emit(type: FYET_SEQUENCE_END)
}

private static func emit(
emitter: OpaquePointer,
private func emit(
scalar: String,
style: fy_scalar_style,
anchor: String?,
Expand All @@ -199,22 +186,21 @@ internal struct YAMLWriter {
scalar.withCString { scalarPtr in
anchor.withCString { anchorPtr in
tag.withCString { tagPtr in
emit(emitter: emitter, type: FYET_SCALAR, args: style.rawValue, scalarPtr, FY_NT, anchorPtr, tagPtr)
emit(type: FYET_SCALAR, args: style.rawValue, scalarPtr, FY_NT, anchorPtr, tagPtr)
}
}
}
}

private static func emit(
emitter: OpaquePointer,
private func emit(
alias: String
) {
alias.withCString { aliasPtr in
emit(emitter: emitter, type: FYET_ALIAS, args: aliasPtr)
emit(type: FYET_ALIAS, args: aliasPtr)
}
}

private static func emit(emitter: OpaquePointer, type: fy_event_type, args: CVarArg...) {
private func emit(type: fy_event_type, args: CVarArg...) {
withVaList(args) { valist in
let event = fy_emit_event_vcreate(emitter, type, valist)
fy_emit_event(emitter, event)
Expand Down
Loading

0 comments on commit 82fd696

Please sign in to comment.