[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/skia-python/skia-python/main/src/skia/Stream.cpp [Back]  [Original]

#include "common.h"

template  class PyStream : public T {
public:
    using T::T;
    size_t read(void* buffer, size_t size) override {
        PYBIND11_OVERLOAD_PURE(size_t, T, read, buffer, size);
    }
    size_t peek(void* buffer, size_t size) const override {
        PYBIND11_OVERLOAD(size_t, T, peek, buffer, size);
    }
    bool isAtEnd() const override {
        PYBIND11_OVERLOAD_PURE(bool, T, isAtEnd);
    }
    bool rewind() override { PYBIND11_OVERLOAD(bool, T, rewind); }
    bool hasPosition() const override {
        PYBIND11_OVERLOAD(bool, T, hasPosition);
    }
    size_t getPosition() const override {
        PYBIND11_OVERLOAD(size_t, T, getPosition);
    }
    bool seek(size_t position) override {
        PYBIND11_OVERLOAD(bool, T, seek, position);
    }
    bool move(long offset) override {
        PYBIND11_OVERLOAD(bool, T, move, offset);
    }
    bool hasLength() const override {
        PYBIND11_OVERLOAD(bool, T, hasLength);
    }
    size_t getLength() const override {
        PYBIND11_OVERLOAD(size_t, T, getLength);
    }
    const void* getMemoryBase() override {
        PYBIND11_OVERLOAD(const void*, T, getMemoryBase);
    }
};

template  class PyStreamRewindable : public T {
public:
    using T::T;
    size_t read(void* buffer, size_t size) override {
        PYBIND11_OVERLOAD(size_t, T, read, buffer, size);
    }
    size_t peek(void* buffer, size_t size) const override {
        PYBIND11_OVERLOAD(size_t, T, peek, buffer, size);
    }
    bool isAtEnd() const override {
        PYBIND11_OVERLOAD(bool, T, isAtEnd);
    }
    bool rewind() override { PYBIND11_OVERLOAD_PURE(bool, T, rewind); }
    bool hasPosition() const override {
        PYBIND11_OVERLOAD(bool, T, hasPosition);
    }
    size_t getPosition() const override {
        PYBIND11_OVERLOAD(size_t, T, getPosition);
    }
    bool seek(size_t position) override {
        PYBIND11_OVERLOAD(bool, T, seek, position);
    }
    bool move(long offset) override {
        PYBIND11_OVERLOAD(bool, T, move, offset);
    }
    bool hasLength() const override {
        PYBIND11_OVERLOAD(bool, T, hasLength);
    }
    size_t getLength() const override {
        PYBIND11_OVERLOAD(size_t, T, getLength);
    }
    const void* getMemoryBase() override {
        PYBIND11_OVERLOAD(const void*, T, getMemoryBase);
    }
};

template  class PyStreamSeekable : public T {
public:
    using T::T;
    size_t read(void* buffer, size_t size) override {
        PYBIND11_OVERLOAD(size_t, T, read, buffer, size);
    }
    size_t peek(void* buffer, size_t size) const override {
        PYBIND11_OVERLOAD(size_t, T, peek, buffer, size);
    }
    bool isAtEnd() const override {
        PYBIND11_OVERLOAD(bool, T, isAtEnd);
    }
    bool rewind() override { PYBIND11_OVERLOAD(bool, T, rewind); }
    bool hasPosition() const override {
        PYBIND11_OVERLOAD_PURE(bool, T, hasPosition);
    }
    size_t getPosition() const override {
        PYBIND11_OVERLOAD_PURE(size_t, T, getPosition);
    }
    bool seek(size_t position) override {
        PYBIND11_OVERLOAD_PURE(bool, T, seek, position);
    }
    bool move(long offset) override {
        PYBIND11_OVERLOAD_PURE(bool, T, move, offset);
    }
    bool hasLength() const override {
        PYBIND11_OVERLOAD(bool, T, hasLength);
    }
    size_t getLength() const override {
        PYBIND11_OVERLOAD(size_t, T, getLength);
    }
    const void* getMemoryBase() override {
        PYBIND11_OVERLOAD(const void*, T, getMemoryBase);
    }
};

template  class PyStreamAsset : public T {
public:
    using T::T;
    size_t read(void* buffer, size_t size) override {
        PYBIND11_OVERLOAD(size_t, T, read, buffer, size);
    }
    size_t peek(void* buffer, size_t size) const override {
        PYBIND11_OVERLOAD(size_t, T, peek, buffer, size);
    }
    bool isAtEnd() const override {
        PYBIND11_OVERLOAD(bool, T, isAtEnd);
    }
    bool rewind() override { PYBIND11_OVERLOAD(bool, T, rewind); }
    bool hasPosition() const override {
        PYBIND11_OVERLOAD(bool, T, hasPosition);
    }
    size_t getPosition() const override {
        PYBIND11_OVERLOAD(size_t, T, getPosition);
    }
    bool seek(size_t position) override {
        PYBIND11_OVERLOAD(bool, T, seek, position);
    }
    bool move(long offset) override {
        PYBIND11_OVERLOAD(bool, T, move, offset);
    }
    bool hasLength() const override {
        PYBIND11_OVERLOAD(bool, T, hasLength);
    }
    size_t getLength() const override {
        PYBIND11_OVERLOAD_PURE(size_t, T, getLength);
    }
    const void* getMemoryBase() override {
        PYBIND11_OVERLOAD(const void*, T, getMemoryBase);
    }
};

template  class PyStreamMemory : public T {
public:
    using T::T;
    size_t read(void* buffer, size_t size) override {
        PYBIND11_OVERLOAD(size_t, T, read, buffer, size);
    }
    size_t peek(void* buffer, size_t size) const override {
        PYBIND11_OVERLOAD(size_t, T, peek, buffer, size);
    }
    bool isAtEnd() const override {
        PYBIND11_OVERLOAD(bool, T, isAtEnd);
    }
    bool rewind() override { PYBIND11_OVERLOAD(bool, T, rewind); }
    bool hasPosition() const override {
        PYBIND11_OVERLOAD(bool, T, hasPosition);
    }
    size_t getPosition() const override {
        PYBIND11_OVERLOAD(size_t, T, getPosition);
    }
    bool seek(size_t position) override {
        PYBIND11_OVERLOAD(bool, T, seek, position);
    }
    bool move(long offset) override {
        PYBIND11_OVERLOAD(bool, T, move, offset);
    }
    bool hasLength() const override {
        PYBIND11_OVERLOAD(bool, T, hasLength);
    }
    size_t getLength() const override {
        PYBIND11_OVERLOAD(size_t, T, getLength);
    }
    const void* getMemoryBase() override {
        PYBIND11_OVERLOAD_PURE(const void*, T, getMemoryBase);
    }
};

template  class PyWStream : public T {
public:
    using T::T;
    bool write(const void* buffer, size_t size) override {
        PYBIND11_OVERLOAD_PURE(bool, T, write, buffer, size);
    }
    void flush() override { PYBIND11_OVERLOAD(void, T, flush); };
    size_t bytesWritten() const override {
        PYBIND11_OVERLOAD_PURE(size_t, T, bytesWritten);
    };
};

template  class PyWStreamImpl : public T {
public:
    using T::T;
    bool write(const void* buffer, size_t size) override {
        PYBIND11_OVERLOAD(bool, T, write, buffer, size);
    }
    void flush() override { PYBIND11_OVERLOAD(void, T, flush); };
    size_t bytesWritten() const override {
        PYBIND11_OVERLOAD(size_t, T, bytesWritten);
    };
};

template  class PyStreamImpl : public T {
public:
    using T::T;
    size_t read(void* buffer, size_t size) override {
        PYBIND11_OVERLOAD(size_t, T, read, buffer, size);
    }
    size_t peek(void* buffer, size_t size) const override {
        PYBIND11_OVERLOAD(size_t, T, peek, buffer, size);
    }
    bool isAtEnd() const override {
        PYBIND11_OVERLOAD(bool, T, isAtEnd);
    }
    bool rewind() override { PYBIND11_OVERLOAD(bool, T, rewind); }
    bool hasPosition() const override {
        PYBIND11_OVERLOAD(bool, T, hasPosition);
    }
    size_t getPosition() const override {
        PYBIND11_OVERLOAD(size_t, T, getPosition);
    }
    bool seek(size_t position) override {
        PYBIND11_OVERLOAD(bool, T, seek, position);
    }
    bool move(long offset) override {
        PYBIND11_OVERLOAD(bool, T, move, offset);
    }
    bool hasLength() const override {
        PYBIND11_OVERLOAD(bool, T, hasLength);
    }
    size_t getLength() const override {
        PYBIND11_OVERLOAD(size_t, T, getLength);
    }
    const void* getMemoryBase() override {
        PYBIND11_OVERLOAD(const void*, T, getMemoryBase);
    }
};

template  class PyMemoryStream : public T {
public:
    using T::T;
    size_t read(void* buffer, size_t size) override {
        PYBIND11_OVERLOAD(size_t, T, read, buffer, size);
    }
    size_t peek(void* buffer, size_t size) const override {
        PYBIND11_OVERLOAD(size_t, T, peek, buffer, size);
    }
    bool isAtEnd() const override {
        PYBIND11_OVERLOAD(bool, T, isAtEnd);
    }
    bool rewind() override { PYBIND11_OVERLOAD(bool, T, rewind); }
    bool hasPosition() const override {
        PYBIND11_OVERLOAD(bool, T, hasPosition);
    }
    size_t getPosition() const override {
        PYBIND11_OVERLOAD(size_t, T, getPosition);
    }
    bool seek(size_t position) override {
        PYBIND11_OVERLOAD(bool, T, seek, position);
    }
    bool move(long offset) override {
        PYBIND11_OVERLOAD(bool, T, move, offset);
    }
    bool hasLength() const override {
        PYBIND11_OVERLOAD(bool, T, hasLength);
    }
    size_t getLength() const override {
        PYBIND11_OVERLOAD(size_t, T, getLength);
    }
    const void* getMemoryBase() override {
        PYBIND11_OVERLOAD(const void*, T, getMemoryBase);
    }
    void setMemory(
        const void* data, size_t length, bool copyData = false) override {
        PYBIND11_OVERLOAD(void, T, setMemory, data, length, copyData);
    }
};


void initStream(py::module &m) {

py::class_(m, "Stream",
    R"docstring(
    :py:class:`Stream`  abstraction for a source of bytes.

    Subclasses can be backed by memory, or a file, or something else.

    NOTE:

    Classic "streams" APIs are sort of async, in that on a request for N bytes,
    they may return fewer than N bytes on a given call, in which case the caller
    can "try again" to get more bytes, eventually (modulo an error) receiving
    their total N bytes.

    Skia streams behave differently. They are effectively synchronous, and will
    always return all N bytes of the request if possible. If they return fewer
    (the read() call returns the number of bytes read) then that means there is
    no more data (at EOF or hit an error). The caller should not call again in
    hopes of fulfilling more of the request.

    .. rubric:: Subclasses

    .. autosummary::
        :nosignatures:

        ~FILEStream
        ~MemoryStream
    )docstring")
    .def("read",
        [] (SkStream& stream, py::buffer b, size_t size) {
            auto info = b.request(true);
            size_t given = (info.ndim) ? info.strides[0] * info.shape[0] : 0;
            if (size == 0 || size >= given)
                size = given;
            return stream.read(info.ptr, size);
        },
        R"docstring(
        Reads or skips size number of bytes.

        If buffer == NULL, skip size bytes, return how many were skipped. If
        buffer != NULL, copy size bytes into buffer, return how many were
        copied.

        :param buffer:  when NULL skip size bytes, otherwise copy size bytes
            into buffer
        :param size:    the number of bytes to skip or copy; may be nullptr
        :return: the number of bytes actually read.

        Implemented in :py:class:`MemoryStream`, and :py:class:`FILEStream`.
        )docstring",
        py::arg("buffer"), py::arg("size") = 0)
    .def("skip", &SkStream::skip,
        R"docstring(
        Skip size number of bytes.

        :return: the actual number bytes that could be skipped.
        )docstring",
        py::arg("size"))
    .def("peek",
        [] (SkStream& stream, py::buffer b) {
            auto info = b.request(true);
            size_t size = (info.ndim) ? info.strides[0] * info.shape[0] : 0;
            return stream.peek(info.ptr, size);
        },
        R"docstring(
        Attempt to peek at size bytes.

        If this stream supports peeking, copy min(size, peekable bytes) into
        buffer, and return the number of bytes copied. If the stream does not
        support peeking, or cannot peek any bytes, return 0 and leave buffer
        unchanged. The stream is guaranteed to be in the same visible state
        after this call, regardless of success or failure.

        :param buffer:  Must not be NULL, and must be at least size bytes.
            Destination to copy bytes.
        :param size:  Number of bytes to copy.
        :return: The number of bytes peeked/copied.

        Reimplemented in :py:class:`MemoryStream`.
        )docstring",
        py::arg("buffer"))
    .def("isAtEnd", &SkStream::isAtEnd,
        R"docstring(
        Returns true when all the bytes in the stream have been read.

        This may return true early (when there are no more bytes to be read) or
        late (after the first unsuccessful read).

        Implemented in :py:class:`MemoryStream`, and :py:class:`FILEStream`.
        )docstring")
    .def("readS8",
        [] (SkStream& stream) {
            int8_t value;
            if (stream.readS8(&value))
                return value;
            throw std::runtime_error("Failed to read");
        })
    .def("readS16",
        [] (SkStream& stream) {
            int16_t value;
            if (stream.readS16(&value))
                return value;
            throw std::runtime_error("Failed to read");
        })
    .def("readS32",
        [] (SkStream& stream) {
            int32_t value;
            if (stream.readS32(&value))
                return value;
            throw std::runtime_error("Failed to read");
        })
    .def("readU8",
        [] (SkStream& stream) {
            uint8_t value;
            if (stream.readU8(&value))
                return value;
            throw std::runtime_error("Failed to read");
        })
    .def("readU16",
        [] (SkStream& stream) {
            uint16_t value;
            if (stream.readU16(&value))
                return value;
            throw std::runtime_error("Failed to read");
        })
    .def("readU32",
        [] (SkStream& stream) {
            uint32_t value;
            if (stream.readU32(&value))
                return value;
            throw std::runtime_error("Failed to read");
        })
    .def("readBool",
        [] (SkStream& stream) {
            bool value;
            if (stream.readBool(&value))
                return value;
            throw std::runtime_error("Failed to read");
        })
    .def("readScalar",
        [] (SkStream& stream) {
            SkScalar value;
            if (stream.readScalar(&value))
                return value;
            throw std::runtime_error("Failed to read");
        })
    .def("readPackedUInt",
        [] (SkStream& stream) {
            size_t value;
            if (stream.readPackedUInt(&value))
                return value;
            throw std::runtime_error("Failed to read");
        })
    .def("rewind", &SkStream::rewind,
        R"docstring(
        Rewinds to the beginning of the stream.

        Returns true if the stream is known to be at the beginning after this
        call returns.

        Reimplemented in :py:class:`MemoryStream`, :py:class:`FILEStream`, and
        :py:class:`StreamRewindable`.
        )docstring")
    .def("duplicate", &SkStream::duplicate,
        R"docstring(
        Duplicates this stream.

        If this cannot be done, returns NULL. The returned stream will be
        positioned at the beginning of its data.
        )docstring")
    .def("fork", &SkStream::fork,
        R"docstring(
        Duplicates this stream.

        If this cannot be done, returns NULL. The returned stream will be
        positioned the same as this stream.
        )docstring")
    .def("hasPosition", &SkStream::hasPosition,
        R"docstring(
        Returns true if this stream can report it's current position.

        Reimplemented in :py:class:`StreamSeekable`.
        )docstring")
    .def("getPosition", &SkStream::getPosition,
        R"docstring(
        Returns the current position in the stream.

        If this cannot be done, returns 0.

        Reimplemented in :py:class:`MemoryStream`, :py:class:`FILEStream`, and
        :py:class:`StreamSeekable`.
        )docstring")
    .def("seek", &SkStream::seek,
        R"docstring(
        Seeks to an absolute position in the stream.

        If this cannot be done, returns false. If an attempt is made to seek
        past the end of the stream, the position will be set to the end of the
        stream.

        Reimplemented in :py:class:`MemoryStream`, :py:class:`FILEStream`, and
        :py:class:`StreamSeekable`.
        )docstring",
        py::arg("position"))
    .def("move", &SkStream::move,
        R"docstring(
        Seeks to an relative offset in the stream.

        If this cannot be done, returns false. If an attempt is made to move to
        a position outside the stream, the position will be set to the closest
        point within the stream (beginning or end).

        Reimplemented in :py:class:`MemoryStream`, :py:class:`FILEStream`, and
        :py:class:`StreamSeekable`.
        )docstring",
        py::arg("offset"))
    .def("hasLength", &SkStream::hasLength,
        R"docstring(
        Returns true if this stream can report it's total length.

        Reimplemented in :py:class:`StreamAsset`.
        )docstring")
    .def("getLength", &SkStream::getLength,
        R"docstring(
        Returns the total length of the stream.

        If this cannot be done, returns 0.

        Reimplemented in :py:class:`MemoryStream`, :py:class:`FILEStream`, and
        :py:class:`StreamAsset`.
        )docstring")
    .def("getMemoryBase", &SkStream::getMemoryBase,
        R"docstring(
        Returns the starting address for the data.

        If this cannot be done, returns NULL.

        Reimplemented in :py:class:`MemoryStream`, and :py:class:`StreamMemory`.
        )docstring")
    .def_static("MakeFromFile",
        [] (const std::string& path) {
            return SkStream::MakeFromFile(path.c_str());
        },
        R"docstring(
        Attempts to open the specified file as a stream, returns nullptr on
        failure.
        )docstring",
        py::arg("path"))
    ;

