| 1466 | } |
| 1467 | |
| 1468 | int Fory_PyPrimitiveCollectionWriteToBuffer(PyObject *collection, |
| 1469 | Buffer *buffer, uint8_t type_id) { |
| 1470 | PyObject **items = py_sequence_get_items(collection); |
| 1471 | if (items != nullptr) { |
| 1472 | const Py_ssize_t size = Py_SIZE(collection); |
| 1473 | // Refactor guard: |
| 1474 | // - tuple is immutable, so raw item pointer iteration is always safe. |
| 1475 | // - list is mutable, so use raw pointer path only when |
| 1476 | // can_use_list_sequence_fastpath(...) proves callback-free conversion. |
| 1477 | // Otherwise we must fall back to iterator path for safety. |
| 1478 | if (!PyList_CheckExact(collection) || |
| 1479 | can_use_list_sequence_fastpath(items, size, type_id)) { |
| 1480 | return write_primitive_sequence(items, size, buffer, type_id); |
| 1481 | } |
| 1482 | } |
| 1483 | PyObject *iterator = PyObject_GetIter(collection); |
| 1484 | if (FORY_PREDICT_FALSE(iterator == nullptr)) { |
| 1485 | return -1; |
| 1486 | } |
| 1487 | int rc = 0; |
| 1488 | for (PyObject *item = PyIter_Next(iterator); item != nullptr; |
| 1489 | item = PyIter_Next(iterator)) { |
| 1490 | if (FORY_PREDICT_FALSE(write_primitive_item(buffer, item, type_id) != 0)) { |
| 1491 | Py_DECREF(item); |
| 1492 | rc = -1; |
| 1493 | break; |
| 1494 | } |
| 1495 | Py_DECREF(item); |
| 1496 | } |
| 1497 | if (FORY_PREDICT_FALSE(rc == 0 && PyErr_Occurred() != nullptr)) { |
| 1498 | rc = -1; |
| 1499 | } |
| 1500 | Py_DECREF(iterator); |
| 1501 | return rc; |
| 1502 | } |
| 1503 | |
| 1504 | int Fory_PyPrimitiveCollectionReadFromBuffer(PyObject *collection, |
| 1505 | Buffer *buffer, Py_ssize_t size, |
nothing calls this directly
no test coverage detected