Skip to content

Commit

Permalink
Adapt YAMLWriter to new libfyaml fixes and changes
Browse files Browse the repository at this point in the history
  • Loading branch information
kdubb committed Jun 10, 2024
1 parent fdb681c commit 3caa72a
Show file tree
Hide file tree
Showing 10 changed files with 589 additions and 312 deletions.
138 changes: 138 additions & 0 deletions Sources/PotentYAML/Cfyaml.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
//
// Cfyaml.swift
// PotentCodables
//
// Copyright © 2021 Outfox, inc.
//
//
// Distributed under the MIT License, See LICENSE for details.
//

import Cfyaml


enum Libfyaml {

internal static func createParser() -> OpaquePointer? {

guard let diag = createDiag(options: (FYET_ERROR, false, true)) else {
return nil
}
defer { fy_diag_unref(diag) }

var parseCfg = fy_parse_cfg(
search_path: nil,
flags: FYPCF_QUIET,
userdata: nil,
diag: diag
)

return fy_parser_create(&parseCfg)
}

internal typealias EmitterWriter = (String?) -> Void

internal typealias EmitterOutput = @convention(c) (
OpaquePointer?,
fy_emitter_write_type,
UnsafePointer<Int8>?,
Int32,
UnsafeMutableRawPointer?
) -> Int32

internal static func createEmitter(
flags: fy_emitter_cfg_flags,
output: EmitterOutput,
writer: UnsafePointer<EmitterWriter>
) -> OpaquePointer? {

guard let diag = createDiag(options: (FYET_ERROR, false, false)) else {
return nil
}
defer { fy_diag_unref(diag) }

var cfg = fy_emitter_cfg(
flags: flags,
output: output,
userdata: UnsafeMutableRawPointer(mutating: writer),
diag: diag
)

return fy_emitter_create(&cfg)
}

internal typealias DiagOptions = (level: fy_error_type, showSource: Bool, showPosition: Bool)

internal static func createDiag(options: DiagOptions) -> OpaquePointer? {

var diagCfg = fy_diag_cfg(
fp: nil,
output_fn: nil,
user: nil,
level: FYET_ERROR,
module_mask: UInt32.max,
colorize: false,
show_source: options.showSource,
show_position: options.showPosition,
show_type: false,
show_module: false,
source_width: Int32.max,
position_width: 4,
type_width: 0,
module_width: 0
)

guard let diag = fy_diag_create(&diagCfg) else {
return nil
}

fy_diag_set_collect_errors(diag, true)

return diag
}


}

extension fy_emitter_cfg_flags {

private static var indentMask = Self(UInt32(bitPattern: FYECF_INDENT_MASK))
private static var indentShift = Self(UInt32(bitPattern: FYECF_INDENT_SHIFT))

static func indent<R: RawRepresentable>(_ indent: R) -> Self where R.RawValue == UInt8 {
.indent(indent.rawValue)
}

static func indent(_ indent: UInt8) -> Self {
precondition(indent >= 0 && indent <= 9)
return (Self(UInt32(indent)) & .indentMask) << .indentShift
}

private static var widthMask = Self(UInt32(bitPattern: FYECF_WIDTH_MASK))
private static var widthShift = Self(UInt32(bitPattern: FYECF_WIDTH_SHIFT))

static func width<R: RawRepresentable>(_ width: R) -> Self where R.RawValue == UInt8 {
.width(width.rawValue)
}

static func width(_ width: UInt8) -> Self {
return (Self(UInt32(width)) & .widthMask) << .widthShift
}

static prefix func ~ (_ value: Self) -> Self {
return Self(~value.rawValue)
}

static func & (_ left: Self, _ right: Self) -> Self {
return Self(rawValue: left.rawValue & right.rawValue)
}

static func | (_ left: Self, _ right: Self) -> Self {
return Self(rawValue: left.rawValue | right.rawValue)
}

static func << (_ left: Self, _ right: Self) -> Self {
return Self(rawValue: left.rawValue << right.rawValue)
}

}
82 changes: 35 additions & 47 deletions Sources/PotentYAML/YAMLReader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,54 +11,28 @@
import Cfyaml
import Foundation


