initial cut of direct marshalling code
[lwes-ruby.git] / ext / lwes / numeric.c
blob7f77484b32585b098f068425790181a655b0e7c2
1 #include "lwes_ruby.h"
2 #include <arpa/inet.h>
4 static ID
5 sym_int16, sym_uint16,
6 sym_int32, sym_uint32,
7 sym_int64, sym_uint64,
8 sym_ip_addr;
10 void lwesrb_dump_type(LWES_BYTE type, LWES_BYTE_P buf, size_t *off)
12 if (marshall_BYTE(type, buf, MAX_MSG_SIZE, off) > 0)
13 return;
14 rb_raise(rb_eRuntimeError, "failed to dump type=%02x", (unsigned)type);
17 static int dump_uint16(VALUE val, LWES_BYTE_P buf, size_t *off)
19 int32_t tmp = NUM2INT(val);
21 if (tmp < 0)
22 rb_raise(rb_eRangeError, ":uint16 negative: %d", tmp);
23 if (tmp > UINT16_MAX)
24 rb_raise(rb_eRangeError, ":uint16 too large: %d", tmp);
26 lwesrb_dump_type(LWES_U_INT_16_TOKEN, buf, off);
27 return marshall_U_INT_16((LWES_U_INT_16)tmp, buf, MAX_MSG_SIZE, off);
30 static int dump_int16(VALUE val, LWES_BYTE_P buf, size_t *off)
32 int32_t tmp = NUM2INT(val);
34 if (tmp > INT16_MAX)
35 rb_raise(rb_eRangeError, ":int16 too large: %i", tmp);
36 if (tmp < INT16_MIN)
37 rb_raise(rb_eRangeError, ":int16 too small: %i", tmp);
39 lwesrb_dump_type(LWES_INT_16_TOKEN, buf, off);
40 return marshall_INT_16((LWES_INT_16)tmp, buf, MAX_MSG_SIZE, off);
43 static int dump_uint32(VALUE val, LWES_BYTE_P buf, size_t *off)
45 LONG_LONG tmp = NUM2LL(val);
47 if (tmp < 0)
48 rb_raise(rb_eRangeError, ":uint32 negative: %lli", tmp);
49 if (tmp > UINT32_MAX)
50 rb_raise(rb_eRangeError, ":uint32 too large: %lli", tmp);
52 lwesrb_dump_type(LWES_U_INT_32_TOKEN, buf, off);
53 return marshall_U_INT_32((LWES_U_INT_32)tmp, buf, MAX_MSG_SIZE, off);
56 static int dump_int32(VALUE val, LWES_BYTE_P buf, size_t *off)
58 LONG_LONG tmp = NUM2LL(val);
60 if (tmp > INT32_MAX)
61 rb_raise(rb_eRangeError, ":int32 too large: %lli", tmp);
62 if (tmp < INT32_MIN)
63 rb_raise(rb_eRangeError, ":int32 too small: %lli", tmp);
65 lwesrb_dump_type(LWES_INT_32_TOKEN, buf, off);
66 return marshall_INT_32((LWES_INT_32)tmp, buf, MAX_MSG_SIZE, off);
69 static int dump_uint64(VALUE val, LWES_BYTE_P buf, size_t *off)
71 unsigned LONG_LONG tmp = NUM2ULL(val); /* can raise RangeError */
72 ID type = TYPE(val);
74 if ((type == T_FIXNUM && FIX2LONG(val) < 0) ||
75 (type == T_BIGNUM && RTEST(rb_funcall(val, '<', 1, INT2FIX(0)))))
76 rb_raise(rb_eRangeError, ":uint64 negative: %s",
77 RSTRING_PTR(rb_inspect(val)));
79 lwesrb_dump_type(LWES_U_INT_64_TOKEN, buf, off);
80 return marshall_U_INT_64((LWES_U_INT_64)tmp, buf, MAX_MSG_SIZE, off);
83 static int dump_int64(VALUE val, LWES_BYTE_P buf, size_t *off)
85 LONG_LONG tmp = NUM2LL(val); /* can raise RangeError */
87 lwesrb_dump_type(LWES_INT_64_TOKEN, buf, off);
88 return marshall_INT_64((LWES_INT_64)tmp, buf, MAX_MSG_SIZE, off);
91 static int dump_ip_addr(VALUE val, LWES_BYTE_P buf, size_t *off)
93 LWES_IP_ADDR addr;
95 switch (TYPE(val)) {
96 case T_STRING:
97 addr.s_addr = inet_addr(RSTRING_PTR(val));
98 break;
99 case T_FIXNUM:
100 case T_BIGNUM:
101 addr.s_addr = htonl(NUM2UINT(val));
102 break;
103 default:
104 rb_raise(rb_eTypeError,
105 ":ip_addr address must be String or Integer: %s",
106 RSTRING_PTR(rb_inspect(val)));
108 lwesrb_dump_type(LWES_IP_ADDR_TOKEN, buf, off);
109 return marshall_IP_ADDR(addr, buf, MAX_MSG_SIZE, off);
112 /* simple type => function dispatch map */
113 static struct _type_fn_map {
114 ID type;
115 int (*fn)(VALUE, LWES_BYTE_P, size_t *);
116 } type_fn_map[] = {
117 #define SYMFN(T) { (ID)&sym_##T, dump_##T }
118 SYMFN(uint16),
119 SYMFN(int16),
120 SYMFN(uint32),
121 SYMFN(int32),
122 SYMFN(uint64),
123 SYMFN(int64),
124 SYMFN(ip_addr),
125 #undef SYMFN
128 /* used for Struct serialization where types are known ahead of time */
129 static int dump_num(
130 LWES_TYPE type,
131 VALUE val,
132 LWES_BYTE_P buf,
133 size_t *off)
135 switch (type) {
136 case LWES_TYPE_U_INT_16: return dump_uint16(val, buf, off);
137 case LWES_TYPE_INT_16: return dump_int16(val, buf, off);
138 case LWES_TYPE_U_INT_32: return dump_uint32(val, buf, off);
139 case LWES_TYPE_INT_32: return dump_int32(val, buf, off);
140 case LWES_TYPE_U_INT_64: return dump_uint64(val, buf, off);
141 case LWES_TYPE_INT_64: return dump_int64(val, buf, off);
142 case LWES_TYPE_IP_ADDR: return dump_ip_addr(val, buf, off);
143 default:
144 rb_raise(rb_eRuntimeError,
145 "unknown LWES attribute type: 0x%02x", type);
147 assert("you should never get here (dump_num)");
148 return -1;
151 void lwesrb_dump_num(LWES_BYTE type, VALUE val, LWES_BYTE_P buf, size_t *off)
153 if (dump_num(type, val, buf, off) > 0)
154 return;
155 rb_raise(rb_eRuntimeError,
156 "dumping numeric type 0x%02x, type failed", type);
160 * used for Hash serialization
161 * array contains two elements:
162 * [ symbolic_type, number ]
163 * returns the return value of the underlying lwes_event_set_* call
165 void lwesrb_dump_num_ary(VALUE array, LWES_BYTE_P buf, size_t *off)
167 int i, rv;
168 struct _type_fn_map *head;
169 VALUE *ary;
170 ID type;
172 assert(TYPE(array) == T_ARRAY && "need array here");
174 if (RARRAY_LEN(array) != 2)
175 rb_raise(rb_eArgError, "expected a two element array");
177 ary = RARRAY_PTR(array);
178 type = ary[0];
180 i = sizeof(type_fn_map) / sizeof(type_fn_map[0]);
181 for (head = type_fn_map; --i >= 0; head++) {
182 if (head->type != type)
183 continue;
185 rv = head->fn(ary[1], buf, off);
186 if (rv > 0)
187 return;
188 rb_raise(rb_eRuntimeError,
189 "dumping numeric type %s, type failed",
190 RSTRING_PTR(rb_obj_as_string(type)));
193 rb_raise(rb_eArgError,
194 "unknown type: %s", RSTRING_PTR(rb_inspect(type)));
197 void lwesrb_init_numeric(void)
199 int i;
201 LWESRB_MKSYM(int16);
202 LWESRB_MKSYM(uint16);
203 LWESRB_MKSYM(int32);
204 LWESRB_MKSYM(uint32);
205 LWESRB_MKSYM(int64);
206 LWESRB_MKSYM(uint64);
207 LWESRB_MKSYM(ip_addr);
210 * we needed to have constants for compilation, so we set the
211 * address of the IDs and then dereference + reassign them
212 * at initialization time:
214 i = sizeof(type_fn_map) / sizeof(type_fn_map[0]);
215 while (--i >= 0)
216 type_fn_map[i].type = *(ID *)type_fn_map[i].type;