| 182 | } |
| 183 | |
| 184 | function normalizeAcyclic(value: unknown): unknown { |
| 185 | if (value instanceof Decimal) { |
| 186 | return { __decimal: value.toString() }; |
| 187 | } |
| 188 | if ( |
| 189 | value instanceof BoolArray || |
| 190 | value instanceof ForyFloat16Array || |
| 191 | value instanceof BFloat16Array |
| 192 | ) { |
| 193 | return Array.from(value as Iterable<unknown>, (item) => |
| 194 | normalizeAcyclic(item), |
| 195 | ); |
| 196 | } |
| 197 | if (value instanceof Date) { |
| 198 | return { __dateMs: value.getTime() }; |
| 199 | } |
| 200 | if (value instanceof Map) { |
| 201 | const entries = Array.from(value.entries()).map( |
| 202 | ([key, itemValue]) => |
| 203 | [normalizeAcyclic(key), normalizeAcyclic(itemValue)] as const, |
| 204 | ); |
| 205 | entries.sort((left, right) => |
| 206 | String(left[0]).localeCompare(String(right[0])), |
| 207 | ); |
| 208 | return entries; |
| 209 | } |
| 210 | if (ArrayBuffer.isView(value)) { |
| 211 | if (value instanceof DataView) { |
| 212 | return Array.from( |
| 213 | new Uint8Array(value.buffer, value.byteOffset, value.byteLength), |
| 214 | ); |
| 215 | } |
| 216 | return Array.from(value as unknown as ArrayLike<unknown>, (item) => |
| 217 | normalizeAcyclic(item), |
| 218 | ); |
| 219 | } |
| 220 | if (Array.isArray(value)) { |
| 221 | return value.map((item) => normalizeAcyclic(item)); |
| 222 | } |
| 223 | if (value != null && typeof value === "object") { |
| 224 | const entries = Object.entries(value as Record<string, unknown>); |
| 225 | entries.sort(([left], [right]) => left.localeCompare(right)); |
| 226 | return Object.fromEntries( |
| 227 | entries.map(([key, itemValue]) => [key, normalizeAcyclic(itemValue)]), |
| 228 | ); |
| 229 | } |
| 230 | return value; |
| 231 | } |
| 232 | |
| 233 | function assertAcyclicEqual<T>( |
| 234 | label: string, |