py::class_(
    m, "StreamRewindable")
    .def("duplicate", &SkStreamRewindable::duplicate)
    ;

py::class_(
    m, "StreamSeekable")
    .def("fork", &SkStreamSeekable::fork)
    ;

py::class_(
    m, "StreamAsset")
    .def("duplicate", &SkStreamSeekable::duplicate)
    .def("fork", &SkStreamSeekable::fork)
    ;

py::class_(
    m, "StreamMemory")
    .def("duplicate", &SkStreamSeekable::duplicate)
    .def("fork", &SkStreamSeekable::fork)
    ;

py::class_(m, "WStream",
    R"docstring(
    .. rubric:: Subclasses

    .. autosummary::
        :nosignatures:

        ~FILEWStream
        ~DynamicMemoryWStream
    )docstring")
    .def("write",
        [] (SkWStream& stream, py::buffer b) {
            auto info = b.request();
            size_t size = (info.ndim) ? info.strides[0] * info.shape[0] : 0;
            return stream.write(info.ptr, size);
        },
        R"docstring(
        Called to write bytes to a :py:class:`WStream`.

        Returns true on success

        :param buffer:  the address of at least size bytes to be written to the
            stream
        :param size:    The number of bytes in buffer to write to the stream
        :return: true on success

        Implemented in :py:class:`DynamicMemoryWStream`,
            :py:class:`FILEWStream`, and :py:class:`NullWStream`.
        )docstring",
        py::arg("buffer"))
    .def("flush", &SkWStream::flush,
        R"docstring(
        Reimplemented in :py:class:`FILEWStream`, and :py:class:`NullWStream`.
        )docstring")
    .def("bytesWritten", &SkWStream::bytesWritten)
    .def("write8", &SkWStream::write8, py::arg("value"))
    .def("write16", &SkWStream::write16, py::arg("value"))
    .def("write32", &SkWStream::write32, py::arg("value"))
    .def("writeText",
        [] (SkWStream& stream, const std::string& text) {
            return stream.writeText(text.c_str());
        },
        py::arg("text"))
    .def("newline", &SkWStream::newline)
    .def("writeDecAsText", &SkWStream::writeDecAsText, py::arg("value"))
    .def("writeBigDecAsText", &SkWStream::writeBigDecAsText,
        py::arg("value"), py::arg("minDigits") = 0)
    .def("writeHexAsText", &SkWStream::writeHexAsText,
        py::arg("value"), py::arg("minDigits") = 0)
    .def("writeScalarAsText", &SkWStream::writeScalarAsText, py::arg("value"))
    .def("writeBool", &SkWStream::writeBool, py::arg("value"))
    .def("writeBool", &SkWStream::writeBool, py::arg("value"))
    .def("writeScalar", &SkWStream::writeScalar, py::arg("value"))
    .def("writePackedUInt", &SkWStream::writePackedUInt, py::arg("value"))
    .def("writeStream", &SkWStream::writeStream,
        py::arg("input"), py::arg("length"))
    .def_static("SizeOfPackedUInt", &SkWStream::SizeOfPackedUInt,
        py::arg("value"))
    ;

