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

Adds support for NSDictionary, NSAray, NSValue and NSString #426

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
109 changes: 105 additions & 4 deletions Sources/Yams/Constructor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,19 @@ extension Constructor {
.omap: [Any].construct_omap,
.pairs: [Any].construct_pairs
]

///`Tag.Name` to `Node.Mapping` map that support dynamic collection.
public static let dynamicMappingMap: MappingMap = [
.map: NSMutableDictionary.construct_mapping,
.set: NSMutableSet.construct_set
]

///`Tag.Name` to `Node.Sequence` map that support dynamic collection.
public static let dynamicSequenceMap: SequenceMap = [
.seq: NSMutableArray.construct_seq,
.omap: NSMutableArray.construct_omap,
.pairs: NSMutableArray.construct_pairs
]
}

// MARK: - ScalarConstructible
Expand Down Expand Up @@ -252,12 +265,12 @@ extension ScalarConstructible where Self: FloatingPoint & SexagesimalConvertible
return nil
}

switch scalar.string {
case ".inf", ".Inf", ".INF", "+.inf", "+.Inf", "+.INF":
switch scalar.string.lowercased() {
case ".inf", "+.inf":
return .infinity
case "-.inf", "-.Inf", "-.INF":
case "-.inf":
return -.infinity
case ".nan", ".NaN", ".NAN":
case ".nan":
return .nan
default:
let string = scalar.string.replacingOccurrences(of: "_", with: "")
Expand Down Expand Up @@ -433,6 +446,31 @@ private extension Dictionary {
}
}

extension NSMutableDictionary {
/// Construct an `NSMutableDictionary`, if possible, from the specified mapping.
///
/// - parameter mapping: The `Node.Mapping` from which to extract an `NSMutableDictionary`, if possible.
///
/// - returns: An instance of `NSMutableDictionary`, if one was successfully extracted from the mapping.
public static func construct_mapping(from mapping: Node.Mapping) -> NSMutableDictionary? {
_construct_mapping(from: mapping)
}
}

private extension NSMutableDictionary {
static func _construct_mapping(from mapping: Node.Mapping) -> NSMutableDictionary {
let result = NSMutableDictionary()
let mapping = mapping.flatten()

mapping.forEach { key, value in
if let keyString = String.construct(from: key) {
result[keyString] = mapping.tag.constructor.any(from: value)
}
}
return result
}
}

extension Set {
/// Construct a `Set`, if possible, from the specified mapping.
///
Expand All @@ -447,6 +485,23 @@ extension Set {
}
}

extension NSMutableSet {
/// Construct an `NSMutableSet`, if possible, from the specified mapping.
///
/// - parameter mapping: The `Node.Mapping` from which to extract an `NSMutableSet`, if possible.
///
/// - returns: An instance of `NSMutableSet`, if one was successfully extracted from the mapping.
public static func construct_set(from mapping: Node.Mapping) -> NSMutableSet? {
let result = NSMutableSet()
mapping.forEach { key, _ in
if let keyString = String.construct(from: key) {
result.add(keyString as AnyHashable)
}
}
return result
}
}

// MARK: Sequence

extension Array {
Expand Down Expand Up @@ -488,6 +543,52 @@ extension Array {
}
}

extension NSMutableArray {
/// Construct an NSMutableArray of `Any` from the specified `sequence`.
///
/// - parameter sequence: Sequence to convert to `NSMutableArray`.
///
/// - returns: NSMutableArray of `Any`.
public static func construct_seq(from sequence: Node.Sequence) -> NSMutableArray {
let result = NSMutableArray()
sequence.forEach { subnode in
result.add(sequence.tag.constructor.any(from: subnode))
}
return result
}

/// Construct an "O-map" (NSMutableArray of `(Any, Any)` tuples) from the specified `sequence`.
///
/// - parameter sequence: Sequence to convert to `NSMutableArray`.
///
/// - returns: NSMutableArray of `(Any, Any)` tuples.
public static func construct_omap(from sequence: Node.Sequence) -> NSMutableArray {
let result = NSMutableArray()
sequence.forEach { subnode in
// TODO: Should raise error if subnode is not mapping or mapping.count != 1
if let (key, value) = subnode.mapping?.first {
result.add((sequence.tag.constructor.any(from: key), sequence.tag.constructor.any(from: value)))
}
}
return result
}

/// Construct an NSMutableArray of `(Any, Any)` tuples from the specified `sequence`.
///
/// - parameter sequence: Sequence to convert to `NSMutableArray`.
///
/// - returns: NSMutableArray of `(Any, Any)` tuples.
public static func construct_pairs(from sequence: Node.Sequence) -> NSMutableArray {
let result = NSMutableArray()
sequence.forEach { subnode in
if let (key, value) = subnode.mapping?.first {
result.add((sequence.tag.constructor.any(from: key), sequence.tag.constructor.any(from: value)))
}
}
return result
}
}

private extension String {
func substring(with range: NSRange) -> Substring? {
guard range.location != NSNotFound else { return nil }
Expand Down
31 changes: 31 additions & 0 deletions Sources/Yams/Representer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ extension Array: NodeRepresentable {
}
}

extension NSArray: NodeRepresentable {
/// This value's `Node` representation.
public func represented() throws -> Node {
let nodes = try map(represent)
return Node(nodes, Tag(.seq))
}
}

extension Dictionary: NodeRepresentable {
/// This value's `Node` representation.
public func represented() throws -> Node {
Expand All @@ -65,6 +73,14 @@ extension Dictionary: NodeRepresentable {
}
}

extension NSDictionary: NodeRepresentable {
/// This value's `Node` representation.
public func represented() throws -> Node {
let pairs = try map { (key: try represent($0.0), value: try represent($0.1)) }
return Node(pairs.sorted { $0.key < $1.key }, Tag(.map))
}
}

private func represent(_ value: Any) throws -> Node {
if let representable = value as? NodeRepresentable {
return try representable.represented()
Expand Down Expand Up @@ -187,6 +203,13 @@ extension Float: ScalarRepresentable {
}
}

extension NSValue: ScalarRepresentable {
/// This value's `Node.scalar` representation.
public func represented() -> Node.Scalar {
return .init(floatFormatter.string(for: self)!.replacingOccurrences(of: "+-", with: "-"), Tag(.float))
}
}

private func numberFormatter(with significantDigits: Int) -> NumberFormatter {
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "en_US")
Expand Down Expand Up @@ -258,6 +281,14 @@ extension String: ScalarRepresentable {
}
}

extension NSString: ScalarRepresentable {
/// This value's `Node.scalar` representation.
public func represented() -> Node.Scalar {
let scalar = Node.Scalar(String(self))
return scalar.resolvedTag.name == .str ? scalar : .init(String(self), Tag(.str), .singleQuoted)
}
}

extension UUID: ScalarRepresentable {
/// This value's `Node.scalar` representation.
public func represented() -> Node.Scalar {
Expand Down