Ruby 4.1.0dev (2026-10-24 revision 83c63ffc9e6699e61ccfbfc8e568d2b7b1319c42)
struct.c (83c63ffc9e6699e61ccfbfc8e568d2b7b1319c42)
1/**********************************************************************
2
3 struct.c -
4
5 $Author$
6 created at: Tue Mar 22 18:44:30 JST 1995
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9
10**********************************************************************/
11
12#include "id.h"
13#include "internal.h"
14#include "internal/class.h"
15#include "internal/error.h"
16#include "internal/hash.h"
17#include "internal/object.h"
18#include "internal/proc.h"
19#include "internal/struct.h"
20#include "internal/symbol.h"
21#include "vm_core.h"
22#include "builtin.h"
23
24/* only for struct[:field] access */
25enum {
26 AREF_HASH_UNIT = 5,
27 AREF_HASH_THRESHOLD = 10
28};
29
30/* Note: Data is a stricter version of the Struct: no attr writers & no
31 hash-alike/array-alike behavior. It shares most of the implementation
32 on the C level, but is unrelated on the Ruby level. */
34static VALUE rb_cData;
35static ID id_members, id_back_members, id_keyword_init;
36
37static VALUE struct_alloc(VALUE);
38
39static inline VALUE
40struct_ivar_get(VALUE c, ID id)
41{
42 VALUE orig = c;
43 VALUE ivar = rb_attr_get(c, id);
44
45 if (!NIL_P(ivar))
46 return ivar;
47
48 for (;;) {
50 if (c == rb_cStruct || c == rb_cData || !RTEST(c))
51 return Qnil;
53 ivar = rb_attr_get(c, id);
54 if (!NIL_P(ivar)) {
55 if (!OBJ_FROZEN(orig)) rb_ivar_set(orig, id, ivar);
56 return ivar;
57 }
58 }
59}
60
62rb_struct_s_keyword_init(VALUE klass)
63{
64 return struct_ivar_get(klass, id_keyword_init);
65}
66
69{
70 VALUE members = struct_ivar_get(klass, id_members);
71
72 if (NIL_P(members)) {
73 rb_raise(rb_eTypeError, "uninitialized struct");
74 }
75 if (!RB_TYPE_P(members, T_ARRAY)) {
76 rb_raise(rb_eTypeError, "corrupted struct");
77 }
78 return members;
79}
80
83{
85
86 if (RSTRUCT_LEN_RAW(s) != RARRAY_LEN(members)) {
87 rb_raise(rb_eTypeError, "struct size differs (%"PRIdLEN" required %"PRIdLEN" given)",
88 RARRAY_LEN(members), RSTRUCT_LEN_RAW(s));
89 }
90 return members;
91}
92
93static rb_len_t
94struct_member_pos_ideal(VALUE name, rb_len_t mask)
95{
96 /* (id & (mask/2)) * 2 */
97 return (SYM2ID(name) >> (ID_SCOPE_SHIFT - 1)) & mask;
98}
99
100static rb_len_t
101struct_member_pos_probe(rb_len_t prev, rb_len_t mask)
102{
103 /* (((prev/2) * AREF_HASH_UNIT + 1) & (mask/2)) * 2 */
104 return (prev * AREF_HASH_UNIT + 2) & mask;
105}
106
107static VALUE
108struct_set_members(VALUE klass, VALUE /* frozen hidden array */ members)
109{
110 VALUE back;
111 const rb_len_t members_length = RARRAY_LEN(members);
112
113 if (members_length <= AREF_HASH_THRESHOLD) {
114 back = members;
115 }
116 else {
117 rb_len_t i, j, mask = 64;
118 VALUE name;
119
120 while (mask < members_length * AREF_HASH_UNIT) mask *= 2;
121
122 back = rb_ary_hidden_new(mask + 1);
123 rb_ary_store(back, mask, INT2FIX(members_length));
124 mask -= 2; /* mask = (2**k-1)*2 */
125
126 for (i=0; i < members_length; i++) {
127 name = RARRAY_AREF(members, i);
128
129 j = struct_member_pos_ideal(name, mask);
130
131 for (;;) {
132 if (!RTEST(RARRAY_AREF(back, j))) {
133 rb_ary_store(back, j, name);
134 rb_ary_store(back, j + 1, INT2FIX(i));
135 break;
136 }
137 j = struct_member_pos_probe(j, mask);
138 }
139 }
140 OBJ_FREEZE(back);
141 }
142 rb_ivar_set(klass, id_members, members);
143 rb_ivar_set(klass, id_back_members, back);
144
145 return members;
146}
147
148static inline int
149struct_member_pos(VALUE s, VALUE name)
150{
151 VALUE back = struct_ivar_get(rb_obj_class(s), id_back_members);
152 rb_len_t j, mask;
153
154 if (UNLIKELY(NIL_P(back))) {
155 rb_raise(rb_eTypeError, "uninitialized struct");
156 }
157 if (UNLIKELY(!RB_TYPE_P(back, T_ARRAY))) {
158 rb_raise(rb_eTypeError, "corrupted struct");
159 }
160
161 mask = RARRAY_LEN(back);
162
163 if (mask <= AREF_HASH_THRESHOLD) {
164 if (UNLIKELY(RSTRUCT_LEN_RAW(s) != mask)) {
165 rb_raise(rb_eTypeError,
166 "struct size differs (%"PRIdLEN" required %"PRIdLEN" given)",
167 mask, RSTRUCT_LEN_RAW(s));
168 }
169 for (j = 0; j < mask; j++) {
170 if (RARRAY_AREF(back, j) == name)
171 return (int)j;
172 }
173 return -1;
174 }
175
176 if (UNLIKELY(RSTRUCT_LEN_RAW(s) != FIX2INT(RARRAY_AREF(back, mask-1)))) {
177 rb_raise(rb_eTypeError, "struct size differs (%d required %"PRIdLEN" given)",
178 FIX2INT(RARRAY_AREF(back, mask-1)), RSTRUCT_LEN_RAW(s));
179 }
180
181 mask -= 3;
182 j = struct_member_pos_ideal(name, mask);
183
184 for (;;) {
185 VALUE e = RARRAY_AREF(back, j);
186 if (e == name)
187 return FIX2INT(RARRAY_AREF(back, j + 1));
188 if (!RTEST(e)) {
189 return -1;
190 }
191 j = struct_member_pos_probe(j, mask);
192 }
193}
194
195/*
196 * call-seq:
197 * StructClass::members -> array_of_symbols
198 *
199 * Returns the member names of the Struct descendant as an array:
200 *
201 * Customer = Struct.new(:name, :address, :zip)
202 * Customer.members # => [:name, :address, :zip]
203 *
204 */
205
206static VALUE
207rb_struct_s_members_m(VALUE klass)
208{
209 VALUE members = rb_struct_s_members(klass);
210
211 return rb_ary_dup(members);
212}
213
214/*
215 * call-seq:
216 * members -> array_of_symbols
217 *
218 * Returns the member names from +self+ as an array:
219 *
220 * Customer = Struct.new(:name, :address, :zip)
221 * Customer.new.members # => [:name, :address, :zip]
222 *
223 * Related: #to_a.
224 */
225
226static VALUE
227rb_struct_members_m(VALUE obj)
228{
229 return rb_struct_s_members_m(rb_obj_class(obj));
230}
231
232VALUE
234{
235 VALUE slot = ID2SYM(id);
236 int i = struct_member_pos(obj, slot);
237 if (i != -1) {
238 return RSTRUCT_GET_RAW(obj, i);
239 }
240 rb_name_err_raise("'%1$s' is not a struct member", obj, ID2SYM(id));
241
243}
244
245static void
246rb_struct_modify(VALUE s)
247{
248 rb_check_frozen(s);
249}
250
251static VALUE
252anonymous_struct(VALUE klass)
253{
254 VALUE nstr;
255
256 nstr = rb_class_new(klass);
257 rb_make_metaclass(nstr, RBASIC(klass)->klass);
258 rb_class_inherited(klass, nstr);
259 return nstr;
260}
261
262static VALUE
263new_struct(VALUE name, VALUE super)
264{
265 /* old style: should we warn? */
266 ID id;
267 name = rb_str_to_str(name);
268 if (!rb_is_const_name(name)) {
269 rb_name_err_raise("identifier %1$s needs to be constant",
270 super, name);
271 }
272 id = rb_to_id(name);
273 if (rb_const_defined_at(super, id)) {
274 rb_warn("redefining constant %"PRIsVALUE"::%"PRIsVALUE, super, name);
275 rb_mod_remove_const(super, ID2SYM(id));
276 }
277 return rb_define_class_id_under_no_pin(super, id, super);
278}
279
280NORETURN(static void invalid_struct_pos(VALUE s, VALUE idx));
281
282static void
283define_aref_method(VALUE nstr, VALUE name, VALUE off)
284{
285 rb_add_method_optimized(nstr, SYM2ID(name), OPTIMIZED_METHOD_TYPE_STRUCT_AREF, FIX2UINT(off), METHOD_VISI_PUBLIC);
286}
287
288void
289rb_struct_define_aref_method(VALUE nstr, ID name, unsigned int off)
290{
291 rb_add_method_optimized(nstr, name, OPTIMIZED_METHOD_TYPE_STRUCT_AREF, off, METHOD_VISI_PUBLIC);
292}
293
294static void
295define_aset_method(VALUE nstr, VALUE name, VALUE off)
296{
297 rb_add_method_optimized(nstr, SYM2ID(name), OPTIMIZED_METHOD_TYPE_STRUCT_ASET, FIX2UINT(off), METHOD_VISI_PUBLIC);
298}
299
300static VALUE
301rb_struct_s_inspect(VALUE klass)
302{
303 VALUE inspect = rb_class_name(klass);
304 if (RTEST(rb_struct_s_keyword_init(klass))) {
305 rb_str_cat_cstr(inspect, "(keyword_init: true)");
306 }
307 return inspect;
308}
309
310static VALUE rb_data_initialize_m(int argc, const VALUE *argv, VALUE self);
311
312// Given every member, Data#initialize can only store them and freeze the
313// instance: it raises nothing and calls no Ruby code. So when initialize is
314// that method, the members can be stored without calling it.
315static bool
316data_initialize_default_p(VALUE klass)
317{
318 const rb_callable_method_entry_t *cme = rb_callable_method_entry(klass, idInitialize);
319 return cme && cme->def->type == VM_METHOD_TYPE_CFUNC &&
320 cme->def->body.cfunc.func == (rb_cfunc_t)rb_data_initialize_m;
321}
322
323static VALUE
324rb_data_s_new(int argc, const VALUE *argv, VALUE klass)
325{
326 if (rb_keyword_given_p()) {
327 if (argc > 1 || !RB_TYPE_P(argv[0], T_HASH)) {
328 rb_error_arity(argc, 0, 0);
329 }
330 return rb_class_new_instance_pass_kw(argc, argv, klass);
331 }
332 else {
333 VALUE members = struct_ivar_get(klass, id_members);
334 int num_members = RARRAY_LENINT(members);
335
336 rb_check_arity(argc, 0, num_members);
337 if (argc == num_members && data_initialize_default_p(klass)) {
338 VALUE self = rb_obj_alloc(klass);
339 for (rb_len_t i=0; i<argc; i++) {
340 RSTRUCT_SET_RAW(self, i, argv[i]);
341 }
342 OBJ_FREEZE(self);
343 return self;
344 }
345 VALUE arg_hash = rb_hash_new_capa(argc);
346 for (rb_len_t i=0; i<argc; i++) {
347 VALUE k = rb_ary_entry(members, i), v = argv[i];
348 rb_hash_aset(arg_hash, k, v);
349 }
350 return rb_class_new_instance_kw(1, &arg_hash, klass, RB_PASS_KEYWORDS);
351 }
352}
353
354#if 0 /* for RDoc */
355
356/*
357 * call-seq:
358 * StructClass::keyword_init? -> true or falsy value
359 *
360 * Returns +true+ if the class was initialized with <tt>keyword_init: true</tt>.
361 * Otherwise returns +nil+ or +false+.
362 *
363 * Examples:
364 * Foo = Struct.new(:a)
365 * Foo.keyword_init? # => nil
366 * Bar = Struct.new(:a, keyword_init: true)
367 * Bar.keyword_init? # => true
368 * Baz = Struct.new(:a, keyword_init: false)
369 * Baz.keyword_init? # => false
370 */
371static VALUE
372rb_struct_s_keyword_init_p(VALUE obj)
373{
374}
375#endif
376
377#define rb_struct_s_keyword_init_p rb_struct_s_keyword_init
378
379static VALUE
380setup_struct(VALUE nstr, VALUE members)
381{
382 rb_len_t i, len;
383
384 members = struct_set_members(nstr, members);
385
386 rb_define_alloc_func(nstr, struct_alloc);
389 rb_define_singleton_method(nstr, "members", rb_struct_s_members_m, 0);
390 rb_define_singleton_method(nstr, "inspect", rb_struct_s_inspect, 0);
391 rb_define_singleton_method(nstr, "keyword_init?", rb_struct_s_keyword_init_p, 0);
392
393 len = RARRAY_LEN(members);
394 for (i=0; i< len; i++) {
395 VALUE sym = RARRAY_AREF(members, i);
396 ID id = SYM2ID(sym);
397 VALUE off = LEN2NUM(i);
398
399 define_aref_method(nstr, sym, off);
400 define_aset_method(nstr, ID2SYM(rb_id_attrset(id)), off);
401 }
402
403 return nstr;
404}
405
406static VALUE
407setup_data(VALUE subclass, VALUE members)
408{
409 rb_len_t i, len;
410
411 members = struct_set_members(subclass, members);
412
413 rb_define_alloc_func(subclass, struct_alloc);
414 VALUE sclass = rb_singleton_class(subclass);
415 rb_undef_method(sclass, "define");
416 rb_define_method(sclass, "new", rb_data_s_new, -1);
417 rb_define_method(sclass, "[]", rb_data_s_new, -1);
418 rb_define_method(sclass, "members", rb_struct_s_members_m, 0);
419 rb_define_method(sclass, "inspect", rb_struct_s_inspect, 0); // FIXME: just a separate method?..
420
421 len = RARRAY_LEN(members);
422 for (i=0; i< len; i++) {
423 VALUE sym = RARRAY_AREF(members, i);
424 VALUE off = LEN2NUM(i);
425
426 define_aref_method(subclass, sym, off);
427 }
428
429 return subclass;
430}
431
432VALUE
434{
435 return struct_alloc(klass);
436}
437
438static VALUE
439struct_make_members_list(va_list ar)
440{
441 char *mem;
442 VALUE ary, list = rb_ident_hash_new();
443 RBASIC_CLEAR_CLASS(list);
444 while ((mem = va_arg(ar, char*)) != 0) {
445 VALUE sym = rb_sym_intern_ascii_cstr(mem);
446 if (RTEST(rb_hash_has_key(list, sym))) {
447 rb_raise(rb_eArgError, "duplicate member: %s", mem);
448 }
449 rb_hash_aset(list, sym, Qtrue);
450 }
451 ary = rb_hash_keys(list);
452 RBASIC_CLEAR_CLASS(ary);
453 OBJ_FREEZE(ary);
454 return ary;
455}
456
457static VALUE
458struct_define_without_accessor(VALUE outer, const char *class_name, VALUE super, rb_alloc_func_t alloc, VALUE members)
459{
460 VALUE klass;
461
462 if (class_name) {
463 if (outer) {
464 klass = rb_define_class_under(outer, class_name, super);
465 }
466 else {
467 klass = rb_define_class(class_name, super);
468 }
469 }
470 else {
471 klass = anonymous_struct(super);
472 }
473
474 struct_set_members(klass, members);
475
476 if (alloc) {
477 rb_define_alloc_func(klass, alloc);
478 }
479 else {
480 rb_define_alloc_func(klass, struct_alloc);
481 }
482
483 return klass;
484}
485
486VALUE
487rb_struct_define_without_accessor_under(VALUE outer, const char *class_name, VALUE super, rb_alloc_func_t alloc, ...)
488{
489 va_list ar;
490 VALUE members;
491
492 va_start(ar, alloc);
493 members = struct_make_members_list(ar);
494 va_end(ar);
495
496 return struct_define_without_accessor(outer, class_name, super, alloc, members);
497}
498
499VALUE
500rb_struct_define_without_accessor(const char *class_name, VALUE super, rb_alloc_func_t alloc, ...)
501{
502 va_list ar;
503 VALUE members;
504
505 va_start(ar, alloc);
506 members = struct_make_members_list(ar);
507 va_end(ar);
508
509 return struct_define_without_accessor(0, class_name, super, alloc, members);
510}
511
512VALUE
513rb_struct_define(const char *name, ...)
514{
515 va_list ar;
516 VALUE st, ary;
517
518 va_start(ar, name);
519 ary = struct_make_members_list(ar);
520 va_end(ar);
521
522 if (!name) {
523 st = anonymous_struct(rb_cStruct);
524 }
525 else {
526 st = new_struct(rb_str_new2(name), rb_cStruct);
527 rb_vm_register_global_object(st);
528 }
529 return setup_struct(st, ary);
530}
531
532VALUE
533rb_struct_define_under(VALUE outer, const char *name, ...)
534{
535 va_list ar;
536 VALUE ary;
537
538 va_start(ar, name);
539 ary = struct_make_members_list(ar);
540 va_end(ar);
541
542 return setup_struct(rb_define_class_id_under(outer, rb_intern(name), rb_cStruct), ary);
543}
544
545/*
546 * call-seq:
547 * Struct.new(*member_names, keyword_init: nil){|Struct_subclass| ... } -> Struct_subclass
548 * Struct.new(class_name, *member_names, keyword_init: nil){|Struct_subclass| ... } -> Struct_subclass
549 * Struct_subclass.new(*member_names) -> Struct_subclass_instance
550 * Struct_subclass.new(**member_names) -> Struct_subclass_instance
551 *
552 * <tt>Struct.new</tt> returns a new subclass of +Struct+. The new subclass:
553 *
554 * - May be anonymous, or may have the name given by +class_name+.
555 * - May have members as given by +member_names+.
556 * - May have initialization via ordinary arguments, or via keyword arguments
557 *
558 * The new subclass has its own method <tt>::new</tt>; thus:
559 *
560 * Foo = Struct.new('Foo', :foo, :bar) # => Struct::Foo
561 * f = Foo.new(0, 1) # => #<struct Struct::Foo foo=0, bar=1>
562 *
563 * <b>Class Name</b>
564 *
565 * With string argument +class_name+,
566 * returns a new subclass of +Struct+ named <tt>Struct::<em>class_name</em></tt>:
567 *
568 * Foo = Struct.new('Foo', :foo, :bar) # => Struct::Foo
569 * Foo.name # => "Struct::Foo"
570 * Foo.superclass # => Struct
571 *
572 * Without string argument +class_name+,
573 * returns a new anonymous subclass of +Struct+:
574 *
575 * Struct.new(:foo, :bar).name # => nil
576 *
577 * <b>Block</b>
578 *
579 * With a block given, the created subclass is yielded to the block:
580 *
581 * Customer = Struct.new('Customer', :name, :address) do |new_class|
582 * p "The new subclass is #{new_class}"
583 * def greeting
584 * "Hello #{name} at #{address}"
585 * end
586 * end # => Struct::Customer
587 * dave = Customer.new('Dave', '123 Main')
588 * dave # => #<struct Struct::Customer name="Dave", address="123 Main">
589 * dave.greeting # => "Hello Dave at 123 Main"
590 *
591 * Output, from <tt>Struct.new</tt>:
592 *
593 * "The new subclass is Struct::Customer"
594 *
595 * <b>Member Names</b>
596 *
597 * Symbol arguments +member_names+
598 * determines the members of the new subclass:
599 *
600 * Struct.new(:foo, :bar).members # => [:foo, :bar]
601 * Struct.new('Foo', :foo, :bar).members # => [:foo, :bar]
602 *
603 * The new subclass has instance methods corresponding to +member_names+:
604 *
605 * Foo = Struct.new('Foo', :foo, :bar)
606 * Foo.instance_methods(false) # => [:foo, :bar, :foo=, :bar=]
607 * f = Foo.new # => #<struct Struct::Foo foo=nil, bar=nil>
608 * f.foo # => nil
609 * f.foo = 0 # => 0
610 * f.bar # => nil
611 * f.bar = 1 # => 1
612 * f # => #<struct Struct::Foo foo=0, bar=1>
613 *
614 * <b>Singleton Methods</b>
615 *
616 * A subclass returned by Struct.new has these singleton methods:
617 *
618 * - Method <tt>::new </tt> creates an instance of the subclass:
619 *
620 * Foo.new # => #<struct Struct::Foo foo=nil, bar=nil>
621 * Foo.new(0) # => #<struct Struct::Foo foo=0, bar=nil>
622 * Foo.new(0, 1) # => #<struct Struct::Foo foo=0, bar=1>
623 * Foo.new(0, 1, 2) # Raises ArgumentError: struct size differs
624 *
625 * # Initialization with keyword arguments:
626 * Foo.new(foo: 0) # => #<struct Struct::Foo foo=0, bar=nil>
627 * Foo.new(foo: 0, bar: 1) # => #<struct Struct::Foo foo=0, bar=1>
628 * Foo.new(foo: 0, bar: 1, baz: 2)
629 * # Raises ArgumentError: unknown keywords: baz
630 *
631 * - Method <tt>:inspect</tt> returns a string representation of the subclass:
632 *
633 * Foo.inspect
634 * # => "Struct::Foo"
635 *
636 * - Method <tt>::members</tt> returns an array of the member names:
637 *
638 * Foo.members # => [:foo, :bar]
639 *
640 * <b>Keyword Argument</b>
641 *
642 * By default, the arguments for initializing an instance of the new subclass
643 * can be both positional and keyword arguments.
644 *
645 * Optional keyword argument <tt>keyword_init:</tt> allows to force only one
646 * type of arguments to be accepted:
647 *
648 * KeywordsOnly = Struct.new(:foo, :bar, keyword_init: true)
649 * KeywordsOnly.new(bar: 1, foo: 0)
650 * # => #<struct KeywordsOnly foo=0, bar=1>
651 * KeywordsOnly.new(0, 1)
652 * # Raises ArgumentError: wrong number of arguments
653 *
654 * PositionalOnly = Struct.new(:foo, :bar, keyword_init: false)
655 * PositionalOnly.new(0, 1)
656 * # => #<struct PositionalOnly foo=0, bar=1>
657 * PositionalOnly.new(bar: 1, foo: 0)
658 * # => #<struct PositionalOnly foo={foo: 1, bar: 2}, bar=nil>
659 * # Note that no error is raised, but arguments treated as one hash value
660 *
661 * # Same as not providing keyword_init:
662 * Any = Struct.new(:foo, :bar, keyword_init: nil)
663 * Any.new(foo: 1, bar: 2)
664 * # => #<struct Any foo=1, bar=2>
665 * Any.new(1, 2)
666 * # => #<struct Any foo=1, bar=2>
667 */
668
669static VALUE
670rb_struct_s_def(int argc, VALUE *argv, VALUE klass)
671{
672 VALUE name = Qnil, rest, keyword_init = Qnil;
673 rb_len_t i;
674 VALUE st;
675 VALUE opt;
676
677 argc = rb_scan_args(argc, argv, "0*:", NULL, &opt);
678 if (argc >= 1 && !SYMBOL_P(argv[0])) {
679 name = argv[0];
680 --argc;
681 ++argv;
682 }
683
684 if (!NIL_P(opt)) {
685 static ID keyword_ids[1];
686
687 if (!keyword_ids[0]) {
688 keyword_ids[0] = rb_intern("keyword_init");
689 }
690 rb_get_kwargs(opt, keyword_ids, 0, 1, &keyword_init);
691 if (UNDEF_P(keyword_init)) {
692 keyword_init = Qnil;
693 }
694 else if (RTEST(keyword_init)) {
695 keyword_init = Qtrue;
696 }
697 }
698
699 rest = rb_ident_hash_new();
700 RBASIC_CLEAR_CLASS(rest);
701 for (i=0; i<argc; i++) {
702 VALUE mem = rb_to_symbol(argv[i]);
703 if (rb_is_attrset_sym(mem)) {
704 rb_raise(rb_eArgError, "invalid struct member: %"PRIsVALUE, mem);
705 }
706 if (RTEST(rb_hash_has_key(rest, mem))) {
707 rb_raise(rb_eArgError, "duplicate member: %"PRIsVALUE, mem);
708 }
709 rb_hash_aset(rest, mem, Qtrue);
710 }
711 rest = rb_hash_keys(rest);
712 RBASIC_CLEAR_CLASS(rest);
713 OBJ_FREEZE(rest);
714 if (NIL_P(name)) {
715 st = anonymous_struct(klass);
716 }
717 else {
718 st = new_struct(name, klass);
719 }
720 setup_struct(st, rest);
721 rb_ivar_set(st, id_keyword_init, keyword_init);
722 if (rb_block_given_p()) {
723 rb_mod_module_eval(0, 0, st);
724 }
725
726 return st;
727}
728
729static rb_len_t
730num_members(VALUE klass)
731{
732 VALUE members;
733 members = struct_ivar_get(klass, id_members);
734 if (!RB_TYPE_P(members, T_ARRAY)) {
735 rb_bug("broken members"); /* should never happen */
736 }
737 return RARRAY_LEN(members);
738}
739
741rb_zjit_struct_num_members(VALUE klass)
742{
743 return num_members(klass);
744}
745
746/*
747 */
748
750 VALUE self;
751 VALUE unknown_keywords;
752 VALUE missing_keywords;
753 rb_len_t missing_count;
754};
755
756static int rb_struct_pos(VALUE s, VALUE *name, bool name_only);
757static VALUE deconstruct_keys(VALUE s, VALUE keys, bool name_only);
758static int rb_struct_pos(VALUE s, VALUE *name, bool name_only);
759
760static int
761struct_hash_aset(VALUE key, VALUE val, struct struct_hash_set_arg *args, bool name_only)
762{
763 int i = rb_struct_pos(args->self, &key, name_only);
764 if (i < 0) {
765 if (NIL_P(args->unknown_keywords)) {
766 args->unknown_keywords = rb_ary_new();
767 }
768 rb_ary_push(args->unknown_keywords, key);
769 }
770 else {
771 rb_struct_modify(args->self);
772 RSTRUCT_SET_RAW(args->self, i, val);
773 }
774 return i;
775}
776
777static int
778struct_hash_set_i(VALUE key, VALUE val, VALUE arg)
779{
780 struct struct_hash_set_arg *args = (struct struct_hash_set_arg *)arg;
781 struct_hash_aset(key, val, args, false);
782 return ST_CONTINUE;
783}
784
785static VALUE
786rb_struct_initialize_m(int argc, const VALUE *argv, VALUE self)
787{
788 VALUE klass = rb_obj_class(self);
789 rb_struct_modify(self);
790 rb_len_t n = RSTRUCT_LEN_RAW(self);
791 if (argc == 0) {
792 rb_mem_clear((VALUE *)RSTRUCT_CONST_PTR(self), n);
793 return Qnil;
794 }
795
796 bool keyword_init = false;
797 switch (rb_struct_s_keyword_init(klass)) {
798 default:
799 if (argc > 1 || !RB_TYPE_P(argv[0], T_HASH)) {
800 rb_error_arity(argc, 0, 0);
801 }
802 keyword_init = true;
803 break;
804 case Qfalse:
805 break;
806 case Qnil:
807 if (argc > 1 || !RB_TYPE_P(argv[0], T_HASH)) {
808 break;
809 }
810 keyword_init = rb_keyword_given_p();
811 break;
812 }
813 if (keyword_init) {
814 struct struct_hash_set_arg arg = {
815 .self = self,
816 .unknown_keywords = Qnil,
817 };
818 rb_mem_clear((VALUE *)RSTRUCT_CONST_PTR(self), n);
819 rb_hash_foreach(argv[0], struct_hash_set_i, (VALUE)&arg);
820 if (UNLIKELY(!NIL_P(arg.unknown_keywords))) {
821 rb_raise(rb_eArgError, "unknown keywords: %"PRIsVALUE,
822 rb_ary_join(arg.unknown_keywords, rb_str_new2(", ")));
823 }
824 }
825 else {
826 if (n < argc) {
827 rb_raise(rb_eArgError, "struct size differs");
828 }
829 for (rb_len_t i=0; i<argc; i++) {
830 RSTRUCT_SET_RAW(self, i, argv[i]);
831 }
832 if (n > argc) {
833 rb_mem_clear((VALUE *)RSTRUCT_CONST_PTR(self)+argc, n-argc);
834 }
835 }
836 return Qnil;
837}
838
839VALUE
841{
842 rb_struct_initialize_m(RARRAY_LENINT(values), RARRAY_CONST_PTR(values), self);
843 if (rb_obj_is_kind_of(self, rb_cData)) OBJ_FREEZE(self);
844 RB_GC_GUARD(values);
845 return Qnil;
846}
847
848static VALUE *
849struct_heap_alloc(VALUE st, size_t len)
850{
851 return ALLOC_N(VALUE, len);
852}
853
854STATIC_ASSERT(robject_rstruct_fields_offset, offsetof(struct RObject, as.extended) == offsetof(struct RStruct, fields_obj));
855
856static inline bool
857struct_embedded_p(rb_len_t n)
858{
859 size_t embedded_size = offsetof(struct RStruct, as.ary) + (sizeof(VALUE) * n);
860 const rb_len_t embed_len_max = RSTRUCT_EMBED_LEN_MASK >> RSTRUCT_EMBED_LEN_SHIFT;
861 return n > 0 && n <= embed_len_max && rb_gc_size_allocatable_p(embedded_size);
862}
863
864bool
865rb_zjit_struct_embedded_p(rb_len_t num_members)
866{
867 return struct_embedded_p(num_members);
868}
869
870static VALUE
871struct_alloc(VALUE klass)
872{
873 rb_len_t n = num_members(klass);
874 size_t embedded_size = offsetof(struct RStruct, as.ary) + (sizeof(VALUE) * n);
875 VALUE flags = T_STRUCT;
876
877 if (struct_embedded_p(n)) {
878 flags |= n << RSTRUCT_EMBED_LEN_SHIFT;
879
880 VALUE st = rb_newobj(GET_EC(), klass, flags, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_EXTENDED, true, embedded_size);
881 RSTRUCT_SET_FIELDS_OBJ(st, 0);
882 rb_mem_clear((VALUE *)RSTRUCT(st)->as.ary, n);
883
884 return st;
885 }
886 else {
887 VALUE obj = rb_newobj(GET_EC(), klass, flags, ROOT_SHAPE_ID | SHAPE_ID_LAYOUT_EXTENDED, true, sizeof(struct RStruct));
888 struct RStruct *st = RSTRUCT(obj);
889
890 st->fields_obj = 0;
891 st->as.heap.ptr = NULL;
892 st->as.heap.len = 0;
893
894 st->as.heap.ptr = struct_heap_alloc((VALUE)st, n);
895 rb_mem_clear((VALUE *)st->as.heap.ptr, n);
896 st->as.heap.len = n;
897
898 return obj;
899 }
900}
901
902// Whether `klass` allocates its instances with struct_alloc.
903bool
904rb_zjit_class_has_struct_allocator(VALUE klass)
905{
906 return rb_get_alloc_func(klass) == struct_alloc;
907}
908
909// The ID of the `index`th member of the Struct class `klass`. `index` must be in bounds
910// according to rb_zjit_struct_num_members().
911ID
912rb_zjit_struct_member_id(VALUE klass, rb_len_t index)
913{
914 VALUE members = struct_ivar_get(klass, id_members);
915 RUBY_ASSERT(RB_TYPE_P(members, T_ARRAY));
916 RUBY_ASSERT(index >= 0 && index < RARRAY_LEN(members));
917 return SYM2ID(RARRAY_AREF(members, index));
918}
919
920VALUE
922{
923 return rb_class_new_instance(RARRAY_LENINT(values), RARRAY_CONST_PTR(values), klass);
924}
925
926VALUE
928{
929 VALUE tmpargs[16], *mem = tmpargs;
930 int size, i;
931 va_list args;
932
933 size = rb_len2int(num_members(klass));
934 if (size > numberof(tmpargs)) {
935 tmpargs[0] = rb_ary_hidden_new(size);
936 mem = RARRAY_PTR(tmpargs[0]);
937 }
938 va_start(args, klass);
939 for (i=0; i<size; i++) {
940 mem[i] = va_arg(args, VALUE);
941 }
942 va_end(args);
943
944 return rb_class_new_instance(size, mem, klass);
945}
946
947static VALUE
948struct_enum_size(VALUE s, VALUE args, VALUE eobj)
949{
950 return rb_struct_size(s);
951}
952
953/*
954 * call-seq:
955 * each {|value| ... } -> self
956 * each -> enumerator
957 *
958 * Calls the given block with the value of each member; returns +self+:
959 *
960 * Customer = Struct.new(:name, :address, :zip)
961 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
962 * joe.each {|value| p value }
963 *
964 * Output:
965 *
966 * "Joe Smith"
967 * "123 Maple, Anytown NC"
968 * 12345
969 *
970 * Returns an Enumerator if no block is given.
971 *
972 * Related: #each_pair.
973 */
974
975static VALUE
976rb_struct_each(VALUE s)
977{
978 rb_len_t i;
979
980 RETURN_SIZED_ENUMERATOR(s, 0, 0, struct_enum_size);
981 for (i=0; i<RSTRUCT_LEN_RAW(s); i++) {
982 rb_yield(RSTRUCT_GET_RAW(s, i));
983 }
984 return s;
985}
986
987/*
988 * call-seq:
989 * each_pair {|(name, value)| ... } -> self
990 * each_pair -> enumerator
991 *
992 * Calls the given block with each member name/value pair; returns +self+:
993 *
994 * Customer = Struct.new(:name, :address, :zip) # => Customer
995 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
996 * joe.each_pair {|(name, value)| p "#{name} => #{value}" }
997 *
998 * Output:
999 *
1000 * "name => Joe Smith"
1001 * "address => 123 Maple, Anytown NC"
1002 * "zip => 12345"
1003 *
1004 * Returns an Enumerator if no block is given.
1005 *
1006 * Related: #each.
1007 *
1008 */
1009
1010static VALUE
1011rb_struct_each_pair(VALUE s)
1012{
1013 VALUE members;
1014 rb_len_t i;
1015
1016 RETURN_SIZED_ENUMERATOR(s, 0, 0, struct_enum_size);
1017 members = rb_struct_members(s);
1018 if (rb_block_pair_yield_optimizable()) {
1019 for (i=0; i<RSTRUCT_LEN_RAW(s); i++) {
1020 VALUE key = rb_ary_entry(members, i);
1021 VALUE value = RSTRUCT_GET_RAW(s, i);
1022 rb_yield_values(2, key, value);
1023 }
1024 }
1025 else {
1026 for (i=0; i<RSTRUCT_LEN_RAW(s); i++) {
1027 VALUE key = rb_ary_entry(members, i);
1028 VALUE value = RSTRUCT_GET_RAW(s, i);
1029 rb_yield(rb_assoc_new(key, value));
1030 }
1031 }
1032 return s;
1033}
1034
1035static VALUE
1036inspect_struct(VALUE s, VALUE prefix, int recur)
1037{
1038 VALUE cname = rb_class_path(rb_obj_class(s));
1039 VALUE members;
1040 VALUE str = prefix;
1041 rb_len_t i, len;
1042 char first = RSTRING_PTR(cname)[0];
1043
1044 if (recur || first != '#') {
1045 rb_str_cat2(str, " ");
1046 rb_str_append(str, cname);
1047 }
1048 if (recur) {
1049 return rb_str_cat2(str, ":...>");
1050 }
1051
1052 members = rb_struct_members(s);
1053 len = RSTRUCT_LEN_RAW(s);
1054
1055 for (i=0; i<len; i++) {
1056 VALUE slot;
1057 ID id;
1058
1059 if (i > 0) {
1060 rb_str_cat2(str, ", ");
1061 }
1062 else {
1063 rb_str_cat2(str, " ");
1064 }
1065 slot = RARRAY_AREF(members, i);
1066 id = SYM2ID(slot);
1067 if (rb_is_local_id(id) || rb_is_const_id(id)) {
1068 rb_str_append(str, rb_sym2str(slot));
1069 }
1070 else {
1071 rb_str_append(str, rb_inspect(slot));
1072 }
1073 rb_str_cat2(str, "=");
1074 rb_str_append(str, rb_inspect(RSTRUCT_GET_RAW(s, i)));
1075 }
1076 rb_str_cat2(str, ">");
1077
1078 return str;
1079}
1080
1081/*
1082 * call-seq:
1083 * inspect -> string
1084 *
1085 * Returns a string representation of +self+:
1086 *
1087 * Customer = Struct.new(:name, :address, :zip) # => Customer
1088 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1089 * joe.inspect # => "#<struct Customer name=\"Joe Smith\", address=\"123 Maple, Anytown NC\", zip=12345>"
1090 *
1091 */
1092
1093static VALUE
1094rb_struct_inspect(VALUE s)
1095{
1096 return rb_exec_recursive(inspect_struct, s, rb_str_new2("#<struct"));
1097}
1098
1099/*
1100 * call-seq:
1101 * to_a -> array
1102 *
1103 * Returns the values in +self+ as an array:
1104 *
1105 * Customer = Struct.new(:name, :address, :zip)
1106 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1107 * joe.to_a # => ["Joe Smith", "123 Maple, Anytown NC", 12345]
1108 *
1109 * Related: #members.
1110 */
1111
1112static VALUE
1113rb_struct_to_a(VALUE s)
1114{
1115 return rb_ary_new4(RSTRUCT_LEN_RAW(s), RSTRUCT_CONST_PTR(s));
1116}
1117
1118/*
1119 * call-seq:
1120 * to_h -> hash
1121 * to_h {|name, value| ... } -> hash
1122 *
1123 * Returns a hash containing the name and value for each member:
1124 *
1125 * Customer = Struct.new(:name, :address, :zip)
1126 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1127 * h = joe.to_h
1128 * h # => {name: "Joe Smith", address: "123 Maple, Anytown NC", zip: 12345}
1129 *
1130 * If a block is given, it is called with each name/value pair;
1131 * the block should return a 2-element array whose elements will become
1132 * a key/value pair in the returned hash:
1133 *
1134 * h = joe.to_h{|name, value| [name.upcase, value.to_s.upcase]}
1135 * h # => {NAME: "JOE SMITH", ADDRESS: "123 MAPLE, ANYTOWN NC", ZIP: "12345"}
1136 *
1137 * Raises ArgumentError if the block returns an inappropriate value.
1138 *
1139 */
1140
1141static VALUE
1142rb_struct_to_h(VALUE s)
1143{
1144 VALUE h = rb_hash_new_capa(RSTRUCT_LEN_RAW(s));
1145 VALUE members = rb_struct_members(s);
1146 rb_len_t i;
1147 int block_given = rb_block_given_p();
1148
1149 for (i=0; i<RSTRUCT_LEN_RAW(s); i++) {
1150 VALUE k = rb_ary_entry(members, i), v = RSTRUCT_GET_RAW(s, i);
1151 if (block_given)
1152 rb_hash_set_pair(h, rb_yield_values(2, k, v));
1153 else
1154 rb_hash_aset(h, k, v);
1155 }
1156 return h;
1157}
1158
1159/*
1160 * call-seq:
1161 * deconstruct_keys(array_of_names) -> hash
1162 *
1163 * Returns a hash of the name/value pairs for the given member names.
1164 *
1165 * Customer = Struct.new(:name, :address, :zip)
1166 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1167 * h = joe.deconstruct_keys([:zip, :address])
1168 * h # => {zip: 12345, address: "123 Maple, Anytown NC"}
1169 *
1170 * Returns all names and values if +array_of_names+ is +nil+:
1171 *
1172 * h = joe.deconstruct_keys(nil)
1173 * h # => {name: "Joseph Smith, Jr.", address: "123 Maple, Anytown NC", zip: 12345}
1174 *
1175 */
1176static VALUE
1177rb_struct_deconstruct_keys(VALUE s, VALUE keys)
1178{
1179 return deconstruct_keys(s, keys, false);
1180}
1181
1182static VALUE
1183deconstruct_keys(VALUE s, VALUE keys, bool name_only)
1184{
1185 VALUE h;
1186 rb_len_t i;
1187
1188 if (NIL_P(keys)) {
1189 return rb_struct_to_h(s);
1190 }
1191 if (UNLIKELY(!RB_TYPE_P(keys, T_ARRAY))) {
1192 rb_raise(rb_eTypeError,
1193 "wrong argument type %"PRIsVALUE" (expected Array or nil)",
1194 rb_obj_class(keys));
1195
1196 }
1197 if (RSTRUCT_LEN_RAW(s) < RARRAY_LEN(keys)) {
1198 return rb_hash_new();
1199 }
1200 h = rb_hash_new_capa(RARRAY_LEN(keys));
1201 for (i=0; i<RARRAY_LEN(keys); i++) {
1202 VALUE key = RARRAY_AREF(keys, i);
1203 int i = rb_struct_pos(s, &key, name_only);
1204 if (i < 0) {
1205 return h;
1206 }
1207 rb_hash_aset(h, key, RSTRUCT_GET_RAW(s, i));
1208 }
1209 return h;
1210}
1211
1212/* :nodoc: */
1213VALUE
1214rb_struct_init_copy(VALUE copy, VALUE s)
1215{
1216 rb_len_t i, len;
1217
1218 if (!OBJ_INIT_COPY(copy, s)) return copy;
1219 if (RSTRUCT_LEN_RAW(copy) != RSTRUCT_LEN_RAW(s)) {
1220 rb_raise(rb_eTypeError, "struct size mismatch");
1221 }
1222
1223 for (i=0, len=RSTRUCT_LEN_RAW(copy); i<len; i++) {
1224 RSTRUCT_SET_RAW(copy, i, RSTRUCT_GET_RAW(s, i));
1225 }
1226
1227 return copy;
1228}
1229
1230static int
1231rb_struct_pos(VALUE s, VALUE *name, bool name_only)
1232{
1233 rb_len_t i;
1234 VALUE idx = *name;
1235
1236 if (SYMBOL_P(idx)) {
1237 return struct_member_pos(s, idx);
1238 }
1239 else if (name_only || RB_TYPE_P(idx, T_STRING)) {
1240 idx = rb_check_symbol(name);
1241 if (NIL_P(idx)) return -1;
1242 return struct_member_pos(s, idx);
1243 }
1244 else {
1245 rb_len_t len;
1246 i = NUM2LEN(idx);
1247 len = RSTRUCT_LEN_RAW(s);
1248 if (i < 0) {
1249 if (i + len < 0) {
1250 *name = LEN2NUM(i);
1251 return -1;
1252 }
1253 i += len;
1254 }
1255 else if (len <= i) {
1256 *name = LEN2NUM(i);
1257 return -1;
1258 }
1259 return (int)i;
1260 }
1261}
1262
1263static void
1264invalid_struct_pos(VALUE s, VALUE idx)
1265{
1266 if (RB_INTEGER_TYPE_P(idx)) {
1267 rb_len_t i = NUM2LEN(idx), len = RSTRUCT_LEN_RAW(s);
1268 if (i < 0) {
1269 rb_raise(rb_eIndexError, "offset %"PRIdLEN" too small for struct(size:%"PRIdLEN")",
1270 i, len);
1271 }
1272 else {
1273 rb_raise(rb_eIndexError, "offset %"PRIdLEN" too large for struct(size:%"PRIdLEN")",
1274 i, len);
1275 }
1276 }
1277 else {
1278 rb_name_err_raise("no member '%1$s' in struct", s, idx);
1279 }
1280}
1281
1282/*
1283 * call-seq:
1284 * struct[name] -> object
1285 * struct[n] -> object
1286 *
1287 * Returns a value from +self+.
1288 *
1289 * With symbol or string argument +name+ given, returns the value for the named member:
1290 *
1291 * Customer = Struct.new(:name, :address, :zip)
1292 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1293 * joe[:zip] # => 12345
1294 *
1295 * Raises NameError if +name+ is not the name of a member.
1296 *
1297 * With integer argument +n+ given, returns <tt>self.values[n]</tt>
1298 * if +n+ is in range;
1299 * see Array@Array+Indexes:
1300 *
1301 * joe[2] # => 12345
1302 * joe[-2] # => "123 Maple, Anytown NC"
1303 *
1304 * Raises IndexError if +n+ is out of range.
1305 *
1306 */
1307
1308VALUE
1310{
1311 int i = rb_struct_pos(s, &idx, false);
1312 if (i < 0) invalid_struct_pos(s, idx);
1313 return RSTRUCT_GET_RAW(s, i);
1314}
1315
1316/*
1317 * call-seq:
1318 * struct[name] = value -> value
1319 * struct[n] = value -> value
1320 *
1321 * Assigns a value to a member.
1322 *
1323 * With symbol or string argument +name+ given, assigns the given +value+
1324 * to the named member; returns +value+:
1325 *
1326 * Customer = Struct.new(:name, :address, :zip)
1327 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1328 * joe[:zip] = 54321 # => 54321
1329 * joe # => #<struct Customer name="Joe Smith", address="123 Maple, Anytown NC", zip=54321>
1330 *
1331 * Raises NameError if +name+ is not the name of a member.
1332 *
1333 * With integer argument +n+ given, assigns the given +value+
1334 * to the +n+-th member if +n+ is in range;
1335 * see Array@Array+Indexes:
1336 *
1337 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1338 * joe[2] = 54321 # => 54321
1339 * joe[-3] = 'Joseph Smith' # => "Joseph Smith"
1340 * joe # => #<struct Customer name="Joseph Smith", address="123 Maple, Anytown NC", zip=54321>
1341 *
1342 * Raises IndexError if +n+ is out of range.
1343 *
1344 */
1345
1346VALUE
1348{
1349 int i = rb_struct_pos(s, &idx, false);
1350 if (i < 0) invalid_struct_pos(s, idx);
1351 rb_struct_modify(s);
1352 RSTRUCT_SET_RAW(s, i, val);
1353 return val;
1354}
1355
1356FUNC_MINIMIZED(VALUE rb_struct_lookup(VALUE s, VALUE idx));
1357NOINLINE(static VALUE rb_struct_lookup_default(VALUE s, VALUE idx, VALUE notfound, bool name_only));
1358
1359VALUE
1360rb_struct_lookup(VALUE s, VALUE idx)
1361{
1362 return rb_struct_lookup_default(s, idx, Qnil, false);
1363}
1364
1365static VALUE
1366rb_struct_lookup_default(VALUE s, VALUE idx, VALUE notfound, bool name_only)
1367{
1368 int i = rb_struct_pos(s, &idx, name_only);
1369 if (i < 0) return notfound;
1370 return RSTRUCT_GET_RAW(s, i);
1371}
1372
1373static VALUE
1374struct_entry(VALUE s, rb_len_t n)
1375{
1376 return rb_struct_aref(s, LEN2NUM(n));
1377}
1378
1379/*
1380 * call-seq:
1381 * values_at(*integers) -> array
1382 * values_at(integer_range) -> array
1383 *
1384 * Returns an array of values from +self+.
1385 *
1386 * With integer arguments +integers+ given,
1387 * returns an array containing each value given by one of +integers+:
1388 *
1389 * Customer = Struct.new(:name, :address, :zip)
1390 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1391 * joe.values_at(0, 2) # => ["Joe Smith", 12345]
1392 * joe.values_at(2, 0) # => [12345, "Joe Smith"]
1393 * joe.values_at(2, 1, 0) # => [12345, "123 Maple, Anytown NC", "Joe Smith"]
1394 * joe.values_at(0, -3) # => ["Joe Smith", "Joe Smith"]
1395 *
1396 * Raises IndexError if any of +integers+ is out of range;
1397 * see Array@Array+Indexes.
1398 *
1399 * With integer range argument +integer_range+ given,
1400 * returns an array containing each value given by the elements of the range;
1401 * fills with +nil+ values for range elements larger than the structure:
1402 *
1403 * joe.values_at(0..2)
1404 * # => ["Joe Smith", "123 Maple, Anytown NC", 12345]
1405 * joe.values_at(-3..-1)
1406 * # => ["Joe Smith", "123 Maple, Anytown NC", 12345]
1407 * joe.values_at(1..4) # => ["123 Maple, Anytown NC", 12345, nil, nil]
1408 *
1409 * Raises RangeError if any element of the range is negative and out of range;
1410 * see Array@Array+Indexes.
1411 *
1412 */
1413
1414static VALUE
1415rb_struct_values_at(int argc, VALUE *argv, VALUE s)
1416{
1417 return rb_get_values_at(s, RSTRUCT_LEN_RAW(s), argc, argv, struct_entry);
1418}
1419
1420/*
1421 * call-seq:
1422 * select {|value| ... } -> array
1423 * select -> enumerator
1424 *
1425 * With a block given, returns an array of values from +self+
1426 * for which the block returns a truthy value:
1427 *
1428 * Customer = Struct.new(:name, :address, :zip)
1429 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1430 * a = joe.select {|value| value.is_a?(String) }
1431 * a # => ["Joe Smith", "123 Maple, Anytown NC"]
1432 * a = joe.select {|value| value.is_a?(Integer) }
1433 * a # => [12345]
1434 *
1435 * With no block given, returns an Enumerator.
1436 */
1437
1438static VALUE
1439rb_struct_select(int argc, VALUE *argv, VALUE s)
1440{
1441 VALUE result;
1442 rb_len_t i;
1443
1444 rb_check_arity(argc, 0, 0);
1445 RETURN_SIZED_ENUMERATOR(s, 0, 0, struct_enum_size);
1446 result = rb_ary_new();
1447 for (i = 0; i < RSTRUCT_LEN_RAW(s); i++) {
1448 if (RTEST(rb_yield(RSTRUCT_GET_RAW(s, i)))) {
1449 rb_ary_push(result, RSTRUCT_GET_RAW(s, i));
1450 }
1451 }
1452
1453 return result;
1454}
1455
1456static VALUE
1457recursive_equal(VALUE s, VALUE s2, int recur)
1458{
1459 rb_len_t i, len;
1460
1461 if (recur) return Qtrue; /* Subtle! */
1462 len = RSTRUCT_LEN_RAW(s);
1463 for (i=0; i<len; i++) {
1464 if (!rb_equal(RSTRUCT_GET_RAW(s, i), RSTRUCT_GET_RAW(s2, i))) return Qfalse;
1465 }
1466 return Qtrue;
1467}
1468
1469
1470/*
1471 * call-seq:
1472 * self == other -> true or false
1473 *
1474 * Returns whether both the following are true:
1475 *
1476 * - <tt>other.class == self.class</tt>.
1477 * - For each member name +name+, <tt>other.name == self.name</tt>.
1478 *
1479 * Examples:
1480 *
1481 * Customer = Struct.new(:name, :address, :zip)
1482 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1483 * joe_jr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1484 * joe_jr == joe # => true
1485 * joe_jr[:name] = 'Joe Smith, Jr.'
1486 * # => "Joe Smith, Jr."
1487 * joe_jr == joe # => false
1488 */
1489
1490static VALUE
1491rb_struct_equal(VALUE s, VALUE s2)
1492{
1493 if (s == s2) return Qtrue;
1494 if (!RB_TYPE_P(s2, T_STRUCT)) return Qfalse;
1495 if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse;
1496 if (RSTRUCT_LEN_RAW(s) != RSTRUCT_LEN_RAW(s2)) {
1497 rb_bug("inconsistent struct"); /* should never happen */
1498 }
1499
1500 return rb_exec_recursive_paired(recursive_equal, s, s2, s2);
1501}
1502
1503/*
1504 * call-seq:
1505 * hash -> integer
1506 *
1507 * Returns the integer hash value for +self+.
1508 *
1509 * Two structs of the same class and with the same content
1510 * will have the same hash code (and will compare using Struct#eql?):
1511 *
1512 * Customer = Struct.new(:name, :address, :zip)
1513 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1514 * joe_jr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1515 * joe.hash == joe_jr.hash # => true
1516 * joe_jr[:name] = 'Joe Smith, Jr.'
1517 * joe.hash == joe_jr.hash # => false
1518 *
1519 * Related: Object#hash.
1520 */
1521
1522static VALUE
1523rb_struct_hash(VALUE s)
1524{
1525 rb_len_t i, len;
1526 st_index_t h;
1527 VALUE n;
1528
1529 h = rb_hash_start(rb_hash(rb_obj_class(s)));
1530 len = RSTRUCT_LEN_RAW(s);
1531 for (i = 0; i < len; i++) {
1532 n = rb_hash(RSTRUCT_GET_RAW(s, i));
1533 h = rb_hash_uint(h, NUM2LONG(n));
1534 }
1535 h = rb_hash_end(h);
1536 return ST2FIX(h);
1537}
1538
1539static VALUE
1540recursive_eql(VALUE s, VALUE s2, int recur)
1541{
1542 rb_len_t i, len;
1543
1544 if (recur) return Qtrue; /* Subtle! */
1545 len = RSTRUCT_LEN_RAW(s);
1546 for (i=0; i<len; i++) {
1547 if (!rb_eql(RSTRUCT_GET_RAW(s, i), RSTRUCT_GET_RAW(s2, i))) return Qfalse;
1548 }
1549 return Qtrue;
1550}
1551
1552/*
1553 * call-seq:
1554 * eql?(other) -> true or false
1555 *
1556 * Returns +true+ if and only if the following are true; otherwise returns +false+:
1557 *
1558 * - <tt>other.class == self.class</tt>.
1559 * - For each member name +name+, <tt>other.name.eql?(self.name)</tt>.
1560 *
1561 * Customer = Struct.new(:name, :address, :zip)
1562 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1563 * joe_jr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1564 * joe_jr.eql?(joe) # => true
1565 * joe_jr[:name] = 'Joe Smith, Jr.'
1566 * joe_jr.eql?(joe) # => false
1567 *
1568 * Related: Object#==.
1569 */
1570
1571static VALUE
1572rb_struct_eql(VALUE s, VALUE s2)
1573{
1574 if (s == s2) return Qtrue;
1575 if (!RB_TYPE_P(s2, T_STRUCT)) return Qfalse;
1576 if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse;
1577 if (RSTRUCT_LEN_RAW(s) != RSTRUCT_LEN_RAW(s2)) {
1578 rb_bug("inconsistent struct"); /* should never happen */
1579 }
1580
1581 return rb_exec_recursive_paired(recursive_eql, s, s2, s2);
1582}
1583
1584/*
1585 * call-seq:
1586 * size -> integer
1587 *
1588 * Returns the number of members.
1589 *
1590 * Customer = Struct.new(:name, :address, :zip)
1591 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
1592 * joe.size #=> 3
1593 *
1594 */
1595
1596VALUE
1598{
1599 return LEN2NUM(RSTRUCT_LEN_RAW(s));
1600}
1601
1602/*
1603 * call-seq:
1604 * dig(name, *identifiers) -> object
1605 * dig(n, *identifiers) -> object
1606 *
1607 * Finds and returns an object among nested objects.
1608 * The nested objects may be instances of various classes.
1609 * See {Dig Methods}[rdoc-ref:dig_methods.rdoc].
1610 *
1611 *
1612 * Given symbol or string argument +name+,
1613 * returns the object that is specified by +name+ and +identifiers+:
1614 *
1615 * Foo = Struct.new(:a)
1616 * f = Foo.new(Foo.new({b: [1, 2, 3]}))
1617 * f.dig(:a) # => #<struct Foo a={b: [1, 2, 3]}>
1618 * f.dig(:a, :a) # => {b: [1, 2, 3]}
1619 * f.dig(:a, :a, :b) # => [1, 2, 3]
1620 * f.dig(:a, :a, :b, 0) # => 1
1621 * f.dig(:b, 0) # => nil
1622 *
1623 * Given integer argument +n+,
1624 * returns the object that is specified by +n+ and +identifiers+:
1625 *
1626 * f.dig(0) # => #<struct Foo a={b: [1, 2, 3]}>
1627 * f.dig(0, 0) # => {b: [1, 2, 3]}
1628 * f.dig(0, 0, :b) # => [1, 2, 3]
1629 * f.dig(0, 0, :b, 0) # => 1
1630 * f.dig(:b, 0) # => nil
1631 *
1632 */
1633
1634static VALUE
1635rb_struct_dig(int argc, VALUE *argv, VALUE self)
1636{
1638 self = rb_struct_lookup(self, *argv);
1639 if (!--argc) return self;
1640 ++argv;
1641 return rb_obj_dig(argc, argv, self, Qnil);
1642}
1643
1644/*
1645 * Document-class: Data
1646 *
1647 * Class \Data provides a convenient way to define simple classes
1648 * for value-alike objects.
1649 *
1650 * The simplest example of usage:
1651 *
1652 * Measure = Data.define(:amount, :unit)
1653 *
1654 * # Positional arguments constructor is provided
1655 * distance = Measure.new(100, 'km')
1656 * #=> #<data Measure amount=100, unit="km">
1657 *
1658 * # Keyword arguments constructor is provided
1659 * weight = Measure.new(amount: 50, unit: 'kg')
1660 * #=> #<data Measure amount=50, unit="kg">
1661 *
1662 * # Alternative form to construct an object:
1663 * speed = Measure[10, 'mPh']
1664 * #=> #<data Measure amount=10, unit="mPh">
1665 *
1666 * # Works with keyword arguments, too:
1667 * area = Measure[amount: 1.5, unit: 'm^2']
1668 * #=> #<data Measure amount=1.5, unit="m^2">
1669 *
1670 * # Argument accessors are provided:
1671 * distance.amount #=> 100
1672 * distance.unit #=> "km"
1673 *
1674 * Constructed object also has a reasonable definitions of #==
1675 * operator, #to_h hash conversion, and #deconstruct / #deconstruct_keys
1676 * to be used in pattern matching.
1677 *
1678 * ::define method accepts an optional block and evaluates it in
1679 * the context of the newly defined class. That allows to define
1680 * additional methods:
1681 *
1682 * Measure = Data.define(:amount, :unit) do
1683 * def <=>(other)
1684 * return unless other.is_a?(self.class) && other.unit == unit
1685 * amount <=> other.amount
1686 * end
1687 *
1688 * include Comparable
1689 * end
1690 *
1691 * Measure[3, 'm'] < Measure[5, 'm'] #=> true
1692 * Measure[3, 'm'] < Measure[5, 'kg']
1693 * # comparison of Measure with Measure failed (ArgumentError)
1694 *
1695 * Data provides no member writers, or enumerators: it is meant
1696 * to be a storage for immutable atomic values. But note that
1697 * if some of data members is of a mutable class, Data does no additional
1698 * immutability enforcement:
1699 *
1700 * Event = Data.define(:time, :weekdays)
1701 * event = Event.new('18:00', %w[Tue Wed Fri])
1702 * #=> #<data Event time="18:00", weekdays=["Tue", "Wed", "Fri"]>
1703 *
1704 * # There is no #time= or #weekdays= accessors, but changes are
1705 * # still possible:
1706 * event.weekdays << 'Sat'
1707 * event
1708 * #=> #<data Event time="18:00", weekdays=["Tue", "Wed", "Fri", "Sat"]>
1709 *
1710 * See also Struct, which is a similar concept, but has more
1711 * container-alike API, allowing to change contents of the object
1712 * and enumerate it.
1713 */
1714
1715/*
1716 * call-seq:
1717 * define(*symbols) -> class
1718 *
1719 * Defines a new \Data class.
1720 *
1721 * measure = Data.define(:amount, :unit)
1722 * #=> #<Class:0x00007f70c6868498>
1723 * measure.new(1, 'km')
1724 * #=> #<data amount=1, unit="km">
1725 *
1726 * # It you store the new class in the constant, it will
1727 * # affect #inspect and will be more natural to use:
1728 * Measure = Data.define(:amount, :unit)
1729 * #=> Measure
1730 * Measure.new(1, 'km')
1731 * #=> #<data Measure amount=1, unit="km">
1732 *
1733 *
1734 * Note that member-less \Data is acceptable and might be a useful technique
1735 * for defining several homogeneous data classes, like
1736 *
1737 * class HTTPFetcher
1738 * Response = Data.define(:body)
1739 * NotFound = Data.define
1740 * # ... implementation
1741 * end
1742 *
1743 * Now, different kinds of responses from +HTTPFetcher+ would have consistent
1744 * representation:
1745 *
1746 * #<data HTTPFetcher::Response body="<html...">
1747 * #<data HTTPFetcher::NotFound>
1748 *
1749 * And are convenient to use in pattern matching:
1750 *
1751 * case fetcher.get(url)
1752 * in HTTPFetcher::Response(body)
1753 * # process body variable
1754 * in HTTPFetcher::NotFound
1755 * # handle not found case
1756 * end
1757 */
1758
1759static VALUE
1760rb_data_s_def(int argc, VALUE *argv, VALUE klass)
1761{
1762 VALUE rest;
1763 rb_len_t i;
1764 VALUE data_class;
1765
1766 rest = rb_ident_hash_new();
1767 RBASIC_CLEAR_CLASS(rest);
1768 for (i=0; i<argc; i++) {
1769 VALUE mem = rb_to_symbol(argv[i]);
1770 if (rb_is_attrset_sym(mem)) {
1771 rb_raise(rb_eArgError, "invalid data member: %"PRIsVALUE, mem);
1772 }
1773 if (RTEST(rb_hash_has_key(rest, mem))) {
1774 rb_raise(rb_eArgError, "duplicate member: %"PRIsVALUE, mem);
1775 }
1776 rb_hash_aset(rest, mem, Qtrue);
1777 }
1778 rest = rb_hash_keys(rest);
1779 RBASIC_CLEAR_CLASS(rest);
1780 OBJ_FREEZE(rest);
1781 data_class = anonymous_struct(klass);
1782 setup_data(data_class, rest);
1783 if (rb_block_given_p()) {
1784 rb_mod_module_eval(0, 0, data_class);
1785 }
1786
1787 return data_class;
1788}
1789
1790VALUE
1792{
1793 va_list ar;
1794 VALUE ary;
1795 va_start(ar, super);
1796 ary = struct_make_members_list(ar);
1797 va_end(ar);
1798 if (!super) super = rb_cData;
1799 VALUE klass = setup_data(anonymous_struct(super), ary);
1800 rb_vm_register_global_object(klass);
1801 return klass;
1802}
1803
1804static int
1805data_hash_set_i(VALUE key, VALUE val, VALUE arg)
1806{
1807 struct struct_hash_set_arg *args = (struct struct_hash_set_arg *)arg;
1808 int i = struct_hash_aset(key, val, args, true);
1809 if (i >= 0 && args->missing_count > 0) {
1810 VALUE k = RARRAY_AREF(args->missing_keywords, i);
1811 if (!NIL_P(k)) {
1812 RARRAY_ASET(args->missing_keywords, i, Qnil);
1813 args->missing_count--;
1814 }
1815 }
1816 return ST_CONTINUE;
1817}
1818
1819/*
1820 * call-seq:
1821 * DataClass::members -> array_of_symbols
1822 *
1823 * Returns an array of member names of the data class:
1824 *
1825 * Measure = Data.define(:amount, :unit)
1826 * Measure.members # => [:amount, :unit]
1827 *
1828 */
1829
1830#define rb_data_s_members_m rb_struct_s_members_m
1831
1832
1833/*
1834 * call-seq:
1835 * new(*args) -> instance
1836 * new(**kwargs) -> instance
1837 * ::[](*args) -> instance
1838 * ::[](**kwargs) -> instance
1839 *
1840 * Constructors for classes defined with ::define accept both positional and
1841 * keyword arguments.
1842 *
1843 * Measure = Data.define(:amount, :unit)
1844 *
1845 * Measure.new(1, 'km')
1846 * #=> #<data Measure amount=1, unit="km">
1847 * Measure.new(amount: 1, unit: 'km')
1848 * #=> #<data Measure amount=1, unit="km">
1849 *
1850 * # Alternative shorter initialization with []
1851 * Measure[1, 'km']
1852 * #=> #<data Measure amount=1, unit="km">
1853 * Measure[amount: 1, unit: 'km']
1854 * #=> #<data Measure amount=1, unit="km">
1855 *
1856 * All arguments are mandatory (unlike Struct), and converted to keyword arguments:
1857 *
1858 * Measure.new(amount: 1)
1859 * # in `initialize': missing keyword: :unit (ArgumentError)
1860 *
1861 * Measure.new(1)
1862 * # in `initialize': missing keyword: :unit (ArgumentError)
1863 *
1864 * Note that <tt>Measure#initialize</tt> always receives keyword arguments, and that
1865 * mandatory arguments are checked in +initialize+, not in +new+. This can be
1866 * important for redefining initialize in order to convert arguments or provide
1867 * defaults:
1868 *
1869 * Measure = Data.define(:amount, :unit)
1870 * class Measure
1871 * NONE = Data.define
1872 *
1873 * def initialize(amount:, unit: NONE.new)
1874 * super(amount: Float(amount), unit:)
1875 * end
1876 * end
1877 *
1878 * Measure.new('10', 'km') # => #<data Measure amount=10.0, unit="km">
1879 * Measure.new(10_000) # => #<data Measure amount=10000.0, unit=#<data Measure::NONE>>
1880 *
1881 */
1882
1883static VALUE
1884rb_data_initialize_m(int argc, const VALUE *argv, VALUE self)
1885{
1886 VALUE klass = rb_obj_class(self);
1887 rb_struct_modify(self);
1888 VALUE members = struct_ivar_get(klass, id_members);
1889 size_t num_members = RARRAY_LEN(members);
1890
1891 if (argc == 0) {
1892 if (num_members > 0) {
1893 rb_exc_raise(rb_keyword_error_new("missing", members));
1894 }
1895 OBJ_FREEZE(self);
1896 return Qnil;
1897 }
1898 if (argc > 1 || !RB_TYPE_P(argv[0], T_HASH)) {
1899 rb_error_arity(argc, 0, 0);
1900 }
1901
1902 VALUE missing = rb_ary_dup(members);
1903 RBASIC_CLEAR_CLASS(missing);
1904 struct struct_hash_set_arg arg = {
1905 .self = self,
1906 .unknown_keywords = Qnil,
1907 .missing_keywords = missing,
1908 .missing_count = (rb_len_t)num_members,
1909 };
1910 rb_mem_clear((VALUE *)RSTRUCT_CONST_PTR(self), num_members);
1911 rb_hash_foreach(argv[0], data_hash_set_i, (VALUE)&arg);
1912 // Freeze early before potentially raising, so that we don't leave an
1913 // unfrozen copy on the heap, which could get exposed via ObjectSpace.
1914 OBJ_FREEZE(self);
1915 if (UNLIKELY(arg.missing_count > 0)) {
1916 rb_ary_compact_bang(missing);
1917 RUBY_ASSERT(RARRAY_LEN(missing) == arg.missing_count, "missing_count=%"PRIdLEN" but %"PRIdLEN, arg.missing_count, RARRAY_LEN(missing));
1918 RBASIC_SET_CLASS_RAW(missing, rb_cArray);
1919 rb_exc_raise(rb_keyword_error_new("missing", missing));
1920 }
1921 VALUE unknown_keywords = arg.unknown_keywords;
1922 if (UNLIKELY(!NIL_P(unknown_keywords))) {
1923 RBASIC_SET_CLASS_RAW(unknown_keywords, rb_cArray);
1924 rb_exc_raise(rb_keyword_error_new("unknown", unknown_keywords));
1925 }
1926
1927 return Qnil;
1928}
1929
1930/* :nodoc: */
1931static VALUE
1932rb_data_init_copy(VALUE copy, VALUE s)
1933{
1934 copy = rb_struct_init_copy(copy, s);
1935 RB_OBJ_FREEZE(copy);
1936 return copy;
1937}
1938
1939/*
1940 * call-seq:
1941 * with(**kwargs) -> instance
1942 *
1943 * Returns a shallow copy of +self+ --- the instance variables of
1944 * +self+ are copied, but not the objects they reference.
1945 *
1946 * If the method is supplied any keyword arguments, the copy will
1947 * be created with the respective field values updated to use the
1948 * supplied keyword argument values. Note that it is an error to
1949 * supply a keyword that the Data class does not have as a member.
1950 *
1951 * Point = Data.define(:x, :y)
1952 *
1953 * origin = Point.new(x: 0, y: 0)
1954 *
1955 * up = origin.with(x: 1)
1956 * right = origin.with(y: 1)
1957 * up_and_right = up.with(y: 1)
1958 *
1959 * p origin # #<data Point x=0, y=0>
1960 * p up # #<data Point x=1, y=0>
1961 * p right # #<data Point x=0, y=1>
1962 * p up_and_right # #<data Point x=1, y=1>
1963 *
1964 * out = origin.with(z: 1) # ArgumentError: unknown keyword: :z
1965 * some_point = origin.with(1, 2) # ArgumentError: expected keyword arguments, got positional arguments
1966 *
1967 */
1968
1969static VALUE
1970rb_data_with(int argc, const VALUE *argv, VALUE self)
1971{
1972 VALUE kwargs;
1973 rb_scan_args(argc, argv, "0:", &kwargs);
1974 if (NIL_P(kwargs)) {
1975 return self;
1976 }
1977
1978 VALUE h = rb_struct_to_h(self);
1979 rb_hash_update_by(h, kwargs, 0);
1980 return rb_class_new_instance_kw(1, &h, rb_obj_class(self), TRUE);
1981}
1982
1983/*
1984 * call-seq:
1985 * inspect -> string
1986 * to_s -> string
1987 *
1988 * Returns a string representation of +self+:
1989 *
1990 * Measure = Data.define(:amount, :unit)
1991 *
1992 * distance = Measure[10, 'km']
1993 *
1994 * p distance # uses #inspect underneath
1995 * #<data Measure amount=10, unit="km">
1996 *
1997 * puts distance # uses #to_s underneath, same representation
1998 * #<data Measure amount=10, unit="km">
1999 *
2000 */
2001
2002static VALUE
2003rb_data_inspect(VALUE s)
2004{
2005 return rb_exec_recursive(inspect_struct, s, rb_str_new2("#<data"));
2006}
2007
2008/*
2009 * call-seq:
2010 * self == other -> true or false
2011 *
2012 * Returns whether +other+ is the same class as +self+, and all members are
2013 * equal.
2014 *
2015 * Examples:
2016 *
2017 * Measure = Data.define(:amount, :unit)
2018 *
2019 * Measure[1, 'km'] == Measure[1, 'km'] #=> true
2020 * Measure[1, 'km'] == Measure[2, 'km'] #=> false
2021 * Measure[1, 'km'] == Measure[1, 'm'] #=> false
2022 *
2023 * Measurement = Data.define(:amount, :unit)
2024 * # Even though Measurement and Measure have the same "shape"
2025 * # their instances are never equal
2026 * Measure[1, 'km'] == Measurement[1, 'km'] #=> false
2027 */
2028
2029#define rb_data_equal rb_struct_equal
2030
2031/*
2032 * call-seq:
2033 * self.eql?(other) -> true or false
2034 *
2035 * Equality check that is used when two items of data are keys of a Hash.
2036 *
2037 * The subtle difference with #== is that members are also compared with their
2038 * #eql? method, which might be important in some cases:
2039 *
2040 * Measure = Data.define(:amount, :unit)
2041 *
2042 * Measure[1, 'km'] == Measure[1.0, 'km'] #=> true, they are equal as values
2043 * # ...but...
2044 * Measure[1, 'km'].eql? Measure[1.0, 'km'] #=> false, they represent different hash keys
2045 *
2046 * See also Object#eql? for further explanations of the method usage.
2047 */
2048
2049#define rb_data_eql rb_struct_eql
2050
2051/*
2052 * call-seq:
2053 * hash -> integer
2054 *
2055 * Redefines Object#hash (used to distinguish objects as Hash keys) so that
2056 * data objects of the same class with same content would have the same +hash+
2057 * value, and represented the same Hash key.
2058 *
2059 * Measure = Data.define(:amount, :unit)
2060 *
2061 * Measure[1, 'km'].hash == Measure[1, 'km'].hash #=> true
2062 * Measure[1, 'km'].hash == Measure[10, 'km'].hash #=> false
2063 * Measure[1, 'km'].hash == Measure[1, 'm'].hash #=> false
2064 * Measure[1, 'km'].hash == Measure[1.0, 'km'].hash #=> false
2065 *
2066 * # Structurally similar data class, but shouldn't be considered
2067 * # the same hash key
2068 * Measurement = Data.define(:amount, :unit)
2069 *
2070 * Measure[1, 'km'].hash == Measurement[1, 'km'].hash #=> false
2071 */
2072
2073#define rb_data_hash rb_struct_hash
2074
2075/*
2076 * call-seq:
2077 * to_h -> hash
2078 * to_h {|name, value| ... } -> hash
2079 *
2080 * Returns Hash representation of the data object.
2081 *
2082 * Measure = Data.define(:amount, :unit)
2083 * distance = Measure[10, 'km']
2084 *
2085 * distance.to_h
2086 * #=> {amount: 10, unit: "km"}
2087 *
2088 * Like Enumerable#to_h, if the block is provided, it is expected to
2089 * produce key-value pairs to construct a hash:
2090 *
2091 *
2092 * distance.to_h { |name, val| [name.to_s, val.to_s] }
2093 * #=> {"amount"=>"10", "unit"=>"km"}
2094 *
2095 * Note that there is a useful symmetry between #to_h and #initialize:
2096 *
2097 * distance2 = Measure.new(**distance.to_h)
2098 * #=> #<data Measure amount=10, unit="km">
2099 * distance2 == distance
2100 * #=> true
2101 */
2102
2103#define rb_data_to_h rb_struct_to_h
2104
2105/*
2106 * call-seq:
2107 * members -> array_of_symbols
2108 *
2109 * Returns the member names from +self+ as an array:
2110 *
2111 * Measure = Data.define(:amount, :unit)
2112 * distance = Measure[10, 'km']
2113 *
2114 * distance.members #=> [:amount, :unit]
2115 *
2116 */
2117
2118#define rb_data_members_m rb_struct_members_m
2119
2120/*
2121 * call-seq:
2122 * deconstruct -> array
2123 *
2124 * Returns the values in +self+ as an array, to use in pattern matching:
2125 *
2126 * Measure = Data.define(:amount, :unit)
2127 *
2128 * distance = Measure[10, 'km']
2129 * distance.deconstruct #=> [10, "km"]
2130 *
2131 * # usage
2132 * case distance
2133 * in n, 'km' # calls #deconstruct underneath
2134 * puts "It is #{n} kilometers away"
2135 * else
2136 * puts "Don't know how to handle it"
2137 * end
2138 * # prints "It is 10 kilometers away"
2139 *
2140 * Or, with checking the class, too:
2141 *
2142 * case distance
2143 * in Measure(n, 'km')
2144 * puts "It is #{n} kilometers away"
2145 * # ...
2146 * end
2147 */
2148
2149#define rb_data_deconstruct rb_struct_to_a
2150
2151/*
2152 * call-seq:
2153 * deconstruct_keys(array_of_names_or_nil) -> hash
2154 *
2155 * Returns a hash of the name/value pairs, to use in pattern matching.
2156 *
2157 * Measure = Data.define(:amount, :unit)
2158 *
2159 * distance = Measure[10, 'km']
2160 * distance.deconstruct_keys(nil) #=> {amount: 10, unit: "km"}
2161 * distance.deconstruct_keys([:amount]) #=> {amount: 10}
2162 *
2163 * # usage
2164 * case distance
2165 * in amount:, unit: 'km' # calls #deconstruct_keys underneath
2166 * puts "It is #{amount} kilometers away"
2167 * else
2168 * puts "Don't know how to handle it"
2169 * end
2170 * # prints "It is 10 kilometers away"
2171 *
2172 * Or, with checking the class, too:
2173 *
2174 * case distance
2175 * in Measure(amount:, unit: 'km')
2176 * puts "It is #{amount} kilometers away"
2177 * # ...
2178 * end
2179 */
2180
2181static VALUE
2182rb_data_deconstruct_keys(VALUE s, VALUE keys)
2183{
2184 return deconstruct_keys(s, keys, true);
2185}
2186
2187/*
2188 * Document-class: Struct
2189 *
2190 * Class \Struct provides a convenient way to create a simple class
2191 * that can store and fetch values.
2192 *
2193 * This example creates a subclass of +Struct+, <tt>Struct::Customer</tt>;
2194 * the first argument, a string, is the name of the subclass;
2195 * the other arguments, symbols, determine the _members_ of the new subclass.
2196 *
2197 * Customer = Struct.new('Customer', :name, :address, :zip)
2198 * Customer.name # => "Struct::Customer"
2199 * Customer.class # => Class
2200 * Customer.superclass # => Struct
2201 *
2202 * Corresponding to each member are two methods, a writer and a reader,
2203 * that store and fetch values:
2204 *
2205 * methods = Customer.instance_methods false
2206 * methods # => [:zip, :address=, :zip=, :address, :name, :name=]
2207 *
2208 * An instance of the subclass may be created,
2209 * and its members assigned values, via method <tt>::new</tt>:
2210 *
2211 * joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
2212 * joe # => #<struct Struct::Customer name="Joe Smith", address="123 Maple, Anytown NC", zip=12345>
2213 *
2214 * The member values may be managed thus:
2215 *
2216 * joe.name # => "Joe Smith"
2217 * joe.name = 'Joseph Smith'
2218 * joe.name # => "Joseph Smith"
2219 *
2220 * And thus; note that member name may be expressed as either a string or a symbol:
2221 *
2222 * joe[:name] # => "Joseph Smith"
2223 * joe[:name] = 'Joseph Smith, Jr.'
2224 * joe['name'] # => "Joseph Smith, Jr."
2225 *
2226 * See Struct::new.
2227 *
2228 * == What's Here
2229 *
2230 * First, what's elsewhere. Class \Struct:
2231 *
2232 * - Inherits from {class Object}[rdoc-ref:Object@Whats+Here].
2233 * - Includes {module Enumerable}[rdoc-ref:Enumerable@Whats+Here],
2234 * which provides dozens of additional methods.
2235 *
2236 * See also Data, which is a somewhat similar, but stricter concept for defining immutable
2237 * value objects.
2238 *
2239 * Here, class \Struct provides methods that are useful for:
2240 *
2241 * - {Creating a Struct Subclass}[rdoc-ref:Struct@Methods+for+Creating+a+Struct+Subclass]
2242 * - {Querying}[rdoc-ref:Struct@Methods+for+Querying]
2243 * - {Comparing}[rdoc-ref:Struct@Methods+for+Comparing]
2244 * - {Fetching}[rdoc-ref:Struct@Methods+for+Fetching]
2245 * - {Assigning}[rdoc-ref:Struct@Methods+for+Assigning]
2246 * - {Iterating}[rdoc-ref:Struct@Methods+for+Iterating]
2247 * - {Converting}[rdoc-ref:Struct@Methods+for+Converting]
2248 *
2249 * === Methods for Creating a Struct Subclass
2250 *
2251 * - ::new: Returns a new subclass of \Struct.
2252 *
2253 * === Methods for Querying
2254 *
2255 * - #hash: Returns the integer hash code.
2256 * - #size (aliased as #length): Returns the number of members.
2257 *
2258 * === Methods for Comparing
2259 *
2260 * - #==: Returns whether a given object is equal to +self+, using <tt>==</tt>
2261 * to compare member values.
2262 * - #eql?: Returns whether a given object is equal to +self+,
2263 * using <tt>eql?</tt> to compare member values.
2264 *
2265 * === Methods for Fetching
2266 *
2267 * - #[]: Returns the value associated with a given member name.
2268 * - #to_a (aliased as #values, #deconstruct): Returns the member values in +self+ as an array.
2269 * - #deconstruct_keys: Returns a hash of the name/value pairs
2270 * for given member names.
2271 * - #dig: Returns the object in nested objects that is specified
2272 * by a given member name and additional arguments.
2273 * - #members: Returns an array of the member names.
2274 * - #select (aliased as #filter): Returns an array of member values from +self+,
2275 * as selected by the given block.
2276 * - #values_at: Returns an array containing values for given member names.
2277 *
2278 * === Methods for Assigning
2279 *
2280 * - #[]=: Assigns a given value to a given member name.
2281 *
2282 * === Methods for Iterating
2283 *
2284 * - #each: Calls a given block with each member name.
2285 * - #each_pair: Calls a given block with each member name/value pair.
2286 *
2287 * === Methods for Converting
2288 *
2289 * - #inspect (aliased as #to_s): Returns a string representation of +self+.
2290 * - #to_h: Returns a hash of the member name/value pairs in +self+.
2291 *
2292 */
2293void
2294InitVM_Struct(void)
2295{
2296 rb_cStruct = rb_define_class("Struct", rb_cObject);
2298
2300 rb_define_singleton_method(rb_cStruct, "new", rb_struct_s_def, -1);
2301#if 0 /* for RDoc */
2302 rb_define_singleton_method(rb_cStruct, "keyword_init?", rb_struct_s_keyword_init_p, 0);
2303 rb_define_singleton_method(rb_cStruct, "members", rb_struct_s_members_m, 0);
2304#endif
2305
2306 rb_define_method(rb_cStruct, "initialize", rb_struct_initialize_m, -1);
2307 rb_define_method(rb_cStruct, "initialize_copy", rb_struct_init_copy, 1);
2308
2309 rb_define_method(rb_cStruct, "==", rb_struct_equal, 1);
2310 rb_define_method(rb_cStruct, "eql?", rb_struct_eql, 1);
2311 rb_define_method(rb_cStruct, "hash", rb_struct_hash, 0);
2312
2313 rb_define_method(rb_cStruct, "inspect", rb_struct_inspect, 0);
2314 rb_define_alias(rb_cStruct, "to_s", "inspect");
2315 rb_define_method(rb_cStruct, "to_a", rb_struct_to_a, 0);
2316 rb_define_method(rb_cStruct, "to_h", rb_struct_to_h, 0);
2317 rb_define_method(rb_cStruct, "values", rb_struct_to_a, 0);
2318 rb_define_method(rb_cStruct, "size", rb_struct_size, 0);
2319 rb_define_method(rb_cStruct, "length", rb_struct_size, 0);
2320
2321 rb_define_method(rb_cStruct, "each", rb_struct_each, 0);
2322 rb_define_method(rb_cStruct, "each_pair", rb_struct_each_pair, 0);
2323 rb_define_method(rb_cStruct, "[]", rb_struct_aref, 1);
2324 rb_define_method(rb_cStruct, "[]=", rb_struct_aset, 2);
2325 rb_define_method(rb_cStruct, "select", rb_struct_select, -1);
2326 rb_define_method(rb_cStruct, "filter", rb_struct_select, -1);
2327 rb_define_method(rb_cStruct, "values_at", rb_struct_values_at, -1);
2328
2329 rb_define_method(rb_cStruct, "members", rb_struct_members_m, 0);
2330 rb_define_method(rb_cStruct, "dig", rb_struct_dig, -1);
2331
2332 rb_define_method(rb_cStruct, "deconstruct", rb_struct_to_a, 0);
2333 rb_define_method(rb_cStruct, "deconstruct_keys", rb_struct_deconstruct_keys, 1);
2334
2335 rb_cData = rb_define_class("Data", rb_cObject);
2336
2337 rb_undef_method(CLASS_OF(rb_cData), "new");
2338 rb_undef_alloc_func(rb_cData);
2339 rb_define_singleton_method(rb_cData, "define", rb_data_s_def, -1);
2340
2341#if 0 /* for RDoc */
2342 rb_define_singleton_method(rb_cData, "members", rb_data_s_members_m, 0);
2343#endif
2344
2345 rb_define_method(rb_cData, "initialize", rb_data_initialize_m, -1);
2346 rb_define_method(rb_cData, "initialize_copy", rb_data_init_copy, 1);
2347
2348 rb_define_method(rb_cData, "==", rb_data_equal, 1);
2349 rb_define_method(rb_cData, "eql?", rb_data_eql, 1);
2350 rb_define_method(rb_cData, "hash", rb_data_hash, 0);
2351
2352 rb_define_method(rb_cData, "inspect", rb_data_inspect, 0);
2353 rb_define_alias(rb_cData, "to_s", "inspect");
2354 rb_define_method(rb_cData, "to_h", rb_data_to_h, 0);
2355
2356 rb_define_method(rb_cData, "members", rb_data_members_m, 0);
2357
2358 rb_define_method(rb_cData, "deconstruct", rb_data_deconstruct, 0);
2359 rb_define_method(rb_cData, "deconstruct_keys", rb_data_deconstruct_keys, 1);
2360
2361 rb_define_method(rb_cData, "with", rb_data_with, -1);
2362}
2363
2364#undef rb_intern
2365void
2366Init_Struct(void)
2367{
2368 id_members = rb_intern("__members__");
2369 id_back_members = rb_intern("__members_back__");
2370 id_keyword_init = rb_intern("__keyword_init__");
2371
2372 InitVM(Struct);
2373}
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
static void RB_OBJ_FREEZE(VALUE obj)
Freeze the given object if it is not frozen yet.
Definition fl_type.h:756
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1736
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:853
VALUE rb_singleton_class(VALUE obj)
Finds or creates the singleton class of the passed object.
Definition class.c:3017
VALUE rb_define_class_id_under(VALUE outer, ID id, VALUE super)
Identical to rb_define_class_under(), except it takes the name in ID instead of C's string.
Definition class.c:1604
VALUE rb_class_inherited(VALUE super, VALUE klass)
Calls Class::inherited.
Definition class.c:1528
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:3060
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
Definition class.c:2863
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
Definition class.c:3350
int rb_keyword_given_p(void)
Determines if the current method is given a keyword argument.
Definition eval.c:1048
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1035
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:3139
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1700
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
Definition fl_type.h:133
#define LEN2NUM
Old name of RB_LEN2NUM.
Definition len_t.h:33
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1708
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_STRUCT
Old name of RUBY_T_STRUCT.
Definition value_type.h:79
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:131
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define SYM2ID
Old name of RB_SYM2ID.
Definition symbol.h:45
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:205
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define FIX2INT
Old name of RB_FIX2INT.
Definition int.h:41
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define Qtrue
Old name of RUBY_Qtrue.
#define ST2FIX
Old name of RB_ST2FIX.
Definition st_data_t.h:33
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define T_CLASS
Old name of RUBY_T_CLASS.
Definition value_type.h:58
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define NUM2LEN
Old name of RB_NUM2LEN.
Definition len_t.h:34
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:678
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1457
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:464
VALUE rb_eIndexError
IndexError exception.
Definition error.c:1459
VALUE rb_class_superclass(VALUE klass)
Queries the parent of the given class.
Definition object.c:2330
VALUE rb_cArray
Array class.
VALUE rb_cObject
Object class.
Definition object.c:60
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2274
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2315
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
Definition object.c:2303
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:28
VALUE rb_cStruct
Struct class.
Definition struct.c:33
VALUE rb_class_new_instance_pass_kw(int argc, const VALUE *argv, VALUE klass)
Identical to rb_class_new_instance(), except it passes the passed keywords if any to the #initialize ...
Definition object.c:2292
int rb_eql(VALUE lhs, VALUE rhs)
Checks for equality of the passed objects, in terms of Object#eql?.
Definition object.c:153
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:240
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:675
VALUE rb_equal(VALUE lhs, VALUE rhs)
This function is an optimised version of calling #==.
Definition object.c:140
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
Definition object.c:912
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_entry(VALUE ary, rb_len_t off)
Queries an element of an array.
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
void rb_ary_store(VALUE ary, rb_len_t key, VALUE val)
Destructively stores the passed value to the passed array's passed index.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_hidden_new(rb_len_t capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
void rb_mem_clear(VALUE *buf, rb_len_t len)
Fills the memory region with a series of RUBY_Qnil.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
VALUE rb_get_values_at(VALUE obj, rb_len_t olen, int argc, const VALUE *argv, VALUE(*func)(VALUE obj, rb_len_t oidx))
This was a generalisation of Array#values_at, Struct#values_at, and MatchData#values_at.
#define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn)
This roughly resembles return enum_for(__callee__) unless block_given?.
Definition enumerator.h:208
#define UNLIMITED_ARGUMENTS
This macro is used in conjunction with rb_check_arity().
Definition error.h:35
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
int rb_is_const_id(ID id)
Classifies the given ID, then sees if it is a constant.
Definition symbol.c:1235
int rb_is_local_id(ID id)
Classifies the given ID, then sees if it is a local variable.
Definition symbol.c:1265
#define rb_hash_uint(h, i)
Just another name of st_hash_uint.
Definition string.h:967
#define rb_hash_end(h)
Just another name of st_hash_end.
Definition string.h:970
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3924
st_index_t rb_hash_start(st_index_t i)
Starts a series of hashing.
Definition random.c:1714
#define rb_str_cat_cstr(buf, str)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1681
VALUE rb_struct_define_without_accessor_under(VALUE outer, const char *class_name, VALUE super, rb_alloc_func_t alloc,...)
Identical to rb_struct_define_without_accessor(), except it defines the class under the specified nam...
Definition struct.c:487
VALUE rb_struct_define_under(VALUE space, const char *name,...)
Identical to rb_struct_define(), except it defines the class under the specified namespace instead of...
Definition struct.c:533
VALUE rb_struct_new(VALUE klass,...)
Creates an instance of the given struct.
Definition struct.c:927
VALUE rb_struct_initialize(VALUE self, VALUE values)
Mass-assigns a struct's fields.
Definition struct.c:840
VALUE rb_struct_define_without_accessor(const char *name, VALUE super, rb_alloc_func_t func,...)
Identical to rb_struct_define(), except it does not define accessor methods.
Definition struct.c:500
VALUE rb_struct_define(const char *name,...)
Defines a struct class.
Definition struct.c:513
VALUE rb_struct_alloc(VALUE klass, VALUE values)
Identical to rb_struct_new(), except it takes the field values as a Ruby array.
Definition struct.c:921
VALUE rb_data_define(VALUE super,...)
Defines an anonymous data class.
Definition struct.c:1791
VALUE rb_struct_alloc_noinit(VALUE klass)
Allocates an instance of the given class.
Definition struct.c:433
VALUE rb_struct_s_members(VALUE klass)
Queries the list of the names of the fields of the given struct class.
Definition struct.c:68
VALUE rb_struct_members(VALUE self)
Queries the list of the names of the fields of the class of the given struct object.
Definition struct.c:82
VALUE rb_struct_getmember(VALUE self, ID key)
Identical to rb_struct_aref(), except it takes ID instead of VALUE.
Definition struct.c:233
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_exec_recursive_paired(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE p, VALUE h)
Identical to rb_exec_recursive(), except it checks for the recursion on the ordered pair of { g,...
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:2150
VALUE rb_mod_remove_const(VALUE space, VALUE name)
Resembles Module#remove_const.
Definition variable.c:3578
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:516
int rb_const_defined_at(VALUE space, ID name)
Identical to rb_const_defined(), except it doesn't look for parent classes.
Definition variable.c:3814
VALUE rb_class_path(VALUE mod)
Identical to rb_mod_name(), except it returns #<Class: ...> style inspection for anonymous modules.
Definition variable.c:396
VALUE(* rb_alloc_func_t)(VALUE klass)
This is the type of functions that ruby calls when trying to allocate an object.
Definition vm.h:219
void rb_undef_alloc_func(VALUE klass)
Deletes the allocator function of a class.
Definition vm_method.c:1865
rb_alloc_func_t rb_get_alloc_func(VALUE klass)
Queries the allocator function of a class.
Definition vm_method.c:1874
VALUE rb_mod_module_eval(int argc, const VALUE *argv, VALUE mod)
Identical to rb_obj_instance_eval(), except it evaluates within the context of module.
Definition vm_eval.c:2478
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
VALUE rb_check_symbol(volatile VALUE *namep)
Identical to rb_check_id(), except it returns an instance of rb_cSymbol instead.
Definition symbol.c:1348
VALUE rb_sym2str(VALUE symbol)
Obtain a frozen string representation of a symbol (not including the leading colon).
Definition symbol.c:1148
VALUE rb_to_symbol(VALUE name)
Identical to rb_intern_str(), except it generates a dynamic symbol if necessary.
Definition string.c:14221
ID rb_to_id(VALUE str)
Identical to rb_intern_str(), except it tries to convert the parameter object to an instance of rb_cS...
Definition string.c:14211
int off
Offset inside of ptr.
Definition io.h:5
int len
Length of the buffer.
Definition io.h:8
VALUE rb_yield_values(int n,...)
Identical to rb_yield(), except it takes variadic number of parameters and pass them to the block.
Definition vm_eval.c:1402
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1379
#define rb_len2int
Just another name of rb_len2int_inline.
Definition len_t.h:37
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
void rb_hash_foreach(VALUE q, int_type *w, VALUE e)
Iteration over the given hash.
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:50
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:280
static VALUE * RARRAY_PTR(VALUE ary)
Wild use of a C pointer.
Definition rarray.h:365
#define RARRAY_AREF(a, i)
References an object in an array.
Definition rarray.h:421
static void RARRAY_ASET(VALUE ary, rb_len_t i, VALUE v)
Assigns an object in an array.
Definition rarray.h:385
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:51
#define RBASIC(obj)
Convenient casting macro.
Definition rbasic.h:40
VALUE rb_str_to_str(VALUE obj)
Identical to rb_check_string_type(), except it raises exceptions in case of conversion failures.
Definition string.c:1830
VALUE rb_struct_aset(VALUE st, VALUE k, VALUE v)
Resembles Struct#[]=.
Definition struct.c:1347
VALUE rb_struct_size(VALUE st)
Returns the number of struct members.
Definition struct.c:1597
VALUE rb_struct_aref(VALUE st, VALUE k)
Resembles Struct#[].
Definition struct.c:1309
#define InitVM(ext)
This macro is for internal use.
Definition ruby.h:231
#define RB_PASS_KEYWORDS
Pass keywords, final argument must be a hash of keywords.
Definition scan_args.h:72
#define RTEST
This is an old name of RB_TEST.
Ruby's ordinal objects.
Definition robject.h:51
VALUE extended
When an object slot is too small or too complex to store instance variables inline,...
Definition robject.h:73
Definition method.h:63
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
Definition value.h:142
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376