yes, checked it myself.
Yes, Strings are supposed to be immutable so perhaps string literal was placed to readonly section.
For your case you can do:
@[Link(lib: "upcase", ldflags: "-L#{__DIR__}/../upcase-c/_build")]
lib LibUpcase
fun upcase(s : UInt8*) : UInt32
end
def wrap_upcase(s : String) : String
slice = Slice(UInt8).new(s.bytesize + 1) # allocate new (mutable) slice
s.to_slice.copy_to(slice) # copy String content to it
slice[s.bytesize] = 0 # null-terminate it :)
Lib1.upcase(slice)
String.new(slice) # this will perform one more copy.
end
puts wrap_upcase("hello crystal")
note that it will perform copying of string twice - to the slice and from the slice to the returned string. If the performance is critical, you can use some black magic:
@[Link("#{__DIR__}/project1")]
lib Lib1
fun upcase(s : UInt8*) : UInt32
end
def wrap_upcase(s : String) : String
String.new(s.bytesize) do |buffer|
buffer.copy_from(s.to_unsafe, s.bytesize)
Lib1.upcase(buffer)
{s.bytesize, s.size}
end
end
puts wrap_upcase("hello crystal")
but that actually can break if strings aren’t null terminated - i was sure they are and this always worked, but well, i’ve never checked that it is documented somewhere.