#pragma once

#include <xrpl/basics/Buffer.h>
#include <xrpl/basics/CountedObject.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/protocol/STBase.h>

#include <cstring>

namespace xrpl {

// variable length byte string
class STBlob : public STBase, public CountedObject<STBlob>
{
    Buffer value_;

public:
    using value_type = Slice;

    STBlob() = default;
    STBlob(STBlob const& rhs);

    STBlob(SField const& f, void const* data, std::size_t size);
    STBlob(SField const& f, Buffer&& b);
    STBlob(SField const& n);
    STBlob(SerialIter&, SField const& name = sfGeneric);

    std::size_t
    size() const;

    std::uint8_t const*
    data() const;

    SerializedTypeID
    getSType() const override;

    std::string
    getText() const override;

    void
    add(Serializer& s) const override;

    bool
    isEquivalent(STBase const& t) const override;

    bool
    isDefault() const override;

    STBlob&
    operator=(Slice const& slice);

    value_type
    value() const noexcept;

    STBlob&
    operator=(Buffer&& buffer);

    void
    setValue(Buffer&& b);

private:
    STBase*
    copy(std::size_t n, void* buf) const override;
    STBase*
    move(std::size_t n, void* buf) override;

    friend class detail::STVar;
};

inline STBlob::STBlob(STBlob const& rhs)
    : STBase(rhs), CountedObject<STBlob>(rhs), value_(rhs.data(), rhs.size())
{
}

inline STBlob::STBlob(SField const& f, void const* data, std::size_t size)
    : STBase(f), value_(data, size)
{
}

inline STBlob::STBlob(SField const& f, Buffer&& b) : STBase(f), value_(std::move(b))
{
}

inline STBlob::STBlob(SField const& n) : STBase(n)
{
}

inline std::size_t
STBlob::size() const
{
    return value_.size();
}

inline std::uint8_t const*
STBlob::data() const
{
    return reinterpret_cast<std::uint8_t const*>(value_.data());
}

inline STBlob&
STBlob::operator=(Slice const& slice)
{
    value_ = Buffer(slice.data(), slice.size());
    return *this;
}

inline STBlob::value_type
STBlob::value() const noexcept
{
    return value_;
}

inline STBlob&
STBlob::operator=(Buffer&& buffer)
{
    value_ = std::move(buffer);
    return *this;
}

inline void
STBlob::setValue(Buffer&& b)
{
    value_ = std::move(b);
}

}  // namespace xrpl
