writing.odin 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package uuid
  2. import "base:runtime"
  3. import "core:io"
  4. import "core:strconv"
  5. import "core:strings"
  6. /*
  7. Write a UUID in the 8-4-4-4-12 format.
  8. This procedure performs error checking with every byte written.
  9. If you can guarantee beforehand that your stream has enough space to hold the
  10. UUID (36 bytes), then it is better to use `unsafe_write` instead as that will
  11. be faster.
  12. Inputs:
  13. - w: A writable stream.
  14. - id: The identifier to convert.
  15. Returns:
  16. - error: An `io` error, if one occurred, otherwise `nil`.
  17. */
  18. write :: proc(w: io.Writer, id: Identifier) -> (error: io.Error) #no_bounds_check {
  19. write_octet :: proc(w: io.Writer, octet: u8) -> io.Error #no_bounds_check {
  20. high_nibble := octet >> 4
  21. low_nibble := octet & 0xF
  22. io.write_byte(w, strconv.digits[high_nibble]) or_return
  23. io.write_byte(w, strconv.digits[low_nibble]) or_return
  24. return nil
  25. }
  26. for index in 0 ..< 4 {write_octet(w, id[index]) or_return}
  27. io.write_byte(w, '-') or_return
  28. for index in 4 ..< 6 {write_octet(w, id[index]) or_return}
  29. io.write_byte(w, '-') or_return
  30. for index in 6 ..< 8 {write_octet(w, id[index]) or_return}
  31. io.write_byte(w, '-') or_return
  32. for index in 8 ..< 10 {write_octet(w, id[index]) or_return}
  33. io.write_byte(w, '-') or_return
  34. for index in 10 ..< 16 {write_octet(w, id[index]) or_return}
  35. return nil
  36. }
  37. /*
  38. Write a UUID in the 8-4-4-4-12 format.
  39. This procedure performs no error checking on the underlying stream.
  40. Inputs:
  41. - w: A writable stream.
  42. - id: The identifier to convert.
  43. */
  44. unsafe_write :: proc(w: io.Writer, id: Identifier) #no_bounds_check {
  45. write_octet :: proc(w: io.Writer, octet: u8) #no_bounds_check {
  46. high_nibble := octet >> 4
  47. low_nibble := octet & 0xF
  48. io.write_byte(w, strconv.digits[high_nibble])
  49. io.write_byte(w, strconv.digits[low_nibble])
  50. }
  51. for index in 0 ..< 4 {write_octet(w, id[index])}
  52. io.write_byte(w, '-')
  53. for index in 4 ..< 6 {write_octet(w, id[index])}
  54. io.write_byte(w, '-')
  55. for index in 6 ..< 8 {write_octet(w, id[index])}
  56. io.write_byte(w, '-')
  57. for index in 8 ..< 10 {write_octet(w, id[index])}
  58. io.write_byte(w, '-')
  59. for index in 10 ..< 16 {write_octet(w, id[index])}
  60. }
  61. /*
  62. Convert a UUID to a string in the 8-4-4-4-12 format.
  63. *Allocates Using Provided Allocator*
  64. Inputs:
  65. - id: The identifier to convert.
  66. - allocator: (default: context.allocator)
  67. - loc: The caller location for debugging purposes (default: #caller_location)
  68. Returns:
  69. - str: The allocated and converted string.
  70. - error: An optional allocator error if one occured, `nil` otherwise.
  71. */
  72. to_string_allocated :: proc(
  73. id: Identifier,
  74. allocator := context.allocator,
  75. loc := #caller_location,
  76. ) -> (
  77. str: string,
  78. error: runtime.Allocator_Error,
  79. ) #optional_allocator_error {
  80. buf := make([]byte, EXPECTED_LENGTH, allocator, loc) or_return
  81. builder := strings.builder_from_bytes(buf[:])
  82. unsafe_write(strings.to_writer(&builder), id)
  83. return strings.to_string(builder), nil
  84. }
  85. /*
  86. Convert a UUID to a string in the 8-4-4-4-12 format.
  87. Inputs:
  88. - id: The identifier to convert.
  89. - buffer: A byte buffer to store the result. Must be at least 36 bytes large.
  90. - loc: The caller location for debugging purposes (default: #caller_location)
  91. Returns:
  92. - str: The converted string which will be stored in `buffer`.
  93. */
  94. to_string_buffer :: proc(
  95. id: Identifier,
  96. buffer: []byte,
  97. loc := #caller_location,
  98. ) -> (
  99. str: string,
  100. ) {
  101. assert(
  102. len(buffer) >= EXPECTED_LENGTH,
  103. "The buffer provided is not at least 36 bytes large.",
  104. loc,
  105. )
  106. builder := strings.builder_from_bytes(buffer)
  107. unsafe_write(strings.to_writer(&builder), id)
  108. return strings.to_string(builder)
  109. }
  110. to_string :: proc {
  111. to_string_allocated,
  112. to_string_buffer,
  113. }