prometheus-client-mmap 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,303 +3,319 @@
3
3
  /**
4
4
  * Allocates a fresh unused token from the token pull.
5
5
  */
6
- static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
7
- jsmntok_t *tokens, size_t num_tokens) {
8
- jsmntok_t *tok;
9
- if (parser->toknext >= num_tokens) {
10
- return NULL;
11
- }
12
- tok = &tokens[parser->toknext++];
13
- tok->start = tok->end = -1;
14
- tok->size = 0;
6
+ static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, size_t num_tokens) {
7
+ jsmntok_t *tok;
8
+ if (parser->toknext >= num_tokens) {
9
+ return NULL;
10
+ }
11
+ tok = &tokens[parser->toknext++];
12
+ tok->start = tok->end = -1;
13
+ tok->size = 0;
15
14
  #ifdef JSMN_PARENT_LINKS
16
- tok->parent = -1;
15
+ tok->parent = -1;
17
16
  #endif
18
- return tok;
17
+ return tok;
19
18
  }
20
19
 
21
20
  /**
22
21
  * Fills token type and boundaries.
23
22
  */
24
- static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
25
- int start, int end) {
26
- token->type = type;
27
- token->start = start;
28
- token->end = end;
29
- token->size = 0;
23
+ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type, int start, int end) {
24
+ token->type = type;
25
+ token->start = start;
26
+ token->end = end;
27
+ token->size = 0;
30
28
  }
31
29
 
32
30
  /**
33
31
  * Fills next available token with JSON primitive.
34
32
  */
35
- static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
36
- size_t len, jsmntok_t *tokens, size_t num_tokens) {
37
- jsmntok_t *token;
38
- int start;
33
+ static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) {
34
+ jsmntok_t *token;
35
+ int start;
39
36
 
40
- start = parser->pos;
37
+ start = parser->pos;
41
38
 
42
- for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
43
- switch (js[parser->pos]) {
39
+ for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
40
+ switch (js[parser->pos]) {
44
41
  #ifndef JSMN_STRICT
45
- /* In strict mode primitive must be followed by "," or "}" or "]" */
46
- case ':':
42
+ /* In strict mode primitive must be followed by "," or "}" or "]" */
43
+ case ':':
47
44
  #endif
48
- case '\t' : case '\r' : case '\n' : case ' ' :
49
- case ',' : case ']' : case '}' :
50
- goto found;
51
- }
52
- if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
53
- parser->pos = start;
54
- return JSMN_ERROR_INVAL;
55
- }
56
- }
45
+ case '\t':
46
+ case '\r':
47
+ case '\n':
48
+ case ' ':
49
+ case ',':
50
+ case ']':
51
+ case '}':
52
+ goto found;
53
+ }
54
+ if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
55
+ parser->pos = start;
56
+ return JSMN_ERROR_INVAL;
57
+ }
58
+ }
57
59
  #ifdef JSMN_STRICT
58
- /* In strict mode primitive must be followed by a comma/object/array */
59
- parser->pos = start;
60
- return JSMN_ERROR_PART;
60
+ /* In strict mode primitive must be followed by a comma/object/array */
61
+ parser->pos = start;
62
+ return JSMN_ERROR_PART;
61
63
  #endif
62
64
 
63
65
  found:
64
- if (tokens == NULL) {
65
- parser->pos--;
66
- return 0;
67
- }
68
- token = jsmn_alloc_token(parser, tokens, num_tokens);
69
- if (token == NULL) {
70
- parser->pos = start;
71
- return JSMN_ERROR_NOMEM;
72
- }
73
- jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
66
+ if (tokens == NULL) {
67
+ parser->pos--;
68
+ return 0;
69
+ }
70
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
71
+ if (token == NULL) {
72
+ parser->pos = start;
73
+ return JSMN_ERROR_NOMEM;
74
+ }
75
+ jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
74
76
  #ifdef JSMN_PARENT_LINKS
75
- token->parent = parser->toksuper;
77
+ token->parent = parser->toksuper;
76
78
  #endif
77
- parser->pos--;
78
- return 0;
79
+ parser->pos--;
80
+ return 0;
79
81
  }
80
82
 
81
83
  /**
82
84
  * Fills next token with JSON string.
83
85
  */