internal enum YAMLReader {

typealias Error = YAMLSerialization.Error

static func read(data: Data) throws -> YAML.Sequence {

var diagCfg =
fy_diag_cfg(
fp: nil,
output_fn: nil,
user: nil,
level: FYET_ERROR,
module_mask: UInt32.max,
colorize: false,
show_source: false,
show_position: true,
show_type: false,
show_module: false,
source_width: Int32.max,
position_width: 4,
type_width: 0,
module_width: 0
)
let diag = fy_diag_create(&diagCfg)
fy_diag_set_collect_errors(diag, true)
defer { fy_diag_destroy(diag) }

var parseCfg = fy_parse_cfg(search_path: nil, flags: FYPCF_QUIET, userdata: nil, diag: diag)

guard let parser = fy_parser_create(&parseCfg).map({ Parser(rawParser: $0, rawDiag: diag) }) else {
guard let parser = Libfyaml.createParser().map(Parser.init) else {
throw Error.unableToCreateParser
}

defer { parser.destroy() }

return try data.withUnsafeBytes { (ptr: UnsafeRawBufferPointer) in

let bytes = ptr.bindMemory(to: Int8.self)

fy_parser_set_string(parser.rawParser, bytes.baseAddress, bytes.count)
parser.setInput(ptr.bindMemory(to: CChar.self))

_ = try parser.expect(eventType: FYET_STREAM_START)
try parser.expect(eventType: FYET_STREAM_START)

return try stream(parser: parser)
}
}


static func stream(parser: Parser) throws -> YAML.Sequence {

var documents: YAML.Sequence = []
Expand Down Expand Up @@ -91,7 +65,7 @@ internal enum YAMLReader {

let document = try value(event: root, parser: parser)

_ = try parser.expect(eventType: FYET_DOCUMENT_END)
try parser.expect(eventType: FYET_DOCUMENT_END)

return document
}
Expand Down Expand Up @@ -263,58 +237,72 @@ internal enum YAMLReader {
struct Parser {

struct Event {
let rawEvent: UnsafeMutablePointer<fy_event>

var type: fy_event_type { rawEvent.pointee.type }
let event: UnsafeMutablePointer<fy_event>

init(_ event: UnsafeMutablePointer<fy_event>) {
self.event = event
}

var type: fy_event_type { event.pointee.type }

var anchor: String? {
guard let token = rawEvent.pointee.scalar.anchor else { return nil }
guard let token = event.pointee.scalar.anchor else { return nil }
return String(token: token)
}

var tag: String? {
guard let token = rawEvent.pointee.scalar.tag else { return nil }
guard let token = event.pointee.scalar.tag else { return nil }
return String(token: token)
}

var scalar: (String, fy_scalar_style)? {
guard let token = rawEvent.pointee.scalar.value else { return nil }
guard let token = event.pointee.scalar.value else { return nil }
return String(token: token).map { ($0, fy_token_scalar_style(token)) }
}

var style: fy_node_style {
return fy_event_get_node_style(rawEvent)
return fy_event_get_node_style(event)
}

}

let rawParser: OpaquePointer
let rawDiag: OpaquePointer?
let parser: OpaquePointer

func nextIfPresent() -> Event? {
return fy_parser_parse(rawParser).map { Event(rawEvent: $0) }
func setInput(_ bytes: UnsafeBufferPointer<CChar>) {

fy_parser_set_string(parser, bytes.baseAddress, bytes.count)
}

private func nextIfPresent() -> Event? {

return fy_parser_parse(parser).map(Event.init)
}

func next() throws -> Event {

guard let event = nextIfPresent() else {
throw error(fallback: .unexpectedEOF)
}

return event
}

func expect(eventType: fy_event_type) throws -> Event {
func expect(eventType: fy_event_type) throws {

let event = try next()
defer { free(event: event) }

if event.type != eventType {
throw error(fallback: .unexpectedEvent)
}

return event
}

func error(fallback: Error) -> Error {
guard let diag = rawDiag else { return fallback }

guard let diag = fy_parser_get_diag(parser) else {
return fallback
}

var prev: UnsafeMutableRawPointer?
if let error = fy_diag_errors_iterate(diag, &prev) {
Expand All @@ -327,11 +315,11 @@ internal enum YAMLReader {
}

func destroy() {
fy_parser_destroy(rawParser)
fy_parser_destroy(parser)
}

func free(event: Event) {
fy_parser_event_free(rawParser, event.rawEvent)
fy_parser_event_free(parser, event.event)
}

}
Expand Down
34 changes: 27 additions & 7 deletions Sources/PotentYAML/YAMLSerialization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public enum YAMLSerialization {
/// possible
public enum Error: Swift.Error {
case unableToCreateEmitter
case emitError
case emitError(message: String)
case unableToCreateParser
case parserError(message: String, line: Int, column: Int)
case unexpectedEOF
Expand Down Expand Up @@ -74,6 +74,7 @@ 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 let explictDocumentMarkers = WritingOptions(rawValue: 1 << 4)
}

public static func data(from yaml: YAML,
Expand Down Expand Up @@ -102,12 +103,13 @@ public enum YAMLSerialization {

var output = String()

try YAMLWriter.write([yaml],
preferredStyles: (preferredCollectionStyle, preferredStringStyle),
json: options.contains(.json),
pretty: options.contains(.pretty),
width: options.contains(.pretty) ? .normal : .infinite,
sortedKeys: options.contains(.sortedKeys)) {
let writerOptions = YAMLWriter.Options(
writingOptions: options,
preferredCollectionStyle: preferredCollectionStyle,
preferredStringStyle: preferredStringStyle
)

try YAMLWriter.write([yaml], options: writerOptions) {
guard let str = $0 else { return }
output.append(str)
}
Expand All @@ -116,3 +118,21 @@ public enum YAMLSerialization {
}

}

extension YAMLWriter.Options {

init(
writingOptions: YAMLSerialization.WritingOptions,
preferredCollectionStyle: YAML.CollectionStyle,
preferredStringStyle: YAML.StringStyle
) {
self.preferredCollectionStyle = preferredCollectionStyle
self.preferredStringStyle = preferredStringStyle
self.json = writingOptions.contains(.json)
self.pretty = writingOptions.contains(.pretty)
self.width = writingOptions.contains(.pretty) ? .normal : .infinite
self.sortedKeys = writingOptions.contains(.sortedKeys)
self.explicitDocumentMarkers = writingOptions.contains(.explictDocumentMarkers)
}

}
Loading

0 comments on commit 3caa72a

Please sign in to comment.