| 663 | } |
| 664 | |
| 665 | static int write_python_string(Buffer *buffer, PyObject *value) { |
| 666 | if (FORY_PREDICT_FALSE(!PyUnicode_Check(value))) { |
| 667 | PyErr_Format(PyExc_TypeError, "expected str, got %.200s", |
| 668 | Py_TYPE(value)->tp_name); |
| 669 | return -1; |
| 670 | } |
| 671 | if (FORY_PREDICT_FALSE(PyUnicode_READY(value) < 0)) { |
| 672 | return -1; |
| 673 | } |
| 674 | const Py_ssize_t length = PyUnicode_GET_LENGTH(value); |
| 675 | const int kind = PyUnicode_KIND(value); |
| 676 | const void *data = PyUnicode_DATA(value); |
| 677 | uint64_t header = 0; |
| 678 | uint32_t buffer_size = 0; |
| 679 | |
| 680 | if (kind == PyUnicode_1BYTE_KIND) { |
| 681 | if (FORY_PREDICT_FALSE(length > std::numeric_limits<uint32_t>::max())) { |
| 682 | PyErr_SetString(PyExc_OverflowError, |
| 683 | "string too large for fastpath encoding"); |
| 684 | return -1; |
| 685 | } |
| 686 | buffer_size = static_cast<uint32_t>(length); |
| 687 | header = (static_cast<uint64_t>(length) << 2U) | 0ULL; |
| 688 | } else if (kind == PyUnicode_2BYTE_KIND) { |
| 689 | const uint64_t bytes = static_cast<uint64_t>(length) << 1U; |
| 690 | if (FORY_PREDICT_FALSE(bytes > std::numeric_limits<uint32_t>::max())) { |
| 691 | PyErr_SetString(PyExc_OverflowError, |
| 692 | "string too large for fastpath encoding"); |
| 693 | return -1; |
| 694 | } |
| 695 | buffer_size = static_cast<uint32_t>(bytes); |
| 696 | // Keep wire format exactly aligned with Buffer.write_string in buffer.pyx. |
| 697 | header = (static_cast<uint64_t>(length) << 3U) | 1ULL; |
| 698 | } else { |
| 699 | Py_ssize_t utf8_size = 0; |
| 700 | const char *utf8 = PyUnicode_AsUTF8AndSize(value, &utf8_size); |
| 701 | if (FORY_PREDICT_FALSE(utf8 == nullptr)) { |
| 702 | return -1; |
| 703 | } |
| 704 | if (FORY_PREDICT_FALSE(utf8_size > std::numeric_limits<uint32_t>::max())) { |
| 705 | PyErr_SetString(PyExc_OverflowError, |
| 706 | "string too large for fastpath encoding"); |
| 707 | return -1; |
| 708 | } |
| 709 | data = utf8; |
| 710 | buffer_size = static_cast<uint32_t>(utf8_size); |
| 711 | header = (static_cast<uint64_t>(buffer_size) << 2U) | 2ULL; |
| 712 | } |
| 713 | |
| 714 | buffer->write_var_uint64(header); |
| 715 | if (buffer_size == 0) { |
| 716 | return 0; |
| 717 | } |
| 718 | const uint32_t writer_index = buffer->writer_index(); |
| 719 | buffer->grow(buffer_size); |
| 720 | buffer->unsafe_put(writer_index, data, buffer_size); |
| 721 | buffer->increase_writer_index(buffer_size); |
| 722 | return 0; |
no test coverage detected