1/*
2 * This file is part of the MicroPython project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013, 2014 Damien P. George
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
27#include <stdint.h>
28#include <stdio.h>
29#include <stdarg.h>
30#include <assert.h>
31
32#include "py/obj.h"
33#include "py/objtype.h"
34#include "py/objint.h"
35#include "py/objstr.h"
36#include "py/runtime.h"
37#include "py/stackctrl.h"
38#include "py/stream.h" // for mp_obj_print
39
40const mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in) {
41 #if MICROPY_OBJ_IMMEDIATE_OBJS && MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A
42
43 if (mp_obj_is_obj(o_in)) {
44 const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in);
45 return o->type;
46 } else {
47 static const mp_obj_type_t *const types[] = {
48 NULL, &mp_type_int, &mp_type_str, &mp_type_int,
49 NULL, &mp_type_int, &mp_type_NoneType, &mp_type_int,
50 NULL, &mp_type_int, &mp_type_str, &mp_type_int,
51 NULL, &mp_type_int, &mp_type_bool, &mp_type_int,
52 };
53 return types[(uintptr_t)o_in & 0xf];
54 }
55
56 #elif MICROPY_OBJ_IMMEDIATE_OBJS && MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
57
58 if (mp_obj_is_small_int(o_in)) {
59 return &mp_type_int;
60 } else if (mp_obj_is_obj(o_in)) {
61 const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in);
62 return o->type;
63 #if MICROPY_PY_BUILTINS_FLOAT
64 } else if ((((mp_uint_t)(o_in)) & 0xff800007) != 0x00000006) {
65 return &mp_type_float;
66 #endif
67 } else {
68 static const mp_obj_type_t *const types[] = {
69 &mp_type_str, &mp_type_NoneType, &mp_type_str, &mp_type_bool,
70 };
71 return types[((uintptr_t)o_in >> 3) & 3];
72 }
73
74 #else
75
76 if (mp_obj_is_small_int(o_in)) {
77 return &mp_type_int;
78 } else if (mp_obj_is_qstr(o_in)) {
79 return &mp_type_str;
80 #if MICROPY_PY_BUILTINS_FLOAT && ( \
81 MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D)
82 } else if (mp_obj_is_float(o_in)) {
83 return &mp_type_float;
84 #endif
85 #if MICROPY_OBJ_IMMEDIATE_OBJS
86 } else if (mp_obj_is_immediate_obj(o_in)) {
87 static const mp_obj_type_t *const types[2] = {&mp_type_NoneType, &mp_type_bool};
88 return types[MP_OBJ_IMMEDIATE_OBJ_VALUE(o_in) & 1];
89 #endif
90 } else {
91 const mp_obj_base_t *o = MP_OBJ_TO_PTR(o_in);
92 return o->type;
93 }
94
95 #endif
96}
97
98const char *mp_obj_get_type_str(mp_const_obj_t o_in) {
99 return qstr_str(mp_obj_get_type(o_in)->name);
100}
101
102void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
103 // There can be data structures nested too deep, or just recursive
104 MP_STACK_CHECK();
105 #ifndef NDEBUG
106 if (o_in == MP_OBJ_NULL) {
107 mp_print_str(print, "(nil)");
108 return;
109 }
110 #endif
111 const mp_obj_type_t *type = mp_obj_get_type(o_in);
112 if (type->print != NULL) {
113 type->print((mp_print_t *)print, o_in, kind);
114 } else {
115 mp_printf(print, "<%q>", type->name);
116 }
117}
118
119void mp_obj_print(mp_obj_t o_in, mp_print_kind_t kind) {
120 mp_obj_print_helper(MP_PYTHON_PRINTER, o_in, kind);
121}
122
123// helper function to print an exception with traceback
124void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc) {
125 if (mp_obj_is_exception_instance(exc)) {
126 size_t n, *values;
127 mp_obj_exception_get_traceback(exc, &n, &values);
128 if (n > 0) {
129 assert(n % 3 == 0);
130 mp_print_str(print, "Traceback (most recent call last):\n");
131 for (int i = n - 3; i >= 0; i -= 3) {
132 #if MICROPY_ENABLE_SOURCE_LINE
133 mp_printf(print, " File \"%q\", line %d", values[i], (int)values[i + 1]);
134 #else
135 mp_printf(print, " File \"%q\"", values[i]);
136 #endif
137 // the block name can be NULL if it's unknown
138 qstr block = values[i + 2];
139 if (block == MP_QSTRnull) {
140 mp_print_str(print, "\n");
141 } else {
142 mp_printf(print, ", in %q\n", block);
143 }
144 }
145 }
146 }
147 mp_obj_print_helper(print, exc, PRINT_EXC);
148 mp_print_str(print, "\n");
149}
150
151bool mp_obj_is_true(mp_obj_t arg) {
152 if (arg == mp_const_false) {
153 return 0;
154 } else if (arg == mp_const_true) {
155 return 1;
156 } else if (arg == mp_const_none) {
157 return 0;
158 } else if (mp_obj_is_small_int(arg)) {
159 if (arg == MP_OBJ_NEW_SMALL_INT(0)) {
160 return 0;
161 } else {
162 return 1;
163 }
164 } else {
165 const mp_obj_type_t *type = mp_obj_get_type(arg);
166 if (type->unary_op != NULL) {
167 mp_obj_t result = type->unary_op(MP_UNARY_OP_BOOL, arg);
168 if (result != MP_OBJ_NULL) {
169 return result == mp_const_true;
170 }
171 }
172
173 mp_obj_t len = mp_obj_len_maybe(arg);
174 if (len != MP_OBJ_NULL) {
175 // obj has a length, truth determined if len != 0
176 return len != MP_OBJ_NEW_SMALL_INT(0);
177 } else {
178 // any other obj is true per Python semantics
179 return 1;
180 }
181 }
182}
183
184bool mp_obj_is_callable(mp_obj_t o_in) {
185 const mp_call_fun_t call = mp_obj_get_type(o_in)->call;
186 if (call != mp_obj_instance_call) {
187 return call != NULL;
188 }
189 return mp_obj_instance_is_callable(o_in);
190}
191
192// This function implements the '==' and '!=' operators.
193//
194// From the Python language reference:
195// (https://docs.python.org/3/reference/expressions.html#not-in)
196// "The objects need not have the same type. If both are numbers, they are converted
197// to a common type. Otherwise, the == and != operators always consider objects of
198// different types to be unequal."
199//
200// This means that False==0 and True==1 are true expressions.
201//
202// Furthermore, from the v3.4.2 code for object.c: "Practical amendments: If rich
203// comparison returns NotImplemented, == and != are decided by comparing the object
204// pointer."
205mp_obj_t mp_obj_equal_not_equal(mp_binary_op_t op, mp_obj_t o1, mp_obj_t o2) {
206 mp_obj_t local_true = (op == MP_BINARY_OP_NOT_EQUAL) ? mp_const_false : mp_const_true;
207 mp_obj_t local_false = (op == MP_BINARY_OP_NOT_EQUAL) ? mp_const_true : mp_const_false;
208 int pass_number = 0;
209
210 // Shortcut for very common cases
211 if (o1 == o2 &&
212 (mp_obj_is_small_int(o1) || !(mp_obj_get_type(o1)->flags & MP_TYPE_FLAG_EQ_NOT_REFLEXIVE))) {
213 return local_true;
214 }
215
216 // fast path for strings
217 if (mp_obj_is_str(o1)) {
218 if (mp_obj_is_str(o2)) {
219 // both strings, use special function
220 return mp_obj_str_equal(o1, o2) ? local_true : local_false;
221 #if MICROPY_PY_STR_BYTES_CMP_WARN
222 } else if (mp_obj_is_type(o2, &mp_type_bytes)) {
223 str_bytes_cmp:
224 mp_warning(MP_WARN_CAT(BytesWarning), "Comparison between bytes and str");
225 return local_false;
226 #endif
227 } else {
228 goto skip_one_pass;
229 }
230 #if MICROPY_PY_STR_BYTES_CMP_WARN
231 } else if (mp_obj_is_str(o2) && mp_obj_is_type(o1, &mp_type_bytes)) {
232 // o1 is not a string (else caught above), so the objects are not equal
233 goto str_bytes_cmp;
234 #endif
235 }
236
237 // fast path for small ints
238 if (mp_obj_is_small_int(o1)) {
239 if (mp_obj_is_small_int(o2)) {
240 // both SMALL_INT, and not equal if we get here
241 return local_false;
242 } else {
243 goto skip_one_pass;
244 }
245 }
246
247 // generic type, call binary_op(MP_BINARY_OP_EQUAL)
248 while (pass_number < 2) {
249 const mp_obj_type_t *type = mp_obj_get_type(o1);
250 // If a full equality test is not needed and the other object is a different
251 // type then we don't need to bother trying the comparison.
252 if (type->binary_op != NULL &&
253 ((type->flags & MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE) || mp_obj_get_type(o2) == type)) {
254 // CPython is asymmetric: it will try __eq__ if there's no __ne__ but not the
255 // other way around. If the class doesn't need a full test we can skip __ne__.
256 if (op == MP_BINARY_OP_NOT_EQUAL && (type->flags & MP_TYPE_FLAG_EQ_HAS_NEQ_TEST)) {
257 mp_obj_t r = type->binary_op(MP_BINARY_OP_NOT_EQUAL, o1, o2);
258 if (r != MP_OBJ_NULL) {
259 return r;
260 }
261 }
262
263 // Try calling __eq__.
264 mp_obj_t r = type->binary_op(MP_BINARY_OP_EQUAL, o1, o2);
265 if (r != MP_OBJ_NULL) {
266 if (op == MP_BINARY_OP_EQUAL) {
267 return r;
268 } else {
269 return mp_obj_is_true(r) ? local_true : local_false;
270 }
271 }
272 }
273
274 skip_one_pass:
275 // Try the other way around if none of the above worked
276 ++pass_number;
277 mp_obj_t temp = o1;
278 o1 = o2;
279 o2 = temp;
280 }
281
282 // equality not implemented, so fall back to pointer conparison
283 return (o1 == o2) ? local_true : local_false;
284}
285
286bool mp_obj_equal(mp_obj_t o1, mp_obj_t o2) {
287 return mp_obj_is_true(mp_obj_equal_not_equal(MP_BINARY_OP_EQUAL, o1, o2));
288}
289
290mp_int_t mp_obj_get_int(mp_const_obj_t arg) {
291 // This function essentially performs implicit type conversion to int
292 // Note that Python does NOT provide implicit type conversion from
293 // float to int in the core expression language, try some_list[1.0].
294 if (arg == mp_const_false) {
295 return 0;
296 } else if (arg == mp_const_true) {
297 return 1;
298 } else if (mp_obj_is_small_int(arg)) {
299 return MP_OBJ_SMALL_INT_VALUE(arg);
300 } else if (mp_obj_is_type(arg, &mp_type_int)) {
301 return mp_obj_int_get_checked(arg);
302 } else {
303 mp_obj_t res = mp_unary_op(MP_UNARY_OP_INT, (mp_obj_t)arg);
304 return mp_obj_int_get_checked(res);
305 }
306}
307
308mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg) {
309 if (mp_obj_is_int(arg)) {
310 return mp_obj_int_get_truncated(arg);
311 } else {
312 return mp_obj_get_int(arg);
313 }
314}
315
316// returns false if arg is not of integral type
317// returns true and sets *value if it is of integral type
318// can throw OverflowError if arg is of integral type, but doesn't fit in a mp_int_t
319bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value) {
320 if (arg == mp_const_false) {
321 *value = 0;
322 } else if (arg == mp_const_true) {
323 *value = 1;
324 } else if (mp_obj_is_small_int(arg)) {
325 *value = MP_OBJ_SMALL_INT_VALUE(arg);
326 } else if (mp_obj_is_type(arg, &mp_type_int)) {
327 *value = mp_obj_int_get_checked(arg);
328 } else {
329 return false;
330 }
331 return true;
332}
333
334#if MICROPY_PY_BUILTINS_FLOAT
335bool mp_obj_get_float_maybe(mp_obj_t arg, mp_float_t *value) {
336 mp_float_t val;
337
338 if (arg == mp_const_false) {
339 val = 0;
340 } else if (arg == mp_const_true) {
341 val = 1;
342 } else if (mp_obj_is_small_int(arg)) {
343 val = (mp_float_t)MP_OBJ_SMALL_INT_VALUE(arg);
344 #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
345 } else if (mp_obj_is_type(arg, &mp_type_int)) {
346 val = mp_obj_int_as_float_impl(arg);
347 #endif
348 } else if (mp_obj_is_float(arg)) {
349 val = mp_obj_float_get(arg);
350 } else {
351 return false;
352 }
353
354 *value = val;
355 return true;
356}
357
358mp_float_t mp_obj_get_float(mp_obj_t arg) {
359 mp_float_t val;
360
361 if (!mp_obj_get_float_maybe(arg, &val)) {
362 #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
363 mp_raise_TypeError(MP_ERROR_TEXT("can't convert to float"));
364 #else
365 mp_raise_msg_varg(&mp_type_TypeError,
366 MP_ERROR_TEXT("can't convert %s to float"), mp_obj_get_type_str(arg));
367 #endif
368 }
369
370 return val;
371}
372
373#if MICROPY_PY_BUILTINS_COMPLEX
374bool mp_obj_get_complex_maybe(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
375 if (arg == mp_const_false) {
376 *real = 0;
377 *imag = 0;
378 } else if (arg == mp_const_true) {
379 *real = 1;
380 *imag = 0;
381 } else if (mp_obj_is_small_int(arg)) {
382 *real = (mp_float_t)MP_OBJ_SMALL_INT_VALUE(arg);
383 *imag = 0;
384 #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
385 } else if (mp_obj_is_type(arg, &mp_type_int)) {
386 *real = mp_obj_int_as_float_impl(arg);
387 *imag = 0;
388 #endif
389 } else if (mp_obj_is_float(arg)) {
390 *real = mp_obj_float_get(arg);
391 *imag = 0;
392 } else if (mp_obj_is_type(arg, &mp_type_complex)) {
393 mp_obj_complex_get(arg, real, imag);
394 } else {
395 return false;
396 }
397 return true;
398}
399
400void mp_obj_get_complex(mp_obj_t arg, mp_float_t *real, mp_float_t *imag) {
401 if (!mp_obj_get_complex_maybe(arg, real, imag)) {
402 #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
403 mp_raise_TypeError(MP_ERROR_TEXT("can't convert to complex"));
404 #else
405 mp_raise_msg_varg(&mp_type_TypeError,
406 MP_ERROR_TEXT("can't convert %s to complex"), mp_obj_get_type_str(arg));
407 #endif
408 }
409}
410#endif
411#endif
412
413// note: returned value in *items may point to the interior of a GC block
414void mp_obj_get_array(mp_obj_t o, size_t *len, mp_obj_t **items) {
415 if (mp_obj_is_type(o, &mp_type_tuple)) {
416 mp_obj_tuple_get(o, len, items);
417 } else if (mp_obj_is_type(o, &mp_type_list)) {
418 mp_obj_list_get(o, len, items);
419 } else {
420 #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
421 mp_raise_TypeError(MP_ERROR_TEXT("expected tuple/list"));
422 #else
423 mp_raise_msg_varg(&mp_type_TypeError,
424 MP_ERROR_TEXT("object '%s' isn't a tuple or list"), mp_obj_get_type_str(o));
425 #endif
426 }
427}
428
429// note: returned value in *items may point to the interior of a GC block
430void mp_obj_get_array_fixed_n(mp_obj_t o, size_t len, mp_obj_t **items) {
431 size_t seq_len;
432 mp_obj_get_array(o, &seq_len, items);
433 if (seq_len != len) {
434 #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
435 mp_raise_ValueError(MP_ERROR_TEXT("tuple/list has wrong length"));
436 #else
437 mp_raise_msg_varg(&mp_type_ValueError,
438 MP_ERROR_TEXT("requested length %d but object has length %d"), (int)len, (int)seq_len);
439 #endif
440 }
441}
442
443// is_slice determines whether the index is a slice index
444size_t mp_get_index(const mp_obj_type_t *type, size_t len, mp_obj_t index, bool is_slice) {
445 mp_int_t i;
446 if (mp_obj_is_small_int(index)) {
447 i = MP_OBJ_SMALL_INT_VALUE(index);
448 } else if (!mp_obj_get_int_maybe(index, &i)) {
449 #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
450 mp_raise_TypeError(MP_ERROR_TEXT("indices must be integers"));
451 #else
452 mp_raise_msg_varg(&mp_type_TypeError,
453 MP_ERROR_TEXT("%q indices must be integers, not %s"),
454 type->name, mp_obj_get_type_str(index));
455 #endif
456 }
457
458 if (i < 0) {
459 i += len;
460 }
461 if (is_slice) {
462 if (i < 0) {
463 i = 0;
464 } else if ((mp_uint_t)i > len) {
465 i = len;
466 }
467 } else {
468 if (i < 0 || (mp_uint_t)i >= len) {
469 #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
470 mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("index out of range"));
471 #else
472 mp_raise_msg_varg(&mp_type_IndexError, MP_ERROR_TEXT("%q index out of range"), type->name);
473 #endif
474 }
475 }
476
477 // By this point 0 <= i <= len and so fits in a size_t
478 return (size_t)i;
479}
480
481mp_obj_t mp_obj_id(mp_obj_t o_in) {
482 mp_int_t id = (mp_int_t)o_in;
483 if (!mp_obj_is_obj(o_in)) {
484 return mp_obj_new_int(id);
485 } else if (id >= 0) {
486 // Many OSes and CPUs have affinity for putting "user" memories
487 // into low half of address space, and "system" into upper half.
488 // We're going to take advantage of that and return small int
489 // (signed) for such "user" addresses.
490 return MP_OBJ_NEW_SMALL_INT(id);
491 } else {
492 // If that didn't work, well, let's return long int, just as
493 // a (big) positive value, so it will never clash with the range
494 // of small int returned in previous case.
495 return mp_obj_new_int_from_uint((mp_uint_t)id);
496 }
497}
498
499// will raise a TypeError if object has no length
500mp_obj_t mp_obj_len(mp_obj_t o_in) {
501 mp_obj_t len = mp_obj_len_maybe(o_in);
502 if (len == MP_OBJ_NULL) {
503 #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
504 mp_raise_TypeError(MP_ERROR_TEXT("object has no len"));
505 #else
506 mp_raise_msg_varg(&mp_type_TypeError,
507 MP_ERROR_TEXT("object of type '%s' has no len()"), mp_obj_get_type_str(o_in));
508 #endif
509 } else {
510 return len;
511 }
512}
513
514// may return MP_OBJ_NULL
515mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) {
516 if (
517 #if !MICROPY_PY_BUILTINS_STR_UNICODE
518 // It's simple - unicode is slow, non-unicode is fast
519 mp_obj_is_str(o_in) ||
520 #endif
521 mp_obj_is_type(o_in, &mp_type_bytes)) {
522 GET_STR_LEN(o_in, l);
523 return MP_OBJ_NEW_SMALL_INT(l);
524 } else {
525 const mp_obj_type_t *type = mp_obj_get_type(o_in);
526 if (type->unary_op != NULL) {
527 return type->unary_op(MP_UNARY_OP_LEN, o_in);
528 } else {
529 return MP_OBJ_NULL;
530 }
531 }
532}
533
534mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
535 const mp_obj_type_t *type = mp_obj_get_type(base);
536 if (type->subscr != NULL) {
537 mp_obj_t ret = type->subscr(base, index, value);
538 if (ret != MP_OBJ_NULL) {
539 return ret;
540 }
541 // TODO: call base classes here?
542 }
543 if (value == MP_OBJ_NULL) {
544 #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
545 mp_raise_TypeError(MP_ERROR_TEXT("object doesn't support item deletion"));
546 #else
547 mp_raise_msg_varg(&mp_type_TypeError,
548 MP_ERROR_TEXT("'%s' object doesn't support item deletion"), mp_obj_get_type_str(base));
549 #endif
550 } else if (value == MP_OBJ_SENTINEL) {
551 #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
552 mp_raise_TypeError(MP_ERROR_TEXT("object isn't subscriptable"));
553 #else
554 mp_raise_msg_varg(&mp_type_TypeError,
555 MP_ERROR_TEXT("'%s' object isn't subscriptable"), mp_obj_get_type_str(base));
556 #endif
557 } else {
558 #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE
559 mp_raise_TypeError(MP_ERROR_TEXT("object doesn't support item assignment"));
560 #else
561 mp_raise_msg_varg(&mp_type_TypeError,
562 MP_ERROR_TEXT("'%s' object doesn't support item assignment"), mp_obj_get_type_str(base));
563 #endif
564 }
565}
566
567// Return input argument. Useful as .getiter for objects which are
568// their own iterators, etc.
569mp_obj_t mp_identity(mp_obj_t self) {
570 return self;
571}
572MP_DEFINE_CONST_FUN_OBJ_1(mp_identity_obj, mp_identity);
573
574mp_obj_t mp_identity_getiter(mp_obj_t self, mp_obj_iter_buf_t *iter_buf) {
575 (void)iter_buf;
576 return self;
577}
578
579bool mp_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
580 const mp_obj_type_t *type = mp_obj_get_type(obj);
581 if (type->buffer_p.get_buffer == NULL) {
582 return false;
583 }
584 int ret = type->buffer_p.get_buffer(obj, bufinfo, flags);
585 if (ret != 0) {
586 return false;
587 }
588 return true;
589}
590
591void mp_get_buffer_raise(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
592 if (!mp_get_buffer(obj, bufinfo, flags)) {
593 mp_raise_TypeError(MP_ERROR_TEXT("object with buffer protocol required"));
594 }
595}
596
597mp_obj_t mp_generic_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
598 switch (op) {
599 case MP_UNARY_OP_HASH:
600 return MP_OBJ_NEW_SMALL_INT((mp_uint_t)o_in);
601 default:
602 return MP_OBJ_NULL; // op not supported
603 }
604}
605