cbor.odin 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. package encoding_cbor
  2. import "base:intrinsics"
  3. import "core:encoding/json"
  4. import "core:io"
  5. import "core:mem"
  6. import "core:strconv"
  7. import "core:strings"
  8. // If we are decoding a stream of either a map or list, the initial capacity will be this value.
  9. INITIAL_STREAMED_CONTAINER_CAPACITY :: 8
  10. // If we are decoding a stream of either text or bytes, the initial capacity will be this value.
  11. INITIAL_STREAMED_BYTES_CAPACITY :: 16
  12. // The default maximum amount of bytes to allocate on a buffer/container at once to prevent
  13. // malicious input from causing massive allocations.
  14. DEFAULT_MAX_PRE_ALLOC :: mem.Kilobyte
  15. // Known/common headers are defined, undefined headers can still be valid.
  16. // Higher 3 bits is for the major type and lower 5 bits for the additional information.
  17. Header :: enum u8 {
  18. U8 = (u8(Major.Unsigned) << 5) | u8(Add.One_Byte),
  19. U16 = (u8(Major.Unsigned) << 5) | u8(Add.Two_Bytes),
  20. U32 = (u8(Major.Unsigned) << 5) | u8(Add.Four_Bytes),
  21. U64 = (u8(Major.Unsigned) << 5) | u8(Add.Eight_Bytes),
  22. Neg_U8 = (u8(Major.Negative) << 5) | u8(Add.One_Byte),
  23. Neg_U16 = (u8(Major.Negative) << 5) | u8(Add.Two_Bytes),
  24. Neg_U32 = (u8(Major.Negative) << 5) | u8(Add.Four_Bytes),
  25. Neg_U64 = (u8(Major.Negative) << 5) | u8(Add.Eight_Bytes),
  26. False = (u8(Major.Other) << 5) | u8(Add.False),
  27. True = (u8(Major.Other) << 5) | u8(Add.True),
  28. Nil = (u8(Major.Other) << 5) | u8(Add.Nil),
  29. Undefined = (u8(Major.Other) << 5) | u8(Add.Undefined),
  30. Simple = (u8(Major.Other) << 5) | u8(Add.One_Byte),
  31. F16 = (u8(Major.Other) << 5) | u8(Add.Two_Bytes),
  32. F32 = (u8(Major.Other) << 5) | u8(Add.Four_Bytes),
  33. F64 = (u8(Major.Other) << 5) | u8(Add.Eight_Bytes),
  34. Break = (u8(Major.Other) << 5) | u8(Add.Break),
  35. }
  36. // The higher 3 bits of the header which denotes what type of value it is.
  37. Major :: enum u8 {
  38. Unsigned,
  39. Negative,
  40. Bytes,
  41. Text,
  42. Array,
  43. Map,
  44. Tag,
  45. Other,
  46. }
  47. // The lower 3 bits of the header which denotes additional information for the type of value.
  48. Add :: enum u8 {
  49. False = 20,
  50. True = 21,
  51. Nil = 22,
  52. Undefined = 23,
  53. One_Byte = 24,
  54. Two_Bytes = 25,
  55. Four_Bytes = 26,
  56. Eight_Bytes = 27,
  57. Length_Unknown = 31,
  58. Break = Length_Unknown,
  59. }
  60. Value :: union {
  61. u8,
  62. u16,
  63. u32,
  64. u64,
  65. Negative_U8,
  66. Negative_U16,
  67. Negative_U32,
  68. Negative_U64,
  69. // Pointers so the size of the Value union stays small.
  70. ^Bytes,
  71. ^Text,
  72. ^Array,
  73. ^Map,
  74. ^Tag,
  75. Simple,
  76. f16,
  77. f32,
  78. f64,
  79. bool,
  80. Undefined,
  81. Nil,
  82. }
  83. Bytes :: []byte
  84. Text :: string
  85. Array :: []Value
  86. Map :: []Map_Entry
  87. Map_Entry :: struct {
  88. key: Value, // Can be any unsigned, negative, float, Simple, bool, Text.
  89. value: Value,
  90. }
  91. Tag :: struct {
  92. number: Tag_Number,
  93. value: Value, // Value based on the number.
  94. }
  95. Tag_Number :: u64
  96. Nil :: distinct rawptr
  97. Undefined :: distinct rawptr
  98. // A distinct atom-like number, range from `0..=19` and `32..=max(u8)`.
  99. Simple :: distinct u8
  100. Atom :: Simple
  101. Unmarshal_Error :: union #shared_nil {
  102. io.Error,
  103. mem.Allocator_Error,
  104. Decode_Data_Error,
  105. Unmarshal_Data_Error,
  106. Maybe(Unsupported_Type_Error),
  107. }
  108. Marshal_Error :: union #shared_nil {
  109. io.Error,
  110. mem.Allocator_Error,
  111. Encode_Data_Error,
  112. Marshal_Data_Error,
  113. Maybe(Unsupported_Type_Error),
  114. }
  115. Decode_Error :: union #shared_nil {
  116. io.Error,
  117. mem.Allocator_Error,
  118. Decode_Data_Error,
  119. }
  120. Encode_Error :: union #shared_nil {
  121. io.Error,
  122. mem.Allocator_Error,
  123. Encode_Data_Error,
  124. }
  125. Decode_Data_Error :: enum {
  126. None,
  127. Bad_Major, // An invalid major type was encountered.
  128. Bad_Argument, // A general unexpected value (most likely invalid additional info in header).
  129. Bad_Tag_Value, // When the type of value for the given tag is not valid.
  130. Nested_Indefinite_Length, // When an streamed/indefinite length container nests another, this is not allowed.
  131. Nested_Tag, // When a tag's value is another tag, this is not allowed.
  132. Length_Too_Big, // When the length of a container (map, array, bytes, string) is more than `max(int)`.
  133. Disallowed_Streaming, // When the `.Disallow_Streaming` flag is set and a streaming header is encountered.
  134. Break, // When the `break` header was found without any stream to break off.
  135. }
  136. Encode_Data_Error :: enum {
  137. None,
  138. Invalid_Simple, // When a simple is being encoded that is out of the range `0..=19` and `32..=max(u8)`.
  139. Int_Too_Big, // When an int is being encoded that is larger than `max(u64)` or smaller than `min(u64)`.
  140. Bad_Tag_Value, // When the type of value is not supported by the tag implementation.
  141. }
  142. Unmarshal_Data_Error :: enum {
  143. None,
  144. Invalid_Parameter, // When the given `any` can not be unmarshalled into.
  145. Non_Pointer_Parameter, // When the given `any` is not a pointer.
  146. }
  147. Marshal_Data_Error :: enum {
  148. None,
  149. Invalid_CBOR_Tag, // When the struct tag `cbor_tag:""` is not a registered name or number.
  150. }
  151. // Error that is returned when a type couldn't be marshalled into or out of, as much information
  152. // as possible/available is added.
  153. Unsupported_Type_Error :: struct {
  154. id: typeid,
  155. hdr: Header,
  156. add: Add,
  157. }
  158. _unsupported :: proc(v: any, hdr: Header, add: Add = nil) -> Maybe(Unsupported_Type_Error) {
  159. return Unsupported_Type_Error{
  160. id = v.id,
  161. hdr = hdr,
  162. add = add,
  163. }
  164. }
  165. // Actual value is `-1 - x` (be careful of overflows).
  166. Negative_U8 :: distinct u8
  167. Negative_U16 :: distinct u16
  168. Negative_U32 :: distinct u32
  169. Negative_U64 :: distinct u64
  170. // Turns the CBOR negative unsigned int type into a signed integer type.
  171. negative_to_int :: proc {
  172. negative_u8_to_int,
  173. negative_u16_to_int,
  174. negative_u32_to_int,
  175. negative_u64_to_int,
  176. }
  177. negative_u8_to_int :: #force_inline proc(u: Negative_U8) -> i16 {
  178. return -1 - i16(u)
  179. }
  180. negative_u16_to_int :: #force_inline proc(u: Negative_U16) -> i32 {
  181. return -1 - i32(u)
  182. }
  183. negative_u32_to_int :: #force_inline proc(u: Negative_U32) -> i64 {
  184. return -1 - i64(u)
  185. }
  186. negative_u64_to_int :: #force_inline proc(u: Negative_U64) -> i128 {
  187. return -1 - i128(u)
  188. }
  189. // Utility for converting between the different errors when they are subsets of the other.
  190. err_conv :: proc {
  191. encode_to_marshal_err,
  192. encode_to_marshal_err_p2,
  193. decode_to_unmarshal_err,
  194. decode_to_unmarshal_err_p,
  195. decode_to_unmarshal_err_p2,
  196. }
  197. encode_to_marshal_err :: #force_inline proc(err: Encode_Error) -> Marshal_Error {
  198. switch e in err {
  199. case nil: return nil
  200. case io.Error: return e
  201. case mem.Allocator_Error: return e
  202. case Encode_Data_Error: return e
  203. case: return nil
  204. }
  205. }
  206. encode_to_marshal_err_p2 :: #force_inline proc(v: $T, v2: $T2, err: Encode_Error) -> (T, T2, Marshal_Error) {
  207. return v, v2, err_conv(err)
  208. }
  209. decode_to_unmarshal_err :: #force_inline proc(err: Decode_Error) -> Unmarshal_Error {
  210. switch e in err {
  211. case nil: return nil
  212. case io.Error: return e
  213. case mem.Allocator_Error: return e
  214. case Decode_Data_Error: return e
  215. case: return nil
  216. }
  217. }
  218. decode_to_unmarshal_err_p :: #force_inline proc(v: $T, err: Decode_Error) -> (T, Unmarshal_Error) {
  219. return v, err_conv(err)
  220. }
  221. decode_to_unmarshal_err_p2 :: #force_inline proc(v: $T, v2: $T2, err: Decode_Error) -> (T, T2, Unmarshal_Error) {
  222. return v, v2, err_conv(err)
  223. }
  224. // Recursively frees all memory allocated when decoding the passed value.
  225. destroy :: proc(val: Value, allocator := context.allocator) {
  226. context.allocator = allocator
  227. #partial switch v in val {
  228. case ^Map:
  229. if v == nil { return }
  230. for entry in v {
  231. destroy(entry.key)
  232. destroy(entry.value)
  233. }
  234. delete(v^)
  235. free(v)
  236. case ^Array:
  237. if v == nil { return }
  238. for entry in v {
  239. destroy(entry)
  240. }
  241. delete(v^)
  242. free(v)
  243. case ^Text:
  244. if v == nil { return }
  245. delete(v^)
  246. free(v)
  247. case ^Bytes:
  248. if v == nil { return }
  249. delete(v^)
  250. free(v)
  251. case ^Tag:
  252. if v == nil { return }
  253. destroy(v.value)
  254. free(v)
  255. }
  256. }
  257. /*
  258. to_diagnostic_format either writes or returns a human-readable representation of the value,
  259. optionally formatted, defined as the diagnostic format in [[RFC 8949 Section 8;https://www.rfc-editor.org/rfc/rfc8949.html#name-diagnostic-notation]].
  260. Incidentally, if the CBOR does not contain any of the additional types defined on top of JSON
  261. this will also be valid JSON.
  262. */
  263. to_diagnostic_format :: proc {
  264. to_diagnostic_format_string,
  265. to_diagnostic_format_writer,
  266. }
  267. // Turns the given CBOR value into a human-readable string.
  268. // See docs on the proc group `diagnose` for more info.
  269. to_diagnostic_format_string :: proc(val: Value, padding := 0, allocator := context.allocator, loc := #caller_location) -> (string, mem.Allocator_Error) #optional_allocator_error {
  270. b := strings.builder_make(allocator, loc)
  271. w := strings.to_stream(&b)
  272. err := to_diagnostic_format_writer(w, val, padding)
  273. if err == .EOF {
  274. // The string builder stream only returns .EOF, and only if it can't write (out of memory).
  275. return "", .Out_Of_Memory
  276. }
  277. assert(err == nil)
  278. return strings.to_string(b), nil
  279. }
  280. // Writes the given CBOR value into the writer as human-readable text.
  281. // See docs on the proc group `diagnose` for more info.
  282. to_diagnostic_format_writer :: proc(w: io.Writer, val: Value, padding := 0) -> io.Error {
  283. @(require_results)
  284. indent :: proc(padding: int) -> int {
  285. padding := padding
  286. if padding != -1 {
  287. padding += 1
  288. }
  289. return padding
  290. }
  291. @(require_results)
  292. dedent :: proc(padding: int) -> int {
  293. padding := padding
  294. if padding != -1 {
  295. padding -= 1
  296. }
  297. return padding
  298. }
  299. comma :: proc(w: io.Writer, padding: int) -> io.Error {
  300. _ = io.write_string(w, ", " if padding == -1 else ",") or_return
  301. return nil
  302. }
  303. newline :: proc(w: io.Writer, padding: int) -> io.Error {
  304. if padding != -1 {
  305. io.write_string(w, "\n") or_return
  306. for _ in 0..<padding {
  307. io.write_string(w, "\t") or_return
  308. }
  309. }
  310. return nil
  311. }
  312. padding := padding
  313. switch v in val {
  314. case u8: io.write_uint(w, uint(v)) or_return
  315. case u16: io.write_uint(w, uint(v)) or_return
  316. case u32: io.write_uint(w, uint(v)) or_return
  317. case u64: io.write_u64(w, v) or_return
  318. case Negative_U8: io.write_int(w, int(negative_to_int(v))) or_return
  319. case Negative_U16: io.write_int(w, int(negative_to_int(v))) or_return
  320. case Negative_U32: io.write_int(w, int(negative_to_int(v))) or_return
  321. case Negative_U64: io.write_i128(w, i128(negative_to_int(v))) or_return
  322. // NOTE: not using io.write_float because it removes the sign,
  323. // which we want for the diagnostic format.
  324. case f16:
  325. buf: [64]byte
  326. str := strconv.append_float(buf[:], f64(v), 'f', 2*size_of(f16), 8*size_of(f16))
  327. if str[0] == '+' && str != "+Inf" { str = str[1:] }
  328. io.write_string(w, str) or_return
  329. case f32:
  330. buf: [128]byte
  331. str := strconv.append_float(buf[:], f64(v), 'f', 2*size_of(f32), 8*size_of(f32))
  332. if str[0] == '+' && str != "+Inf" { str = str[1:] }
  333. io.write_string(w, str) or_return
  334. case f64:
  335. buf: [256]byte
  336. str := strconv.append_float(buf[:], f64(v), 'f', 2*size_of(f64), 8*size_of(f64))
  337. if str[0] == '+' && str != "+Inf" { str = str[1:] }
  338. io.write_string(w, str) or_return
  339. case bool: io.write_string(w, "true" if v else "false") or_return
  340. case Nil: io.write_string(w, "nil") or_return
  341. case Undefined: io.write_string(w, "undefined") or_return
  342. case ^Bytes:
  343. io.write_string(w, "h'") or_return
  344. for b in v { io.write_int(w, int(b), 16) or_return }
  345. io.write_string(w, "'") or_return
  346. case ^Text:
  347. io.write_string(w, `"`) or_return
  348. io.write_string(w, v^) or_return
  349. io.write_string(w, `"`) or_return
  350. case ^Array:
  351. if v == nil || len(v) == 0 {
  352. io.write_string(w, "[]") or_return
  353. return nil
  354. }
  355. io.write_string(w, "[") or_return
  356. padding = indent(padding)
  357. newline(w, padding) or_return
  358. for entry, i in v {
  359. to_diagnostic_format(w, entry, padding) or_return
  360. if i != len(v)-1 {
  361. comma(w, padding) or_return
  362. newline(w, padding) or_return
  363. }
  364. }
  365. padding = dedent(padding)
  366. newline(w, padding) or_return
  367. io.write_string(w, "]") or_return
  368. case ^Map:
  369. if v == nil || len(v) == 0 {
  370. io.write_string(w, "{}") or_return
  371. return nil
  372. }
  373. io.write_string(w, "{") or_return
  374. padding = indent(padding)
  375. newline(w, padding) or_return
  376. for entry, i in v {
  377. to_diagnostic_format(w, entry.key, padding) or_return
  378. io.write_string(w, ": ") or_return
  379. to_diagnostic_format(w, entry.value, padding) or_return
  380. if i != len(v)-1 {
  381. comma(w, padding) or_return
  382. newline(w, padding) or_return
  383. }
  384. }
  385. padding = dedent(padding)
  386. newline(w, padding) or_return
  387. io.write_string(w, "}") or_return
  388. case ^Tag:
  389. io.write_u64(w, v.number) or_return
  390. io.write_string(w, "(") or_return
  391. to_diagnostic_format(w, v.value, padding) or_return
  392. io.write_string(w, ")") or_return
  393. case Simple:
  394. io.write_string(w, "simple(") or_return
  395. io.write_uint(w, uint(v)) or_return
  396. io.write_string(w, ")") or_return
  397. }
  398. return nil
  399. }
  400. /*
  401. Converts from JSON to CBOR.
  402. Everything is copied to the given allocator, the passed in JSON value can be deleted after.
  403. */
  404. from_json :: proc(val: json.Value, allocator := context.allocator) -> (Value, mem.Allocator_Error) #optional_allocator_error {
  405. internal :: proc(val: json.Value) -> (ret: Value, err: mem.Allocator_Error) {
  406. switch v in val {
  407. case json.Null: return Nil{}, nil
  408. case json.Integer:
  409. i, major := _int_to_uint(v)
  410. #partial switch major {
  411. case .Unsigned: return i, nil
  412. case .Negative: return Negative_U64(i), nil
  413. case: unreachable()
  414. }
  415. case json.Float: return v, nil
  416. case json.Boolean: return v, nil
  417. case json.String:
  418. container := new(Text) or_return
  419. // We need the string to have a nil byte at the end so we clone to cstring.
  420. container^ = string(strings.clone_to_cstring(v) or_return)
  421. return container, nil
  422. case json.Array:
  423. arr := new(Array) or_return
  424. arr^ = make([]Value, len(v)) or_return
  425. for _, i in arr {
  426. arr[i] = internal(v[i]) or_return
  427. }
  428. return arr, nil
  429. case json.Object:
  430. m := new(Map) or_return
  431. dm := make([dynamic]Map_Entry, 0, len(v)) or_return
  432. for mkey, mval in v {
  433. append(&dm, Map_Entry{from_json(mkey) or_return, from_json(mval) or_return})
  434. }
  435. m^ = dm[:]
  436. return m, nil
  437. }
  438. return nil, nil
  439. }
  440. context.allocator = allocator
  441. return internal(val)
  442. }
  443. /*
  444. Converts from CBOR to JSON.
  445. NOTE: overflow on integers or floats is not handled.
  446. Everything is copied to the given allocator, the passed in CBOR value can be `destroy`'ed after.
  447. If a CBOR map with non-string keys is encountered it is turned into an array of tuples.
  448. */
  449. to_json :: proc(val: Value, allocator := context.allocator) -> (json.Value, mem.Allocator_Error) #optional_allocator_error {
  450. internal :: proc(val: Value) -> (ret: json.Value, err: mem.Allocator_Error) {
  451. switch v in val {
  452. case Simple: return json.Integer(v), nil
  453. case u8: return json.Integer(v), nil
  454. case u16: return json.Integer(v), nil
  455. case u32: return json.Integer(v), nil
  456. case u64: return json.Integer(v), nil
  457. case Negative_U8: return json.Integer(negative_to_int(v)), nil
  458. case Negative_U16: return json.Integer(negative_to_int(v)), nil
  459. case Negative_U32: return json.Integer(negative_to_int(v)), nil
  460. case Negative_U64: return json.Integer(negative_to_int(v)), nil
  461. case f16: return json.Float(v), nil
  462. case f32: return json.Float(v), nil
  463. case f64: return json.Float(v), nil
  464. case bool: return json.Boolean(v), nil
  465. case Undefined: return json.Null{}, nil
  466. case Nil: return json.Null{}, nil
  467. case ^Bytes: return json.String(strings.clone(string(v^)) or_return), nil
  468. case ^Text: return json.String(strings.clone(v^) or_return), nil
  469. case ^Map:
  470. keys_all_strings :: proc(m: ^Map) -> bool {
  471. for entry in m {
  472. #partial switch kv in entry.key {
  473. case ^Bytes:
  474. case ^Text:
  475. case: return false
  476. }
  477. }
  478. return false
  479. }
  480. if keys_all_strings(v) {
  481. obj := make(json.Object, len(v)) or_return
  482. for entry in v {
  483. k: string
  484. #partial switch kv in entry.key {
  485. case ^Bytes: k = string(kv^)
  486. case ^Text: k = kv^
  487. case: unreachable()
  488. }
  489. v := internal(entry.value) or_return
  490. obj[k] = v
  491. }
  492. return obj, nil
  493. } else {
  494. // Resort to an array of tuples if keys aren't all strings.
  495. arr := make(json.Array, 0, len(v)) or_return
  496. for entry in v {
  497. entry_arr := make(json.Array, 0, 2) or_return
  498. append(&entry_arr, internal(entry.key) or_return) or_return
  499. append(&entry_arr, internal(entry.value) or_return) or_return
  500. append(&arr, entry_arr) or_return
  501. }
  502. return arr, nil
  503. }
  504. case ^Array:
  505. arr := make(json.Array, 0, len(v)) or_return
  506. for entry in v {
  507. append(&arr, internal(entry) or_return) or_return
  508. }
  509. return arr, nil
  510. case ^Tag:
  511. obj := make(json.Object, 2) or_return
  512. obj[strings.clone("number") or_return] = internal(v.number) or_return
  513. obj[strings.clone("value") or_return] = internal(v.value) or_return
  514. return obj, nil
  515. case: return json.Null{}, nil
  516. }
  517. }
  518. context.allocator = allocator
  519. return internal(val)
  520. }
  521. _int_to_uint :: proc {
  522. _i8_to_uint,
  523. _i16_to_uint,
  524. _i32_to_uint,
  525. _i64_to_uint,
  526. _i128_to_uint,
  527. }
  528. _u128_to_u64 :: #force_inline proc(v: u128) -> (u64, Encode_Data_Error) {
  529. if v > u128(max(u64)) {
  530. return 0, .Int_Too_Big
  531. }
  532. return u64(v), nil
  533. }
  534. _i8_to_uint :: #force_inline proc(v: i8) -> (u: u8, m: Major) {
  535. if v < 0 {
  536. return u8(abs(v)-1), .Negative
  537. }
  538. return u8(v), .Unsigned
  539. }
  540. _i16_to_uint :: #force_inline proc(v: i16) -> (u: u16, m: Major) {
  541. if v < 0 {
  542. return u16(abs(v)-1), .Negative
  543. }
  544. return u16(v), .Unsigned
  545. }
  546. _i32_to_uint :: #force_inline proc(v: i32) -> (u: u32, m: Major) {
  547. if v < 0 {
  548. return u32(abs(v)-1), .Negative
  549. }
  550. return u32(v), .Unsigned
  551. }
  552. _i64_to_uint :: #force_inline proc(v: i64) -> (u: u64, m: Major) {
  553. if v < 0 {
  554. return u64(abs(v)-1), .Negative
  555. }
  556. return u64(v), .Unsigned
  557. }
  558. _i128_to_uint :: proc(v: i128) -> (u: u64, m: Major, err: Encode_Data_Error) {
  559. if v < 0 {
  560. m = .Negative
  561. u, err = _u128_to_u64(u128(abs(v) - 1))
  562. return
  563. }
  564. m = .Unsigned
  565. u, err = _u128_to_u64(u128(v))
  566. return
  567. }