ref_record
ref_record
Mutable structs in Crystal made easy - simple wrapper that allows to pass structs by reference without a fear that copy will be modified instead of original.
Installation
-
Add the dependency to your
shard.yml
:dependencies: ref_record: github: konovod/ref_record
-
Run
shards install
Usage
require "ref_record"
# use `ref_record` instead of `record` to define struct
ref_record Point, x : Int32, y : Int32
# this is just a normal struct variable
v = Point.new(123,456)
# and this is a reference to v (holds a pointer to v inside)
pt = RefPoint.new(pointerof(v))
# pt accessors never create a copy of struct but modify it inplace:
pt.x = 1
pt.y += 1
puts pt, v
Structs nesting
You can nest structures, but to make it possible you have to mark struct fields somehow, current way is prepending type name with Struct
:
ref_record Point, x : Int32, y : Int32
ref_record Line, start : StructPoint, finish : StructPoint, color : String
line = RefLine.new(pointerof(@some_field))
line.start.x += 1
Passing to functions
References can be passed to functions (it has a type RefTypeName < RefStruct(TypeName)
):
ref_record Body, pos : Int32, speed : Int32
def update(body : RefBody)
body.pos += body.speed
end
Pointers to fields
For a low level manipulations, you can get pointer to a field from a reference to a struct. Use syntax #ptr_<field_name>
:
point = Point.new(123, 456)
p1 = RefPoint.new(pointerof(point))
ptr = p1.ptr_x
ptr.value = 10
puts p1 # => Point.new(10, 456)
To simplify support of C-style structs, #ptr_XXX
for a fields with StaticArray type has a return type that points to element of array:
ref_record Protocol, header : StructHeader, data : UInt8[0]
typeof(Protocol.ptr_data) # => Pointer(UInt8)
Development
There is a one big problem in my implementation. (requirement to use StructXXX
in fields definition)
There are also lesser problems, but they are (i think) unsolvable by design:
- The reference use
pointer_of
that is unsafe, soreturn RefPoint.new(pointerof(local_variable))
will corrupt memory in a horrible way - It works only with structs defined with
ref_record
, not structs defined in stdlib or byrecord
(orstruct
)
Contributing
- Fork it (https://github.com/konovod/ref_record/fork)
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request
Contributors
- konovod - creator and maintainer
ref_record
- 0
- 0
- 0
- 0
- 0
- 9 days ago
- April 11, 2025
MIT License
Thu, 24 Apr 2025 04:33:42 GMT