py::class_(
    m, "NullWStream")
    .def(py::init())
    ;

py::class_(
    m, "FILEStream")
    .def("__enter__", [] (const SkFILEStream* stream) { return stream; })
    .def("__exit__",
        [] (SkFILEStream& stream, py::object exc_type, py::object exc_value,
            py::object traceback) { stream.close(); })
    .def(py::init(
        [] (const std::string& path) {
            const char* path_ = path.c_str();
            return SkFILEStream::Make(path_);
        }),
        py::arg("path"))
    .def_static("Make",
        [] (const std::string& path) {
            const char* path_ = path.c_str();
            return SkFILEStream::Make(path_);
        },
        py::arg("path"))
    .def("isValid", &SkFILEStream::isValid)
    .def("close", &SkFILEStream::close)
    ;

py::class_(m, "MemoryStream")
    .def(py::init())
    .def(py::init(), py::arg("length"))
    .def(py::init(
        [] (py::buffer b, bool copyData) {
            auto info = b.request();
            size_t size = (info.ndim) ? info.strides[0] * info.shape[0] : 0;
            return std::unique_ptr(
                new SkMemoryStream(info.ptr, size, copyData));
        }),
        py::arg("data"), py::arg("copyData") = false)
    .def(py::init(), py::arg("data"), py::arg("length"), py::arg("copyData") = false)
    .def(py::init(), py::arg("data"))
    .def_static("MakeCopy",
        [] (py::buffer b) {
            auto info = b.request();
            size_t size = (info.ndim) ? info.strides[0] * info.shape[0] : 0;
            return SkMemoryStream::MakeCopy(info.ptr, size);
        },
        py::arg("data"))
    .def_static("MakeDirect",
        [] (py::buffer b) {
            auto info = b.request();
            size_t size = (info.ndim) ? info.strides[0] * info.shape[0] : 0;
            return SkMemoryStream::MakeDirect(info.ptr, size);
        },
        py::arg("data"))
    .def_static("Make", &SkMemoryStream::Make, py::arg("data"))
    .def("setMemory",
        [] (SkMemoryStream& stream, py::buffer b, bool copyData) {
            auto info = b.request();
            size_t size = (info.ndim) ? info.strides[0] * info.shape[0] : 0;
            stream.setMemory(info.ptr, size, copyData);
        },
        py::arg("data"), py::arg("copyData") = false)
    .def("asData", &SkMemoryStream::getData)
    .def("setData", &SkMemoryStream::setData, py::arg("data"))
    .def("skipToAlign4",
        [] (SkMemoryStream& stream) {
            size_t fOffset = stream.getPosition();
            // cast to remove unary-minus warning
            fOffset += -(int)fOffset & 0x03;
            stream.seek(fOffset);
        }
        )
    .def("getAtPos", &SkMemoryStream::getAtPos)
    ;

