Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

YAML support JSON output and preferred string style #71

Merged
merged 1 commit into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
Loading