diff --git a/spec/std/base64_spec.cr b/spec/std/base64_spec.cr index 567340d6fa38..9c1dbb90142d 100644 --- a/spec/std/base64_spec.cr +++ b/spec/std/base64_spec.cr @@ -54,11 +54,10 @@ describe "Base64" do assert_prints base64_strict_encode(slice), "" end - it "encodes static array" do - array = uninitialized StaticArray(UInt8, 5) - (0...5).each { |i| array[i] = 1_u8 } - assert_prints base64_encode(array), "AQEBAQE=\n" - assert_prints base64_strict_encode(array), "AQEBAQE=" + it "encodes calling `#to_slice`" do + data = "\x01\x01\x01\x01\x01" + assert_prints base64_encode(data), "AQEBAQE=\n" + assert_prints base64_strict_encode(data), "AQEBAQE=" end describe "base" do diff --git a/spec/std/crystal/digest/md5_spec.cr b/spec/std/crystal/digest/md5_spec.cr index 92363dddb4fd..ce4e2dcba1e0 100644 --- a/spec/std/crystal/digest/md5_spec.cr +++ b/spec/std/crystal/digest/md5_spec.cr @@ -23,8 +23,7 @@ describe Crystal::Digest::MD5 do end it "calculates hash of #to_slice" do - buffer = StaticArray(UInt8, 1).new(1_u8) - Crystal::Digest::MD5.hexdigest(buffer).should eq("55a54008ad1ba589aa210d2629c1df41") + Crystal::Digest::MD5.hexdigest("\x01").should eq("55a54008ad1ba589aa210d2629c1df41") end it "can take a block" do diff --git a/spec/std/digest/adler32_spec.cr b/spec/std/digest/adler32_spec.cr index 65511569283b..98eb75568704 100644 --- a/spec/std/digest/adler32_spec.cr +++ b/spec/std/digest/adler32_spec.cr @@ -23,8 +23,7 @@ describe Digest::Adler32 do end it "calculates hash of #to_slice" do - buffer = StaticArray(UInt8, 1).new(1_u8) - Digest::Adler32.hexdigest(buffer).should eq("00020002") + Digest::Adler32.hexdigest("\x01").should eq("00020002") end it "can take a block" do diff --git a/spec/std/digest/crc32_spec.cr b/spec/std/digest/crc32_spec.cr index fbd2997f9e26..e3769e78f012 100644 --- a/spec/std/digest/crc32_spec.cr +++ b/spec/std/digest/crc32_spec.cr @@ -23,8 +23,7 @@ describe Digest::CRC32 do end it "calculates hash of #to_slice" do - buffer = StaticArray(UInt8, 1).new(1_u8) - Digest::CRC32.hexdigest(buffer).should eq("a505df1b") + Digest::CRC32.hexdigest("\x01").should eq("a505df1b") end it "can take a block" do diff --git a/spec/std/digest/md5_spec.cr b/spec/std/digest/md5_spec.cr index 9e34d5394560..9b4f45c65ffc 100644 --- a/spec/std/digest/md5_spec.cr +++ b/spec/std/digest/md5_spec.cr @@ -23,8 +23,7 @@ describe Digest::MD5 do end it "calculates hash of #to_slice" do - buffer = StaticArray(UInt8, 1).new(1_u8) - Digest::MD5.hexdigest(buffer).should eq("55a54008ad1ba589aa210d2629c1df41") + Digest::MD5.hexdigest("\x01").should eq("55a54008ad1ba589aa210d2629c1df41") end it "can take a block" do diff --git a/spec/std/http/chunked_content_spec.cr b/spec/std/http/chunked_content_spec.cr index c8a659f11bbb..a8a9b381b435 100644 --- a/spec/std/http/chunked_content_spec.cr +++ b/spec/std/http/chunked_content_spec.cr @@ -6,9 +6,9 @@ describe HTTP::ChunkedContent do mem = IO::Memory.new("4\r\n123\n\r\n0\r\n\r\n") content = HTTP::ChunkedContent.new(mem) bytes = uninitialized UInt8[4] - bytes_read = content.read(bytes.to_slice) + bytes_read = content.read(bytes.to_unsafe_slice) bytes_read.should eq(4) - String.new(bytes.to_slice).should eq("123\n") + String.new(bytes.to_unsafe_slice).should eq("123\n") mem.pos.should eq(7) # only this chunk was read end diff --git a/spec/std/http/web_socket_spec.cr b/spec/std/http/web_socket_spec.cr index 75a54e91fb2e..22aee803e2de 100644 --- a/spec/std/http/web_socket_spec.cr +++ b/spec/std/http/web_socket_spec.cr @@ -203,7 +203,7 @@ describe HTTP::WebSocket do io = IO::Memory.new ws = HTTP::WebSocket::Protocol.new(io, masked: true) - ws.send(sent_bytes.to_slice) + ws.send(sent_bytes.to_unsafe_slice) bytes = io.to_slice (bytes[0] & 0x0f).should eq(0x02) end diff --git a/spec/std/io/hexdump_spec.cr b/spec/std/io/hexdump_spec.cr index f8d3acd1cbd2..462975cd2b31 100644 --- a/spec/std/io/hexdump_spec.cr +++ b/spec/std/io/hexdump_spec.cr @@ -22,8 +22,8 @@ describe IO::Hexdump do w.write(slice) buf = uninitialized UInt8[101] - r.read_fully(buf.to_slice).should eq(101) - buf.to_slice.should eq(slice) + r.read_fully(buf.to_unsafe_slice).should eq(101) + buf.to_unsafe_slice.should eq(slice) io.to_s.should eq("#{ascii_table}\n") end @@ -49,8 +49,8 @@ describe IO::Hexdump do w.write(slice) buf = uninitialized UInt8[96] - r.read_fully(buf.to_slice).should eq(96) - buf.to_slice.should eq(slice) + r.read_fully(buf.to_unsafe_slice).should eq(96) + buf.to_unsafe_slice.should eq(slice) io.to_s.should eq("#{ascii_table}\n") end diff --git a/spec/std/io/io_spec.cr b/spec/std/io/io_spec.cr index b73640e61918..4a38b6b26388 100644 --- a/spec/std/io/io_spec.cr +++ b/spec/std/io/io_spec.cr @@ -696,9 +696,9 @@ describe IO do io.set_encoding("EUC-JP") buffer = uninitialized UInt8[1024] - bytes_read = io.read_utf8(buffer.to_slice) # => 3 + bytes_read = io.read_utf8(buffer.to_unsafe_slice) # => 3 bytes_read.should eq(3) - buffer.to_slice[0, bytes_read].to_a.should eq("好".bytes) + buffer.to_unsafe_slice[0, bytes_read].to_a.should eq("好".bytes) end it "raises on incomplete byte sequence" do diff --git a/spec/std/socket/udp_socket_spec.cr b/spec/std/socket/udp_socket_spec.cr index 113a4ea3cf61..3cb44e4e358f 100644 --- a/spec/std/socket/udp_socket_spec.cr +++ b/spec/std/socket/udp_socket_spec.cr @@ -55,16 +55,16 @@ describe UDPSocket, tags: "network" do buffer = uninitialized UInt8[256] - bytes_read, client_addr = server.receive(buffer.to_slice) - message = String.new(buffer.to_slice[0, bytes_read]) + bytes_read, client_addr = server.receive(buffer.to_unsafe_slice) + message = String.new(buffer.to_unsafe_slice[0, bytes_read]) message.should eq("laus deo semper") client.send("laus deo semper") # WSA errors with WSAEMSGSIZE if the buffer is not large enough to receive the message {% unless flag?(:win32) %} - bytes_read, client_addr = server.receive(buffer.to_slice[0, 4]) - message = String.new(buffer.to_slice[0, bytes_read]) + bytes_read, client_addr = server.receive(buffer.to_unsafe_slice[0, 4]) + message = String.new(buffer.to_unsafe_slice[0, bytes_read]) message.should eq("laus") {% end %} diff --git a/src/char.cr b/src/char.cr index 4047db2b4caa..8ccf14920632 100644 --- a/src/char.cr +++ b/src/char.cr @@ -989,7 +989,7 @@ struct Char chars[i] = byte i += 1 end - io.write_string chars.to_slice[0, i] + io.write_string chars.to_unsafe_slice[0, i] end end diff --git a/src/compress/deflate/reader.cr b/src/compress/deflate/reader.cr index d4c6d13d21cf..74563e6237c4 100644 --- a/src/compress/deflate/reader.cr +++ b/src/compress/deflate/reader.cr @@ -77,7 +77,7 @@ class Compress::Deflate::Reader < IO # the compressed data (for example, if the compressed stream # is part of a zip/gzip file). @stream.next_in = @buf.to_unsafe - @stream.avail_in = @io.read(@buf.to_slice).to_u32 + @stream.avail_in = @io.read(@buf.to_unsafe_slice).to_u32 end end diff --git a/src/compress/deflate/writer.cr b/src/compress/deflate/writer.cr index f9a5adeb366f..b40bf976f8ff 100644 --- a/src/compress/deflate/writer.cr +++ b/src/compress/deflate/writer.cr @@ -90,7 +90,7 @@ class Compress::Deflate::Writer < IO @stream.next_out = @buf.to_unsafe @stream.avail_out = @buf.size.to_u32 LibZ.deflate(pointerof(@stream), flush) # no bad return value - @output.write(@buf.to_slice[0, @buf.size - @stream.avail_out]) + @output.write(@buf.to_unsafe_slice[0, @buf.size - @stream.avail_out]) break if @stream.avail_out != 0 end end diff --git a/src/compress/gzip/header.cr b/src/compress/gzip/header.cr index a99027f59004..2ce21ae689c5 100644 --- a/src/compress/gzip/header.cr +++ b/src/compress/gzip/header.cr @@ -26,7 +26,7 @@ class Compress::Gzip::Header def initialize(first_byte : UInt8, io : IO) header = uninitialized UInt8[10] header[0] = first_byte - io.read_fully(header.to_slice + 1) + io.read_fully(header.to_unsafe_slice + 1) if header[0] != ID1 || header[1] != ID2 || header[2] != DEFLATE raise Error.new("Invalid gzip header") @@ -34,7 +34,7 @@ class Compress::Gzip::Header flg = Flg.new(header[3]) - seconds = IO::ByteFormat::LittleEndian.decode(Int32, header.to_slice[4, 4]) + seconds = IO::ByteFormat::LittleEndian.decode(Int32, header.to_unsafe_slice[4, 4]) @modification_time = Time.unix(seconds).to_local xfl = header[8] diff --git a/src/crystal/hasher.cr b/src/crystal/hasher.cr index 0c80fe5a0c50..227a86cdc229 100644 --- a/src/crystal/hasher.cr +++ b/src/crystal/hasher.cr @@ -80,7 +80,7 @@ struct Crystal::Hasher HASH_INF_MINUS = (-314159_i64).unsafe_as(UInt64) @@seed = uninitialized UInt64[2] - Crystal::System::Random.random_bytes(@@seed.to_slice.to_unsafe_bytes) + Crystal::System::Random.random_bytes(@@seed.to_unsafe_slice.to_unsafe_bytes) def initialize(@a : UInt64 = @@seed[0], @b : UInt64 = @@seed[1]) end diff --git a/src/crystal/system/unix.cr b/src/crystal/system/unix.cr index 136472b79535..05855f3abc72 100644 --- a/src/crystal/system/unix.cr +++ b/src/crystal/system/unix.cr @@ -2,7 +2,7 @@ module Crystal::System def self.retry_with_buffer(function_name, max_buffer, &) initial_buf = uninitialized UInt8[1024] - buf = initial_buf + buf = initial_buf.to_unsafe_slice while (ret = yield buf.to_slice) != 0 case ret diff --git a/src/crystal/system/unix/getrandom.cr b/src/crystal/system/unix/getrandom.cr index 7be835ff5ab9..5ecd0c541a24 100644 --- a/src/crystal/system/unix/getrandom.cr +++ b/src/crystal/system/unix/getrandom.cr @@ -63,7 +63,7 @@ module Crystal::System::Random if @@getrandom_available buf = uninitialized UInt8[1] - getrandom(buf.to_slice) + getrandom(buf.to_unsafe_slice) buf.unsafe_as(UInt8) elsif urandom = @@urandom urandom.read_byte.not_nil! diff --git a/src/digest/digest.cr b/src/digest/digest.cr index c55d2a84ead1..74f8555c23a9 100644 --- a/src/digest/digest.cr +++ b/src/digest/digest.cr @@ -198,7 +198,7 @@ abstract class Digest raise "Digest#hexfinal(IO) can't handle digest_size over 64 bits" end sary = uninitialized StaticArray(UInt8, 128) - tmp = sary.to_slice[0, digest_size * 2] + tmp = sary.to_unsafe_slice[0, digest_size * 2] hexfinal tmp io << tmp end @@ -222,8 +222,8 @@ abstract class Digest # Reads the io's data and updates the digest with it. def update(io : IO) : self buffer = uninitialized UInt8[IO::DEFAULT_BUFFER_SIZE] - while (read_bytes = io.read(buffer.to_slice)) > 0 - self << buffer.to_slice[0, read_bytes] + while (read_bytes = io.read(buffer.to_unsafe_slice)) > 0 + self << buffer.to_unsafe_slice[0, read_bytes] end self end diff --git a/src/float/printer.cr b/src/float/printer.cr index 8fa64dd5072c..25ffcb118d04 100644 --- a/src/float/printer.cr +++ b/src/float/printer.cr @@ -35,7 +35,7 @@ module Float::Printer end # remove trailing zeros - buffer = str.to_slice[ptr - str.to_unsafe..] + buffer = str.to_unsafe_slice[ptr - str.to_unsafe..] while buffer.size > 1 && buffer.unsafe_fetch(buffer.size - 1) === '0' buffer = buffer[..-2] decimal_exponent += 1 diff --git a/src/http/common.cr b/src/http/common.cr index b2139194b045..66bc1a7134ee 100644 --- a/src/http/common.cr +++ b/src/http/common.cr @@ -297,10 +297,10 @@ module HTTP def self.serialize_chunked_body(io, body) buf = uninitialized UInt8[8192] - while (buf_length = body.read(buf.to_slice)) > 0 + while (buf_length = body.read(buf.to_unsafe_slice)) > 0 buf_length.to_s(io, 16) io << "\r\n" - io.write(buf.to_slice[0, buf_length]) + io.write(buf.to_unsafe_slice[0, buf_length]) io << "\r\n" end io << "0\r\n\r\n" diff --git a/src/http/web_socket/protocol.cr b/src/http/web_socket/protocol.cr index 2ae1c9e81ce9..5497691fd917 100644 --- a/src/http/web_socket/protocol.cr +++ b/src/http/web_socket/protocol.cr @@ -138,7 +138,7 @@ class HTTP::WebSocket::Protocol key = Random::DEFAULT.next_int mask_array = key.unsafe_as(StaticArray(UInt8, 4)) - @io.write mask_array.to_slice + @io.write mask_array.to_unsafe_slice write_masked_data(data, mask_array) end @@ -162,7 +162,7 @@ class HTTP::WebSocket::Protocol end # Write the masked data - @io.write(masked_data.to_slice[0, chunk_size]) + @io.write(masked_data.to_unsafe_slice[0, chunk_size]) # Discard the written data remaining_data = remaining_data[chunk_size..] @@ -172,14 +172,14 @@ class HTTP::WebSocket::Protocol private def read_header # First byte: FIN (1 bit), RSV1,2,3 (3 bits), Opcode (4 bits) # Second byte: MASK (1 bit), Payload Length (7 bits) - @io.read_fully(@header.to_slice) + @io.read_fully(@header.to_unsafe_slice) opcode = read_opcode @remaining = read_size # Read mask, if needed if masked? - @io.read_fully(@mask.to_slice) + @io.read_fully(@mask.to_unsafe_slice) @mask_offset = 0 end @@ -308,7 +308,7 @@ class HTTP::WebSocket::Protocol end {% end %} - random_key = Base64.strict_encode(StaticArray(UInt8, 16).new { rand(256).to_u8 }) + random_key = Base64.strict_encode(StaticArray(UInt8, 16).new { rand(256).to_u8 }.to_unsafe_slice) headers["Host"] = "#{host}:#{port}" headers["Connection"] = "Upgrade" @@ -356,7 +356,7 @@ class HTTP::WebSocket::Protocol {% if flag?(:without_openssl) %} ::Crystal::Digest::SHA1.base64digest(key + GUID) {% else %} - Base64.strict_encode(OpenSSL::SHA1.hash(key + GUID)) + Base64.strict_encode(OpenSSL::SHA1.hash(key + GUID).to_unsafe_slice) {% end %} end end diff --git a/src/io.cr b/src/io.cr index c159c77776b5..d66a50280d1f 100644 --- a/src/io.cr +++ b/src/io.cr @@ -869,7 +869,7 @@ abstract class IO def skip(bytes_count : Int) : Nil buffer = uninitialized UInt8[DEFAULT_BUFFER_SIZE] while bytes_count > 0 - read_count = read(buffer.to_slice[0, Math.min(bytes_count, buffer.size)]) + read_count = read(buffer.to_unsafe_slice[0, Math.min(bytes_count, buffer.size)]) raise IO::EOFError.new if read_count == 0 bytes_count -= read_count @@ -880,7 +880,7 @@ abstract class IO # are no more bytes. def skip_to_end : Nil buffer = uninitialized UInt8[DEFAULT_BUFFER_SIZE] - while read(buffer.to_slice) > 0 + while read(buffer.to_unsafe_slice) > 0 end end @@ -1173,8 +1173,8 @@ abstract class IO def self.copy(src, dst) : Int64 buffer = uninitialized UInt8[DEFAULT_BUFFER_SIZE] count = 0_i64 - while (len = src.read(buffer.to_slice).to_i32) > 0 - dst.write buffer.to_slice[0, len] + while (len = src.read(buffer.to_unsafe_slice).to_i32) > 0 + dst.write buffer.to_unsafe_slice[0, len] count &+= len end count @@ -1197,8 +1197,8 @@ abstract class IO buffer = uninitialized UInt8[DEFAULT_BUFFER_SIZE] remaining = limit - while (len = src.read(buffer.to_slice[0, Math.min(buffer.size, Math.max(remaining, 0))])) > 0 - dst.write buffer.to_slice[0, len] + while (len = src.read(buffer.to_unsafe_slice[0, Math.min(buffer.size, Math.max(remaining, 0))])) > 0 + dst.write buffer.to_unsafe_slice[0, len] remaining &-= len end limit - remaining @@ -1218,8 +1218,8 @@ abstract class IO buf2 = uninitialized UInt8[1024] while true - read1 = stream1.read(buf1.to_slice) - read2 = stream2.read_fully?(buf2.to_slice[0, read1]) + read1 = stream1.read(buf1.to_unsafe_slice) + read2 = stream2.read_fully?(buf2.to_unsafe_slice[0, read1]) return false unless read2 return false if buf1.to_unsafe.memcmp(buf2.to_unsafe, read1) != 0 diff --git a/src/io/byte_format.cr b/src/io/byte_format.cr index d8f7e4cb5e71..1e72a5447e2a 100644 --- a/src/io/byte_format.cr +++ b/src/io/byte_format.cr @@ -128,18 +128,18 @@ module IO::ByteFormat def self.encode(int : {{type.id}}, io : IO) buffer = int.unsafe_as(StaticArray(UInt8, {{bytesize}})) buffer.reverse! unless SystemEndian == self - io.write(buffer.to_slice) + io.write(buffer.to_unsafe_slice) end def self.encode(int : {{type.id}}, bytes : Bytes) buffer = int.unsafe_as(StaticArray(UInt8, {{bytesize}})) buffer.reverse! unless SystemEndian == self - buffer.to_slice.copy_to(bytes) + buffer.to_unsafe_slice.copy_to(bytes) end def self.decode(int : {{type.id}}.class, io : IO) buffer = uninitialized UInt8[{{bytesize}}] - io.read_fully(buffer.to_slice) + io.read_fully(buffer.to_unsafe_slice) buffer.reverse! unless SystemEndian == self buffer.unsafe_as({{type.id}}) end diff --git a/src/io/encoding.cr b/src/io/encoding.cr index 733e6b199168..04690456d39a 100644 --- a/src/io/encoding.cr +++ b/src/io/encoding.cr @@ -43,7 +43,7 @@ class IO if err == Crystal::Iconv::ERROR @iconv.handle_invalid(pointerof(inbuf_ptr), pointerof(inbytesleft)) end - io.write(outbuf.to_slice[0, outbuf.size - outbytesleft]) + io.write(outbuf.to_unsafe_slice[0, outbuf.size - outbytesleft]) end end diff --git a/src/openssl/ssl/hostname_validation.cr b/src/openssl/ssl/hostname_validation.cr index 8c0a787e6541..4988dabb3854 100644 --- a/src/openssl/ssl/hostname_validation.cr +++ b/src/openssl/ssl/hostname_validation.cr @@ -49,14 +49,14 @@ module OpenSSL::SSL::HostnameValidation case data.size when 4 if v4_fields = ::Socket::IPAddress.parse_v4_fields?(hostname) - return Result::MatchFound if v4_fields.to_slice == data + return Result::MatchFound if v4_fields.to_unsafe_slice == data end when 16 if v6_fields = ::Socket::IPAddress.parse_v6_fields?(hostname) {% if IO::ByteFormat::NetworkEndian != IO::ByteFormat::SystemEndian %} v6_fields.map! &.byte_swap {% end %} - return Result::MatchFound if v6_fields.to_slice.to_unsafe_bytes == data + return Result::MatchFound if v6_fields.to_unsafe_slice.to_unsafe_bytes == data end else # not a length we expect diff --git a/src/random.cr b/src/random.cr index 61fe9df09d6b..47e9f04dda30 100644 --- a/src/random.cr +++ b/src/random.cr @@ -333,7 +333,7 @@ module Random private def rand_type_from_bytes(t : T.class) forall T buffer = uninitialized UInt8[sizeof(T)] - random_bytes(buffer.to_slice) + random_bytes(buffer.to_unsafe_slice) buffer.unsafe_as(T) end diff --git a/src/random/secure.cr b/src/random/secure.cr index 1722b5e6e884..30ac7f7cc763 100644 --- a/src/random/secure.cr +++ b/src/random/secure.cr @@ -49,7 +49,7 @@ module Random::Secure (result << 8) | byte end else - random_bytes(buf.to_slice) + random_bytes(buf.to_unsafe_slice) buf.unsafe_as({{type}}) end end diff --git a/src/slice.cr b/src/slice.cr index 7a27218221a2..d25dd43419ee 100644 --- a/src/slice.cr +++ b/src/slice.cr @@ -728,7 +728,7 @@ struct Slice(T) return 0 if empty? line = uninitialized UInt8[77] - line_slice = line.to_slice + line_slice = line.to_unsafe_slice count = 0 pos = 0 diff --git a/src/static_array.cr b/src/static_array.cr index 4cb2b186f200..e492749e9c04 100644 --- a/src/static_array.cr +++ b/src/static_array.cr @@ -116,7 +116,7 @@ struct StaticArray(T, N) end def <=>(other : StaticArray) - to_slice <=> other.to_slice + to_unsafe_slice <=> other.to_unsafe_slice end @[AlwaysInline] @@ -142,19 +142,19 @@ struct StaticArray(T, N) # :inherit: def fill(value : T) : self # enable memset optimization - to_slice.fill(value) + to_unsafe_slice.fill(value) self end # :inherit: def fill(value : T, start : Int, count : Int) : self - to_slice.fill(value, start, count) + to_unsafe_slice.fill(value, start, count) self end # :inherit: def fill(value : T, range : Range) : self - to_slice.fill(value, range) + to_unsafe_slice.fill(value, range) self end @@ -260,13 +260,13 @@ struct StaticArray(T, N) # :inherit: def sort! : self - to_slice.sort! + to_unsafe_slice.sort! self end # :inherit: def unstable_sort! : self - to_slice.unstable_sort! + to_unsafe_slice.unstable_sort! self end @@ -276,7 +276,7 @@ struct StaticArray(T, N) {% raise "Expected block to return Int32 or Nil, not #{U}" %} {% end %} - to_slice.sort!(&block) + to_unsafe_slice.sort!(&block) self end @@ -286,7 +286,7 @@ struct StaticArray(T, N) {% raise "Expected block to return Int32 or Nil, not #{U}" %} {% end %} - to_slice.unstable_sort!(&block) + to_unsafe_slice.unstable_sort!(&block) self end @@ -353,7 +353,7 @@ struct StaticArray(T, N) # :inherit: def rotate!(n : Int = 1) : self - to_slice.rotate!(n) + to_unsafe_slice.rotate!(n) self end @@ -362,14 +362,36 @@ struct StaticArray(T, N) # # ``` # array = StaticArray(Int32, 3).new(2) - # slice = array.to_slice # => Slice[2, 2, 2] + # slice = array.to_unsafe_slice # => Slice[2, 2, 2] # slice[0] = 3 # array # => StaticArray[3, 2, 2] # ``` - def to_slice : Slice(T) + # + # WARNING: The slice that this method returns points to stack memory. It + # becomes invalid when execution leaves the context where the `StaticArray` is + # stored. Use `Slice#dup` to duplicate the slice on the heap for safe access. + # + # ``` + # def foo + # # allocates on the stack + # ary = StaticArray[1, 2, 3] + # # create a slice pointing to stack + # ary.to_unsafe_slice + # # at the end of the method the stack pointer becomes invalid + # end + # + # foo # the stack pointer slice is now garbage + # ``` + def to_unsafe_slice : Slice(T) Slice.new(to_unsafe, size) end + # :ditto: + @[Deprecated("Use `#to_unsafe_slice` instead.")] + def to_slice : Slice(T) + to_unsafe_slice + end + # Returns a pointer to this static array's data. # # ``` @@ -397,7 +419,7 @@ struct StaticArray(T, N) # value and for big static arrays that seems to make # LLVM really slow. # TODO: investigate why, maybe report a bug to LLVM? - pp.list("StaticArray[", to_slice, "]") + pp.list("StaticArray[", to_unsafe_slice, "]") end # Returns a new `StaticArray` where each element is cloned from elements in `self`. @@ -413,7 +435,7 @@ struct StaticArray(T, N) # Optimize for the case of looking for a byte in a byte slice if T.is_a?(UInt8.class) && (object.is_a?(UInt8) || (object.is_a?(Int) && 0 <= object < 256)) - return to_slice.fast_index(object, offset) + return to_unsafe_slice.fast_index(object, offset) end super diff --git a/src/string.cr b/src/string.cr index d3bc7d6998b2..83bcff328d32 100644 --- a/src/string.cr +++ b/src/string.cr @@ -1837,7 +1837,7 @@ class String if err == Crystal::Iconv::ERROR iconv.handle_invalid(pointerof(inbuf_ptr), pointerof(inbytesleft)) end - io.write(outbuf.to_slice[0, outbuf.size - outbytesleft]) + io.write(outbuf.to_unsafe_slice[0, outbuf.size - outbytesleft]) end outbuf_ptr = outbuf.to_unsafe @@ -1846,7 +1846,7 @@ class String if err == Crystal::Iconv::ERROR iconv.handle_invalid(pointerof(inbuf_ptr), pointerof(inbytesleft)) end - io.write(outbuf.to_slice[0, outbuf.size - outbytesleft]) + io.write(outbuf.to_unsafe_slice[0, outbuf.size - outbytesleft]) end end diff --git a/src/string/formatter.cr b/src/string/formatter.cr index 0d4956dc0c05..fd7e0a566572 100644 --- a/src/string/formatter.cr +++ b/src/string/formatter.cr @@ -381,7 +381,7 @@ struct String::Formatter(A) printf_buf = uninitialized UInt8[1076] printf_size = Float::Printer::RyuPrintf.d2fixed_buffered_n(float, printf_precision, printf_buf.to_unsafe) - printf_slice = printf_buf.to_slice[0, printf_size] + printf_slice = printf_buf.to_unsafe_slice[0, printf_size] dot_index = printf_slice.index('.'.ord) sign = Math.copysign(1.0, float) @@ -420,7 +420,7 @@ struct String::Formatter(A) printf_buf = uninitialized UInt8[773] printf_size = Float::Printer::RyuPrintf.d2exp_buffered_n(float, printf_precision, printf_buf.to_unsafe) - printf_slice = printf_buf.to_slice[0, printf_size] + printf_slice = printf_buf.to_unsafe_slice[0, printf_size] dot_index = printf_slice.index('.'.ord) e_index = printf_slice.rindex!('e'.ord) sign = Math.copysign(1.0, float) @@ -455,7 +455,7 @@ struct String::Formatter(A) printf_buf = uninitialized UInt8[773] printf_size, trailing_zeros = Float::Printer::RyuPrintf.d2gen_buffered_n(float.abs, precision, printf_buf.to_unsafe, flags.sharp) - printf_slice = printf_buf.to_slice[0, printf_size] + printf_slice = printf_buf.to_unsafe_slice[0, printf_size] dot_index = printf_slice.index('.'.ord) e_index = printf_slice.rindex('e'.ord) sign = Math.copysign(1.0, float) diff --git a/src/uuid.cr b/src/uuid.cr index c7aaee0a605c..d861e15f1efe 100644 --- a/src/uuid.cr +++ b/src/uuid.cr @@ -102,7 +102,7 @@ struct UUID raise ArgumentError.new "Invalid bytes length #{slice.size}, expected 16" unless slice.size == 16 bytes = uninitialized UInt8[16] - slice.copy_to(bytes.to_slice) + slice.copy_to(bytes.to_unsafe_slice) new(bytes, variant, version) end @@ -207,7 +207,7 @@ struct UUID # *random*, such as `Random::Secure`. def self.random(random : Random = Random::Secure, variant : Variant = :rfc4122, version : Version = :v4) : self new_bytes = uninitialized UInt8[16] - random.random_bytes(new_bytes.to_slice) + random.random_bytes(new_bytes.to_unsafe_slice) new(new_bytes, variant, version) end @@ -237,17 +237,17 @@ struct UUID time_hi |= 0x1000 # Version 1 uuid = uninitialized UInt8[16] - IO::ByteFormat::BigEndian.encode(time_low, uuid.to_slice[0..3]) - IO::ByteFormat::BigEndian.encode(time_mid, uuid.to_slice[4..5]) - IO::ByteFormat::BigEndian.encode(time_hi, uuid.to_slice[6..7]) - IO::ByteFormat::BigEndian.encode(seq, uuid.to_slice[8..9]) + IO::ByteFormat::BigEndian.encode(time_low, uuid.to_unsafe_slice[0..3]) + IO::ByteFormat::BigEndian.encode(time_mid, uuid.to_unsafe_slice[4..5]) + IO::ByteFormat::BigEndian.encode(time_hi, uuid.to_unsafe_slice[6..7]) + IO::ByteFormat::BigEndian.encode(seq, uuid.to_unsafe_slice[8..9]) if node_id 6.times do |i| - uuid.to_slice[10 + i] = node_id[i] + uuid.to_unsafe_slice[10 + i] = node_id[i] end else - Random::Secure.random_bytes(uuid.to_slice[10..15]) + Random::Secure.random_bytes(uuid.to_unsafe_slice[10..15]) # set multicast bit as recommended per section 4.5 of the RFC 4122 spec # to not conflict with real MAC addresses uuid[10] |= 0x01_u8 @@ -271,7 +271,7 @@ struct UUID uuid = v1(node_id: node_id).bytes uuid[6] = (uuid[6] & 0x0f) | 0x20 # Version 2 uuid[9] = domain.to_u8 - IO::ByteFormat::BigEndian.encode(id, uuid.to_slice[0..3]) + IO::ByteFormat::BigEndian.encode(id, uuid.to_unsafe_slice[0..3]) new(uuid, version: UUID::Version::V2, variant: UUID::Variant::RFC4122) end @@ -280,7 +280,7 @@ struct UUID def self.v3(name : String, namespace : UUID) : self klass = {% if flag?(:without_openssl) %}::Crystal::Digest::MD5{% else %}::Digest::MD5{% end %} hash = klass.digest do |ctx| - ctx.update namespace.bytes + ctx.update namespace.bytes.to_unsafe_slice ctx.update name end new(hash[0...16], version: UUID::Version::V3, variant: UUID::Variant::RFC4122) @@ -299,7 +299,7 @@ struct UUID def self.v5(name : String, namespace : UUID) : self klass = {% if flag?(:without_openssl) %}::Crystal::Digest::SHA1{% else %}::Digest::SHA1{% end %} hash = klass.digest do |ctx| - ctx.update namespace.bytes + ctx.update namespace.bytes.to_unsafe_slice ctx.update name end new(hash[0...16], version: UUID::Version::V5, variant: UUID::Variant::RFC4122) @@ -399,7 +399,7 @@ struct UUID end def to_s(io : IO) : Nil - slice = @bytes.to_slice + slice = @bytes.to_unsafe_slice buffer = uninitialized UInt8[36] buffer_ptr = buffer.to_unsafe @@ -411,11 +411,11 @@ struct UUID slice[8, 2].hexstring(buffer_ptr + 19) slice[10, 6].hexstring(buffer_ptr + 24) - io.write_string(buffer.to_slice) + io.write_string(buffer.to_unsafe_slice) end def hexstring : String - @bytes.to_slice.hexstring + @bytes.to_unsafe_slice.hexstring end # Returns a `String` that is a valid urn of *self*