84
- static int jsmn_parse_string(jsmn_parser *parser, const char *js,
85
- size_t len, jsmntok_t *tokens, size_t num_tokens) {
86
- jsmntok_t *token;
86
+ static int jsmn_parse_string(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, size_t num_tokens) {
87
+ jsmntok_t *token;
87
88
 
88
- int start = parser->pos;
89
+ int start = parser->pos;
89
90
 
90
- parser->pos++;
91
+ parser->pos++;
91
92
 
92
- /* Skip starting quote */
93
- for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
94
- char c = js[parser->pos];
93
+ /* Skip starting quote */
94
+ for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
95
+ char c = js[parser->pos];
95
96
 
96
- /* Quote: end of string */
97
- if (c == '\"') {
98
- if (tokens == NULL) {
99
- return 0;
100
- }
101
- token = jsmn_alloc_token(parser, tokens, num_tokens);
102
- if (token == NULL) {
103
- parser->pos = start;
104
- return JSMN_ERROR_NOMEM;
105
- }
106
- jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
97
+ /* Quote: end of string */
98
+ if (c == '\"') {
99
+ if (tokens == NULL) {
100
+ return 0;
101
+ }
102
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
103
+ if (token == NULL) {
104
+ parser->pos = start;
105
+ return JSMN_ERROR_NOMEM;
106
+ }
107
+ jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos);
107
108
  #ifdef JSMN_PARENT_LINKS
108
- token->parent = parser->toksuper;
109
+ token->parent = parser->toksuper;
109
110
  #endif
110
- return 0;
111
- }
111
+ return 0;
112
+ }
112
113
 
113
- /* Backslash: Quoted symbol expected */
114
- if (c == '\\' && parser->pos + 1 < len) {
115
- int i;
116
- parser->pos++;
117
- switch (js[parser->pos]) {
118
- /* Allowed escaped symbols */
119
- case '\"': case '/' : case '\\' : case 'b' :
120
- case 'f' : case 'r' : case 'n' : case 't' :
121
- break;
122
- /* Allows escaped symbol \uXXXX */
123
- case 'u':
124
- parser->pos++;
125
- for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
126
- /* If it isn't a hex character we have an error */
127
- if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
128
- (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
129
- (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
130
- parser->pos = start;
131
- return JSMN_ERROR_INVAL;
132
- }
133
- parser->pos++;
134
- }
135
- parser->pos--;
136
- break;
137
- /* Unexpected symbol */
138
- default:
139
- parser->pos = start;
140
- return JSMN_ERROR_INVAL;
141
- }
142
- }
143
- }
144
- parser->pos = start;
145
- return JSMN_ERROR_PART;
114
+ /* Backslash: Quoted symbol expected */
115
+ if (c == '\\' && parser->pos + 1 < len) {
116
+ int i;
117
+ parser->pos++;
118
+ switch (js[parser->pos]) {
119
+ /* Allowed escaped symbols */
120
+ case '\"':
121
+ case '/':
122
+ case '\\':
123
+ case 'b':
124
+ case 'f':
125
+ case 'r':
126
+ case 'n':
127
+ case 't':
128
+ break;
129
+ /* Allows escaped symbol \uXXXX */
130
+ case 'u':
131
+ parser->pos++;
132
+ for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
133
+ /* If it isn't a hex character we have an error */
134
+ if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
135
+ (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
136
+ (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
137
+ parser->pos = start;
138
+ return JSMN_ERROR_INVAL;
139
+ }
140
+ parser->pos++;
141
+ }
142
+ parser->pos--;
143
+ break;
144
+ /* Unexpected symbol */
145
+ default:
146
+ parser->pos = start;
147
+ return JSMN_ERROR_INVAL;
148
+ }
149
+ }
150
+ }
151
+ parser->pos = start;
152
+ return JSMN_ERROR_PART;
146
153
  }
147
154
 
148
155
  /**
149
156
  * Parse JSON string and fill tokens.
150
157
  */
