File: Struct.xs

package info (click to toggle)
libobject-pad-classattr-struct-perl 0.06-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 136 kB
  • sloc: perl: 110; makefile: 7; sh: 1
file content (95 lines) | stat: -rw-r--r-- 2,233 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/*  You may distribute under the terms of either the GNU General Public License
 *  or the Artistic License (the same terms as Perl itself)
 *
 *  (C) Paul Evans, 2021-2022 -- leonerd@leonerd.org.uk
 */
#define PERL_NO_GET_CONTEXT

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "object_pad.h"

enum {
  FLAG_READONLY = (1<<0),
};

static bool struct_apply(pTHX_ ClassMeta *classmeta, SV *value, SV **attrdata_ptr, void *_funcdata)
{
  U32 flags = 0;

  if(value && SvPOK(value)) {
    const char *s = SvPVX(value), *e = s + SvCUR(value);

    while(s < e) {
      const char *comma_at = strchr(s, ',');
      if(!comma_at)
        comma_at = e;
      STRLEN len = comma_at - s;

      if(len == 8 && strnEQ(s, "readonly", len))
        flags |= FLAG_READONLY;
      else
        croak("Unrecognised :Struct() option \"%.*s\"", (int)len, s);

      s += len;
      while(*s == ',')
        s++;
    }
  }

  if(flags)
    *attrdata_ptr = newSVuv(flags);

  mop_class_apply_attribute(classmeta, "strict", sv_2mortal(newSVpvs("params")));
  return TRUE;
}

static void struct_post_add_field(pTHX_ ClassMeta *classmeta, SV *attrdata, void *_funcdata, FieldMeta *fieldmeta)
{
  if(mop_field_get_sigil(fieldmeta) != '$')
    return;

  U32 flags = attrdata ? SvUV(attrdata) : 0;

  mop_field_apply_attribute(fieldmeta, "param", NULL);

  if(flags & FLAG_READONLY)
    mop_field_apply_attribute(fieldmeta, "reader", NULL);
  else
    mop_field_apply_attribute(fieldmeta, "mutator", NULL);
}

static void struct_post_seal(pTHX_ ClassMeta *classmeta, SV *attrdata, void *_funcdata)
{
  dSP;

  ENTER;
  SAVETMPS;

  EXTEND(SP, 1);
  PUSHMARK(SP);
  PUSHs(mop_class_get_name(classmeta));
  PUTBACK;

  call_pv("Object::Pad::ClassAttr::Struct::_post_seal", G_VOID);

  FREETMPS;
  LEAVE;
}

static const struct ClassHookFuncs struct_hooks = {
  .ver   = OBJECTPAD_ABIVERSION,
  .flags = 0,
  .permit_hintkey = "Object::Pad::ClassAttr::Struct/Struct",

  .apply          = &struct_apply,
  .post_add_field = &struct_post_add_field,
  .post_seal      = &struct_post_seal,
};

MODULE = Object::Pad::ClassAttr::Struct    PACKAGE = Object::Pad::ClassAttr::Struct

BOOT:
  register_class_attribute("Struct", &struct_hooks, NULL);