py::class_(
    m, "FILEWStream")
    .def(py::init(
        [] (const std::string& path) {
            return std::unique_ptr(
                new SkFILEWStream(path.c_str()));
        }),
        py::arg("path"))
    .def("isValid", &SkFILEWStream::isValid)
    .def("fsync", &SkFILEWStream::fsync)
    ;

py::class_(m, "DynamicMemoryWStream")
    .def(py::init())
    .def("read",
        [] (SkDynamicMemoryWStream& stream, py::buffer b, size_t offset) {
            auto info = b.request(true);
            size_t size = (info.ndim) ? info.strides[0] * info.shape[0] : 0;
            return stream.read(info.ptr, offset, size);
        },
        py::arg("data"), py::arg("offset") = 0)
    .def("copyTo",
        [] (SkDynamicMemoryWStream& stream, py::buffer b) {
            auto info = b.request(true);
            size_t size = (info.ndim) ? info.strides[0] * info.shape[0] : 0;
            if (size < stream.bytesWritten())
                throw py::value_error("Buffer is smaller than required");
            stream.copyTo(info.ptr);
        },
        R"docstring(
        More efficient version of read(dst, 0, :py:meth:`bytesWritten`).
        )docstring",
        py::arg("dst"))
    .def("writeToStream", &SkDynamicMemoryWStream::writeToStream,
        py::arg("dst"))
    .def("copyToAndReset",
        [] (SkDynamicMemoryWStream& stream, py::buffer b) {
            auto info = b.request(true);
            size_t size = (info.ndim) ? info.strides[0] * info.shape[0] : 0;
            if (size < stream.bytesWritten())
                throw py::value_error("Buffer is smaller than required");
            stream.copyToAndReset(info.ptr);
        },
        R"docstring(
        Equivalent to :py:meth:`copyTo` followed by :py:meth:`reset`, but may
        save memory use.
        )docstring",
        py::arg("dst"))
    .def("writeToAndReset",
        py::overload_cast(&SkDynamicMemoryWStream::writeToAndReset),
        R"docstring(
        Equivalent to :py:meth:`writeToStream` followed by :py:meth:`reset`, but
        may save memory use.
        )docstring",
        py::arg("dst"))
    .def("writeToAndReset",
        py::overload_cast(
            &SkDynamicMemoryWStream::writeToAndReset),
        R"docstring(
        Equivalent to :py:meth:`writeToStream` followed by :py:meth:`reset`, but
        may save memory use.

        When the dst is also a :py:class:`DynamicMemoryWStream`, the
        implementation is constant time.
        )docstring",
        py::arg("dst"))
    .def("prependToAndReset", &SkDynamicMemoryWStream::prependToAndReset,
        R"docstring(
        Prepend this stream to dst, resetting this.
        )docstring",
        py::arg("dst"))
    .def("detachAsData", &SkDynamicMemoryWStream::detachAsData,
        R"docstring(
        Return the contents as :py:class:`Data`, and then reset the stream.
        )docstring")
    .def("detachAsStream", &SkDynamicMemoryWStream::detachAsStream,
        R"docstring(
        Reset, returning a reader stream with the current content.
        )docstring")
    .def("reset", &SkDynamicMemoryWStream::reset)
    .def("padToAlign4", &SkDynamicMemoryWStream::padToAlign4)
    ;

}

Web Proxy Viewer  |  New URL  |  Original Page