151
- int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
152
- jsmntok_t *tokens, unsigned int num_tokens) {
153
- int r;
154
- int i;
155
- jsmntok_t *token;
156
- int count = parser->toknext;
158
+ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens) {
159
+ int r;
160
+ int i;
161
+ jsmntok_t *token;
162
+ int count = parser->toknext;
157
163
 
158
- for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
159
- char c;
160
- jsmntype_t type;
164
+ for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
165
+ char c;
166
+ jsmntype_t type;
161
167
 
162
- c = js[parser->pos];
163
- switch (c) {
164
- case '{': case '[':
165
- count++;
166
- if (tokens == NULL) {
167
- break;
168
- }
169
- token = jsmn_alloc_token(parser, tokens, num_tokens);
170
- if (token == NULL)
171
- return JSMN_ERROR_NOMEM;
172
- if (parser->toksuper != -1) {
173
- tokens[parser->toksuper].size++;
168
+ c = js[parser->pos];
169
+ switch (c) {
170
+ case '{':
171
+ case '[':
172
+ count++;
173
+ if (tokens == NULL) {
174
+ break;
175
+ }
176
+ token = jsmn_alloc_token(parser, tokens, num_tokens);
177
+ if (token == NULL) return JSMN_ERROR_NOMEM;
178
+ if (parser->toksuper != -1) {
179
+ tokens[parser->toksuper].size++;
174
180
  #ifdef JSMN_PARENT_LINKS
175
- token->parent = parser->toksuper;
181
+ token->parent = parser->toksuper;
176
182
  #endif
177
- }
178
- token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
179
- token->start = parser->pos;
180
- parser->toksuper = parser->toknext - 1;
181
- break;
182
- case '}': case ']':
183
- if (tokens == NULL)
184
- break;
185
- type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
183
+ }
184
+ token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
185
+ token->start = parser->pos;
186
+ parser->toksuper = parser->toknext - 1;
187
+ break;
188
+ case '}':
189
+ case ']':
190
+ if (tokens == NULL) break;
191
+ type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
186
192
  #ifdef JSMN_PARENT_LINKS
187
- if (parser->toknext < 1) {
188
- return JSMN_ERROR_INVAL;
189
- }
190
- token = &tokens[parser->toknext - 1];
191
- for (;;) {
192
- if (token->start != -1 && token->end == -1) {
193
- if (token->type != type) {
194
- return JSMN_ERROR_INVAL;
195
- }
196
- token->end = parser->pos + 1;
197
- parser->toksuper = token->parent;
198
- break;
199
- }
200
- if (token->parent == -1) {
201
- if(token->type != type || parser->toksuper == -1) {
202
- return JSMN_ERROR_INVAL;
203
- }
204
- break;
205
- }
206
- token = &tokens[token->parent];
207
- }
193
+ if (parser->toknext < 1) {
194
+ return JSMN_ERROR_INVAL;
195
+ }
196
+ token = &tokens[parser->toknext - 1];
197
+ for (;;) {
198
+ if (token->start != -1 && token->end == -1) {
199
+ if (token->type != type) {
200
+ return JSMN_ERROR_INVAL;
201
+ }
202
+ token->end = parser->pos + 1;
203
+ parser->toksuper = token->parent;
204
+ break;
205
+ }
206
+ if (token->parent == -1) {
207
+ if (token->type != type || parser->toksuper == -1) {
208
+ return JSMN_ERROR_INVAL;
209
+ }
210
+ break;
211
+ }
212
+ token = &tokens[token->parent];
213
+ }
208
214
  #else
209
- for (i = parser->toknext - 1; i >= 0; i--) {
210
- token = &tokens[i];
211
- if (token->start != -1 && token->end == -1) {
212
- if (token->type != type) {
213
- return JSMN_ERROR_INVAL;
214
- }
215
- parser->toksuper = -1;
216
- token->end = parser->pos + 1;
217
- break;
218
- }
219
- }
220
- /* Error if unmatched closing bracket */
221
- if (i == -1) return JSMN_ERROR_INVAL;
222
- for (; i >= 0; i--) {
223
- token = &tokens[i];
224
- if (token->start != -1 && token->end == -1) {
225
- parser->toksuper = i;
226
- break;
227
- }
228
- }
215
+ for (i = parser->toknext - 1; i >= 0; i--) {
216
+ token = &tokens[i];
217
+ if (token->start != -1 && token->end == -1) {
218
+ if (token->type != type) {
219
+ return JSMN_ERROR_INVAL;
220
+ }
221
+ parser->toksuper = -1;
222
+ token->end = parser->pos + 1;
223
+ break;
224
+ }
225
+ }
226
+ /* Error if unmatched closing bracket */
227
+ if (i == -1) return JSMN_ERROR_INVAL;
228
+ for (; i >= 0; i--) {
229
+ token = &tokens[i];
230
+ if (token->start != -1 && token->end == -1) {
231
+ parser->toksuper = i;
232
+ break;
233
+ }
234
+ }
229
235
  #endif
230
- break;
231
- case '\"':
232
- r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
233
- if (r < 0) return r;
234
- count++;
235
- if (parser->toksuper != -1 && tokens != NULL)
236
- tokens[parser->toksuper].size++;
237
- break;
238
- case '\t' : case '\r' : case '\n' : case ' ':
239
- break;
240
- case ':':
241
- parser->toksuper = parser->toknext - 1;
242
- break;
243
- case ',':
244
- if (tokens != NULL && parser->toksuper != -1 &&
245
- tokens[parser->toksuper].type != JSMN_ARRAY &&
246
- tokens[parser->toksuper].type != JSMN_OBJECT) {
236
+ break;
237
+ case '\"':
238
+ r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
239
+ if (r < 0) return r;
240
+ count++;
241
+ if (parser->toksuper != -1 && tokens != NULL) tokens[parser->toksuper].size++;
242
+ break;
243
+ case '\t':
244
+ case '\r':
245
+ case '\n':
246
+ case ' ':
247
+ break;
248
+ case ':':
249
+ parser->toksuper = parser->toknext - 1;
250
+ break;
251
+ case ',':
252
+ if (tokens != NULL && parser->toksuper != -1 && tokens[parser->toksuper].type != JSMN_ARRAY &&
253
+ tokens[parser->toksuper].type != JSMN_OBJECT) {
247
254
  #ifdef JSMN_PARENT_LINKS
248
- parser->toksuper = tokens[parser->toksuper].parent;
255
+ parser->toksuper = tokens[parser->toksuper].parent;
249
256
  #else
250
- for (i = parser->toknext - 1; i >= 0; i--) {
251
- if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
252
- if (tokens[i].start != -1 && tokens[i].end == -1) {
253
- parser->toksuper = i;
254
- break;
255
- }
256
- }
257
- }
257
+ for (i = parser->toknext - 1; i >= 0; i--) {
258
+ if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
259
+ if (tokens[i].start != -1 && tokens[i].end == -1) {
260
+ parser->toksuper = i;
261
+ break;
262
+ }
263
+ }
264
+ }
258
265
  #endif
259
- }
260
- break;
266
+ }
267
+ break;
261
268
  #ifdef JSMN_STRICT
262
- /* In strict mode primitives are: numbers and booleans */
263
- case '-': case '0': case '1' : case '2': case '3' : case '4':
264
- case '5': case '6': case '7' : case '8': case '9':
265
- case 't': case 'f': case 'n' :
266
- /* And they must not be keys of the object */
267
- if (tokens != NULL && parser->toksuper != -1) {
268
- jsmntok_t *t = &tokens[parser->toksuper];
269
- if (t->type == JSMN_OBJECT ||
270
- (t->type == JSMN_STRING && t->size != 0)) {
271
- return JSMN_ERROR_INVAL;
272
- }
273
- }
269
+ /* In strict mode primitives are: numbers and booleans */
270
+ case '-':
271
+ case '0':
272
+ case '1':
273
+ case '2':
274
+ case '3':
275
+ case '4':
276
+ case '5':
277
+ case '6':
278
+ case '7':
279
+ case '8':
280
+ case '9':
281
+ case 't':
282
+ case 'f':
283
+ case 'n':
284
+ /* And they must not be keys of the object */
285
+ if (tokens != NULL && parser->toksuper != -1) {
286
+ jsmntok_t *t = &tokens[parser->toksuper];
287
+ if (t->type == JSMN_OBJECT || (t->type == JSMN_STRING && t->size != 0)) {
288
+ return JSMN_ERROR_INVAL;
289
+ }
290
+ }
274
291
  #else
275
- /* In non-strict mode every unquoted value is a primitive */
276
- default:
292
+ /* In non-strict mode every unquoted value is a primitive */
293
+ default:
277
294
  #endif
278
- r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
279
- if (r < 0) return r;
280
- count++;
281
- if (parser->toksuper != -1 && tokens != NULL)
282
- tokens[parser->toksuper].size++;
283
- break;
295
+ r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
296
+ if (r < 0) return r;
297
+ count++;
298
+ if (parser->toksuper != -1 && tokens != NULL) tokens[parser->toksuper].size++;
299
+ break;
284
300
 
285
301
  #ifdef JSMN_STRICT
286
- /* Unexpected char in strict mode */
287
- default:
288
- return JSMN_ERROR_INVAL;
302
+ /* Unexpected char in strict mode */
303
+ default:
304
+ return JSMN_ERROR_INVAL;
289
305
  #endif
290
- }
291
- }
306
+ }
307
+ }
292
308
 
