Skip to content

Commit e80a5d9

Browse files
committed
Convert ipld.ts, update conversion document
1 parent 7e3e112 commit e80a5d9

2 files changed

Lines changed: 111 additions & 146 deletions

File tree

Conversion Documentation/common-web ipld conversion.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ We are using an `enum` for this.
1414

1515
## `export const jsonToIpld = (val: JsonValue): IpldValue`
1616

17-
This type has been converted.
17+
This type has been converted. It is also used in the custom `Decodable` method.
1818

1919
## `export const ipldToJson = (val: IpldValue): JsonValue`
2020

21-
This type has been converted.
21+
This type has been converted. It is also used in the custom `Encodable` method.
2222

2323
## `export const ipldEquals = (a: IpldValue, b: IpldValue): boolean`
2424

25-
This is redundant and will not be converted. The `struct` that contains these objects, including the objects themselves, will conform to `Hashable` instead.
25+
This is redundant and will not be converted. The `enum` that contains these objects, including the objects themselves, will conform to `Equatable` instead.

Sources/ATCommonWeb/TypeScript-bound/IPLD.swift

Lines changed: 108 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,19 @@
88
import Foundation
99
import MultiformatsKit
1010

11+
/// A namespace contains types and utilities for working with IPLD (InterPlanetary Linked Data) values,
12+
/// which are used to represent and encode arbitrary, self-describing, content-addressable data.
13+
public enum IPLD: Equatable {
1114

12-
public struct IPLD {
13-
14-
/// A type-safe and thread-safe representation of JSON-compatible values, used for encoding and
15-
/// decoding arbitrary JSON data.
15+
/// A type-safe and thread-safe representation of JSON-compatible values, used for encoding and decoding
16+
/// arbitrary JSON data.
1617
public enum JSONValue: Codable, Equatable, Hashable {
1718

1819
/// A `String` object.
1920
case string(String)
2021

2122
/// A `Double` object.
22-
case number(Double)
23+
case number(Int)
2324

2425
/// A `Bool` value.
2526
case bool(Bool)
@@ -40,7 +41,7 @@ public struct IPLD {
4041
self = .nil
4142
} else if let bool = try? container.decode(Bool.self) {
4243
self = .bool(bool)
43-
} else if let number = try? container.decode(Double.self) {
44+
} else if let number = try? container.decode(Int.self) {
4445
self = .number(number)
4546
} else if let string = try? container.decode(String.self) {
4647
self = .string(string)
@@ -65,147 +66,111 @@ public struct IPLD {
6566
try container.encode(value)
6667
case .nil:
6768
try container.encodeNil()
68-
case .array(let values):
69-
try container.encode(values)
70-
case .dictionary(let dictionary):
71-
try container.encode(dictionary)
69+
case .array(let value):
70+
try container.encode(value)
71+
case .dictionary(let value):
72+
try container.encode(value)
7273
}
7374
}
7475
}
7576

77+
/// An enum representing all valid IPLD (InterPlanetary Linked Data) values.
78+
public enum IPLDValue: Codable, Equatable, Hashable {
7679

77-
// TODO: Fix this to remove the errors.
78-
// public enum IPLDValue: Codable, Equatable, Hashable {
79-
//
80-
// /// A `String` object.
81-
// case string(String)
82-
//
83-
// /// A `Double` object.
84-
// case number(Double)
85-
//
86-
// /// A `Bool` object.
87-
// case bool(Bool)
88-
//
89-
// /// A `nil` object.
90-
// case `nil`
91-
//
92-
// /// An `Array` of `IPLDValue` objects.
93-
// case array([IPLDValue])
94-
//
95-
// /// A `Dictionary` object, with `IPLDValue` as the value.
96-
// case dictionary([String: IPLDValue])
97-
//
98-
// /// A `CID` object.
99-
// // case cid(CID)
100-
//
101-
// /// A `Data` object.
102-
// case bytes(Data)
103-
//
104-
// public init(from decoder: Decoder) throws {
105-
// let container = try decoder.singleValueContainer()
106-
//
107-
// if container.decodeNil() {
108-
// self = .nil
109-
// } else if let bool = try? container.decode(Bool.self) {
110-
// self = .bool(bool)
111-
// } else if let number = try? container.decode(Double.self) {
112-
// self = .number(number)
113-
// } else if let string = try? container.decode(String.self) {
114-
// self = .string(string)
115-
// } else if let array = try? container.decode([IPLDValue].self) {
116-
// self = .array(array)
117-
// } else if let object = try? container.decode([String: IPLDValue].self) {
118-
// self = .dictionary(object)
119-
// // } else if let cid = try? container.decode(CID.self) {
120-
// // self = .cid(cid)
121-
// } else if let data = try? container.decode(Data.self) {
122-
// self = .bytes(data)
123-
// } else {
124-
// throw DecodingError.dataCorruptedError(
125-
// in: container,
126-
// debugDescription: "Unsupported IPLD value"
127-
// )
128-
// }
129-
// }
130-
//
131-
// public func encode(to encoder: Encoder) throws {
132-
// var container = encoder.singleValueContainer()
133-
//
134-
// switch self {
135-
// case .string(let value):
136-
// try container.encode(value)
137-
// case .number(let value):
138-
// try container.encode(value)
139-
// case .bool(let value):
140-
// try container.encode(value)
141-
// case .nil:
142-
// try container.encodeNil()
143-
// case .array(let values):
144-
// try container.encode(values)
145-
// case .dictionary(let dictionary):
146-
// try container.encode(dictionary)
147-
// // case .cid(let cid):
148-
// // try container.encode(cid)
149-
// case .bytes(let data):
150-
// try container.encode(data)
151-
// }
152-
// }
153-
// }
154-
//
155-
// public static func jsonToIpld(_ value: JSONValue) -> IPLDValue {
156-
// switch value {
157-
// case .string(let str):
158-
// // Handle special IPLD markers
159-
// if let json = try? JSONSerialization.jsonObject(with: Data(str.utf8)) as? [String: Any],
160-
// let onlyKey = json.keys.first, json.count == 1 {
161-
// if onlyKey == "$link", let linkStr = json["$link"] as? String, let cid = try? CID(string: linkStr) {
162-
// return .cid(cid)
163-
// }
164-
// if onlyKey == "$bytes", let base64Str = json["$bytes"] as? String, let data = Data(base64Encoded: base64Str) {
165-
// return .bytes(data)
166-
// }
167-
// }
168-
// return .string(str)
169-
// case .number(let num):
170-
// return .number(num)
171-
// case .bool(let bool):
172-
// return .bool(bool)
173-
// case .nil:
174-
// return .nil
175-
// case .array(let arr):
176-
// return .array(arr.map { jsonToIpld($0) })
177-
// case .dictionary(let dict):
178-
// var newDict: [String: IPLDValue] = [:]
179-
// for (key, val) in dict {
180-
// newDict[key] = jsonToIpld(val)
181-
// }
182-
// return .dictionary(newDict)
183-
// }
184-
// }
185-
//
186-
// public static func ipldToJson(_ value: IPLDValue) -> JSONValue {
187-
// switch value {
188-
// case .string(let str):
189-
// return .string(str)
190-
// case .number(let num):
191-
// return .number(num)
192-
// case .bool(let bool):
193-
// return .bool(bool)
194-
// case .nil:
195-
// return .nil
196-
// case .array(let arr):
197-
// return .array(arr.map { ipldToJson($0) })
198-
// case .dictionary(let dict):
199-
// var newDict: [String: JSONValue] = [:]
200-
// for (key, val) in dict {
201-
// newDict[key] = ipldToJson(val)
202-
// }
203-
// return .dictionary(newDict)
204-
// case .cid(let cid):
205-
// return .dictionary(["$link": .string(cid.description)])
206-
// case .bytes(let data):
207-
// return .dictionary(["$bytes": .string(data.base64EncodedString())])
208-
// }
209-
// }
80+
/// A `JSONValue` object.
81+
case jsonValue(JSONValue)
21082

83+
/// A `CID` object.
84+
case cid(CID)
85+
86+
/// A `Data` object.
87+
case bytes(Data)
88+
89+
/// An array of `IPLDValue` objects.
90+
case array([IPLDValue])
91+
92+
/// A `Dictionary` object, with `IPLDValue` as the value.
93+
case dictionary([String: IPLDValue])
94+
95+
public init(from decoder: Decoder) throws {
96+
// Decode as JSONValue, then use the adapter to make IPLDValue.
97+
let jsonValue = try JSONValue(from: decoder)
98+
self = IPLD.jsonToIPLD(jsonValue)
99+
}
100+
101+
public func encode(to encoder: Encoder) throws {
102+
// Convert self to JSONValue, then encode.
103+
let jsonValue = IPLD.ipldToJSON(self)
104+
try jsonValue.encode(to: encoder)
105+
}
106+
}
107+
108+
/// Converts a `JSONValue` to `IPLDValue`.
109+
///
110+
/// - Parameter value: A `JSONValue` object.
111+
/// - Returns: An `IPLDValue` object.
112+
public static func jsonToIPLD(_ value: JSONValue) -> IPLDValue {
113+
switch value {
114+
case .array(let array):
115+
return .array(array.map { jsonToIPLD($0) })
116+
case .dictionary(let dictionary):
117+
// Special case for { "$link": "..." }
118+
if dictionary.count == 1, let jsonValue = dictionary["$link"], case let .string(linkString) = jsonValue {
119+
if let cid = try? CID(string: linkString) {
120+
return .cid(cid)
121+
}
122+
}
123+
124+
// Special case for { "$bytes": "..." }
125+
if dictionary.count == 1, let jsonValue = dictionary["$bytes"], case let .string(bytesString) = jsonValue {
126+
if let data = Data(base64Encoded: bytesString) {
127+
return .bytes(data)
128+
}
129+
}
130+
131+
// Plain object: recursively convert each value.
132+
var newDictionary: [String: IPLDValue] = [:]
133+
for (key, value) in dictionary {
134+
newDictionary[key] = jsonToIPLD(value)
135+
}
136+
137+
return .dictionary(newDictionary)
138+
case .string(let value):
139+
return .jsonValue(.string(value))
140+
case .number(let value):
141+
return .jsonValue(.number(value))
142+
case .bool(let value):
143+
return .jsonValue(.bool(value))
144+
case .nil:
145+
return .jsonValue(.nil)
146+
}
147+
}
148+
149+
/// Converts an `IPLDValue` to `JSONValue`.
150+
///
151+
/// - Parameter value: A `IPLDValue` object.
152+
/// - Returns: A `JSONValue` object.
153+
public static func ipldToJSON(_ value: IPLDValue) -> JSONValue {
154+
switch value {
155+
case .array(let array):
156+
return .array(array.map { ipldToJSON($0) })
157+
case .dictionary(let dictionary):
158+
var newDictionary: [String: JSONValue] = [:]
159+
for (key, value) in dictionary {
160+
newDictionary[key] = ipldToJSON(value)
161+
}
162+
163+
return .dictionary(newDictionary)
164+
case .cid(let cid):
165+
return .dictionary([
166+
"$link": .string((try? cid.encode()) ?? "")
167+
])
168+
case .bytes(let data):
169+
return .dictionary([
170+
"$bytes": .string(data.base64EncodedString())
171+
])
172+
case .jsonValue(let json):
173+
return json
174+
}
175+
}
211176
}

0 commit comments

Comments
 (0)