Smart Contract
Serialize
A.1e4aa0b87d10b141.Serialize
1import ViewResolver from 0x1d7e57aa55817448
2import MetadataViews from 0x1d7e57aa55817448
3import NonFungibleToken from 0x1d7e57aa55817448
4
5/// This contract is a utility for serializing primitive types, arrays, and common metadata mapping formats to JSON
6/// compatible strings. Also included are interfaces enabling custom serialization for structs and resources.
7///
8/// Special thanks to @austinkline for the idea and initial implementation & @bjartek + @bluesign for optimizations.
9///
10access(all)
11contract Serialize {
12
13 /// Method that returns a serialized representation of the given value or nil if the value is not serializable
14 ///
15 access(all)
16 fun tryToJSONString(_ value: AnyStruct): String? {
17 // Recursively serialize array & return
18 if value.getType().isSubtype(of: Type<[AnyStruct]>()) {
19 return self.arrayToJSONString(value as! [AnyStruct])
20 }
21 // Recursively serialize map & return
22 if value.getType().isSubtype(of: Type<{String: AnyStruct}>()) {
23 return self.dictToJSONString(dict: value as! {String: AnyStruct}, excludedNames: nil)
24 }
25 // Handle primitive types & optionals
26 switch value.getType() {
27 case Type<Never?>():
28 return "\"nil\""
29 case Type<String>():
30 return String.join(["\"", value as! String, "\"" ], separator: "")
31 case Type<String?>():
32 return String.join(["\"", value as? String ?? "nil", "\"" ], separator: "")
33 case Type<Character>():
34 return String.join(["\"", (value as! Character).toString(), "\"" ], separator: "")
35 case Type<Bool>():
36 return String.join(["\"", value as! Bool ? "true" : "false", "\"" ], separator: "")
37 case Type<Address>():
38 return String.join(["\"", (value as! Address).toString(), "\"" ], separator: "")
39 case Type<Address?>():
40 return String.join(["\"", (value as? Address)?.toString() ?? "nil", "\"" ], separator: "")
41 case Type<Int8>():
42 return String.join(["\"", (value as! Int8).toString(), "\"" ], separator: "")
43 case Type<Int16>():
44 return String.join(["\"", (value as! Int16).toString(), "\"" ], separator: "")
45 case Type<Int32>():
46 return String.join(["\"", (value as! Int32).toString(), "\"" ], separator: "")
47 case Type<Int64>():
48 return String.join(["\"", (value as! Int64).toString(), "\"" ], separator: "")
49 case Type<Int128>():
50 return String.join(["\"", (value as! Int128).toString(), "\"" ], separator: "")
51 case Type<Int256>():
52 return String.join(["\"", (value as! Int256).toString(), "\"" ], separator: "")
53 case Type<Int>():
54 return String.join(["\"", (value as! Int).toString(), "\"" ], separator: "")
55 case Type<UInt8>():
56 return String.join(["\"", (value as! UInt8).toString(), "\"" ], separator: "")
57 case Type<UInt16>():
58 return String.join(["\"", (value as! UInt16).toString(), "\"" ], separator: "")
59 case Type<UInt32>():
60 return String.join(["\"", (value as! UInt32).toString(), "\"" ], separator: "")
61 case Type<UInt64>():
62 return String.join(["\"", (value as! UInt64).toString(), "\"" ], separator: "")
63 case Type<UInt128>():
64 return String.join(["\"", (value as! UInt128).toString(), "\"" ], separator: "")
65 case Type<UInt256>():
66 return String.join(["\"", (value as! UInt256).toString(), "\"" ], separator: "")
67 case Type<UInt>():
68 return String.join(["\"", (value as! UInt).toString(), "\"" ], separator: "")
69 case Type<Word8>():
70 return String.join(["\"", (value as! Word8).toString(), "\"" ], separator: "")
71 case Type<Word16>():
72 return String.join(["\"", (value as! Word16).toString(), "\"" ], separator: "")
73 case Type<Word32>():
74 return String.join(["\"", (value as! Word32).toString(), "\"" ], separator: "")
75 case Type<Word64>():
76 return String.join(["\"", (value as! Word64).toString(), "\"" ], separator: "")
77 case Type<Word128>():
78 return String.join(["\"", (value as! Word128).toString(), "\"" ], separator: "")
79 case Type<Word256>():
80 return String.join(["\"", (value as! Word256).toString(), "\"" ], separator: "")
81 case Type<UFix64>():
82 return String.join(["\"", (value as! UFix64).toString(), "\"" ], separator: "")
83 default:
84 return nil
85 }
86 }
87
88 /// Returns a serialized representation of the given array or nil if the value is not serializable
89 ///
90 access(all)
91 fun arrayToJSONString(_ arr: [AnyStruct]): String? {
92 let parts: [String]= []
93 for element in arr {
94 let serializedElement = self.tryToJSONString(element)
95 if serializedElement == nil {
96 continue
97 }
98 parts.append(serializedElement!)
99 }
100 return "[".concat(String.join(parts, separator: ", ")).concat("]")
101 }
102
103 /// Returns a serialized representation of the given String-indexed mapping or nil if the value is not serializable.
104 /// The interface here is largely the same as as the `MetadataViews.dictToTraits` method, though here
105 /// a JSON-compatible String is returned instead of a `Traits` array.
106 ///
107 access(all)
108 fun dictToJSONString(dict: {String: AnyStruct}, excludedNames: [String]?): String? {
109 if excludedNames != nil {
110 for k in excludedNames! {
111 dict.remove(key: k)
112 }
113 }
114 let parts: [String] = []
115 for key in dict.keys {
116 let serializedValue = self.tryToJSONString(dict[key]!)
117 if serializedValue == nil {
118 continue
119 }
120 let serialializedKeyValue = String.join([self.tryToJSONString(key)!, serializedValue!], separator: ": ")
121 parts.append(serialializedKeyValue)
122 }
123 return "{".concat(String.join(parts, separator: ", ")).concat("}")
124 }
125}
126