293
- if (tokens != NULL) {
294
- for (i = parser->toknext - 1; i >= 0; i--) {
295
- /* Unmatched opened object or array */
296
- if (tokens[i].start != -1 && tokens[i].end == -1) {
297
- return JSMN_ERROR_PART;
298
- }
299
- }
300
- }
309
+ if (tokens != NULL) {
310
+ for (i = parser->toknext - 1; i >= 0; i--) {
311
+ /* Unmatched opened object or array */
312
+ if (tokens[i].start != -1 && tokens[i].end == -1) {
313
+ return JSMN_ERROR_PART;
314
+ }
315
+ }
316
+ }
301
317
 
302
- return count;
318
+ return count;
303
319
  }
304
320
 
305
321
  /**
@@ -307,8 +323,7 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
307
323
  * available.
308
324
  */
309
325
  void jsmn_init(jsmn_parser *parser) {
310
- parser->pos = 0;
311
- parser->toknext = 0;
312
- parser->toksuper = -1;
326
+ parser->pos = 0;
327
+ parser->toknext = 0;
328
+ parser->toksuper = -1;
313
329
  }
314
-
@@ -353,5 +353,8 @@ VALUE mm_unmap(VALUE obj) {
353
353
  }
354
354
  i_mm->t->path = NULL;
