I’m looking for Crystal’s equivalent of Ruby’s Array#pack
method.
This thread explains why Crystal doesn’t have it, but I’m wondering if anything has been added since this time to maybe support doing it a different way.
irb(main):001:0> [5].pack('e*').bytes
=> [0, 0, 160, 64]
1 Like
Here’s the way it’s done in JavaScript. Maybe someone has an idea of how to replicate it this way in Crystal?
const buf = Buffer.allocUnsafe(4);
buf.writeFloatLE(5, 0);
Uint8Array.from(buf);
Alright! Thanks to some help from @straight-shoota if anyone else comes looking for answers, here we go:
# Unpack
numbers = [5]
io = IO::Memory.new
numbers.each do |n|
io.write_bytes n.to_f32, IO::ByteFormat::LittleEndian
end
io.rewind
io.to_s.bytes
#=> [0, 0, 160, 64]
# Pack
n = [65, 66, 67]
# Ruby
n.pack("ccc") #=> "ABC"
# Crystal
String.build do |io|
n.each do |number|
io.write_byte number.to_u8
end
end #=> "ABC"
Yes, it’s a bit more verbose, but if you take a look at the closed issue on Crystal, it’ll make a little sense as to why. For me, the pack/unpack
methods in ruby always seemed a little mysterious. Seeing that it’s just writing some bytes to some IO really clears it up for me.
4 Likes
Thanks, this helped me! I wonder if examples like these are present in the documentation?