For interacting with the GTK library I call some functions that hand me a c-string (char*) that my code owns going forward. I want to have those strings in a custom distinct cstring type and define a =copy hook for those strings for use with nim's ARC/ORC system.
My minimal example looks likes this:
type OwnedGtkString* = distinct cstring
proc `=copy`*(dest: var OwnedGtkString, source: OwnedGtkString) =
let areSameObject = pointer(source) == pointer(dest)
if areSameObject:
return
`=destroy`(dest)
wasMoved(dest)
dest = source
let x: OwnedGtkString = "lala".OwnedGtkString
let y = x
echo x.pointer.repr
echo y.pointer.repr
Naturally this is naive implementation. This doesn't work because dest = source triggers the =copy hook again, making the entire thing recursive.
Now what else am I supposed to use here? copyMem would be an option if I could know how long the string is. Given that =copy is supposed to work for a whole breadth of different cstrings that seems non-feasible.
I also can't do simply assignments like this as that triggers the copy proc again.
So how is it supposed to be possible to define a copy-hook for a distinct cstring type?
That actually already did it!
Question though: That'll enable a pointer-copy, is there a way to copy c-strings that you don't know the size of?
That'll enable a pointer-copy, is there a way to copy c-strings that you don't know the size of?
Well you can count the size via strlen.
Is strlen the proc c_strlen in std/segfaults? If so, how do you use it?
I tried this
import std/segfaults
let a: cstring = "lalala"
echo a.c_strlen()
as well as just
let a: cstring = "lalala"
echo a.strlen
In case it's a proc somewhere in std/systems that I just fail to find. Neither can compile because they can't find strlen or c_strlen.
If Nim side owns the string why dont you just convert it to Nim string in the first place ? Otherwise you have to scan all cstring to query it's size every time but getting cstring pointer out of Nim string is effortless.
Do Nim strings hold the null terminator at the end like Delphi's bodged strings did? If so, might not be a bad idea unless its a section of code where that is going to invite a lot of undesired copying.
Is strlen the proc c_strlen in std/segfaults? If so, how do you use it?
I believe it's just .len overloaded for an object of type cstring.
Distinct types pretend to be a completely new type--you have to take extra steps to allow those old behaviors back in to the new type. You can also typecast back to the backing type for free (ex cast[cstring](protected).len.) Such is also one way to get around your copy constructors. You would need to typecast to the backing type--which does not have these copy triggers--and then back to the protected type to return it.
I've tried abusing =copy and such for pointer trickery in the past (in my postbox repo <https://git.sr.ht/~icedquinn/icedpostbox>) and it was kind of a pain. I don't think I would do so again without a real need (like profiling showing you are copying strings back and forth too much, or if you absolutely need a parallel reference tracer for keeping game textures loaded or such.)