355
355
  }
356
+
357
+ close(i_mm->t->fd);
358
+
356
359
  return Qnil;
357
360
  }
Binary file
@@ -25,7 +25,10 @@ module Prometheus
25
25
  @file_locks ||= {}
26
26
  return false unless @file_locks[filepath]
27
27
 
28
- @file_locks.delete(filepath).flock(File::LOCK_UN)
28
+ file = @file_locks[filepath]
29
+ file.flock(File::LOCK_UN)
30
+ file.close
31
+ @file_locks.delete(filepath)
29
32
  end
30
33
  end
31
34
 
@@ -34,6 +37,7 @@ module Prometheus
34
37
  @file_locks ||= {}
35
38
  @file_locks.values.each do |file|
36
39
  file.flock(File::LOCK_UN)
40
+ file.close
37
41
  end
38
42
 
39
43
  @file_locks = {}
@@ -23,6 +23,7 @@ module Prometheus
23
23
 
24
24
  def close
25
25
  munmap
26
+ FileLocker.unlock(filepath)
26
27
  end
27
28
 
28
29
  private
@@ -1,5 +1,5 @@
1
1
  module Prometheus
2
2
  module Client
3
- VERSION = '0.15.0'.freeze
3
+ VERSION = '0.16.0'.freeze
4
4
  end
5
5
  end
@@ -37,6 +37,10 @@ module Prometheus
37
37
  ::Prometheus::Client::MmapedValue.reset_and_reinitialize
38
38
  end
39
39
 
40
+ def cleanup!
41
+ Dir.glob("#{configuration.multiprocess_files_dir}/*.db").each { |f| File.unlink(f) if File.exist?(f) }
42
+ end
43
+
40
44
  # With `force: false`: reinitializes metric files only for processes with the changed PID.
41
45
  # With `force: true`: reinitializes all metrics files.
42
46
  # Always keeps the registry.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prometheus-client-mmap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.0
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tobias Schmidt
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-08-31 00:00:00.000000000 Z
12
+ date: 2022-03-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fuzzbert
@@ -181,7 +181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
181
181
  - !ruby/object:Gem::Version
182
182
  version: '0'
183
183
  requirements: []
184
- rubygems_version: 3.1.4
184
+ rubygems_version: 3.1.6
185
185
  signing_key:
186
186
  specification_version: 4
187
187
  summary: A suite of instrumentation metric primitivesthat can be exposed through a