# SIZE Layer

This layer is responsible to handle the remaining length information.

* During read operation it reads the information about number of

  bytes required to complete the message deserialisation and compares

  it to the number of bytes available for reading. If input buffer has

  enough data, the read operation of the next (wrapped) layer is invoked.
* During write operation, the layer must calculate and write the

  number of bytes required to serialise the message prior to invoking the

  write operation of the next (wrapped) layer.

```cpp
namespace comms
{
// TField is type of the field used to read/write SIZE information
// TNext is the next layer this one wraps
template <typename TField, typename TNext>
class MsgSizeLayer
{
public:
    // Type of the field object used to read/write SIZE information.
    using Field = TField;

    // Take type of the ReadIterator from the next layer
    using ReadIterator = typename TNext::ReadIterator;

    // Take type of the WriteIterator from the next layer
    using WriteIterator = typename TNext::WriteIterator;

    // Take type of the message interface from the next layer
    using Message = typename TNext::Message;

    // Take type of the message interface pointer from the next layer
    using MsgPtr = typename TNext::MsgPtr; 

    template <typename TMsgPtr>
    ErrorStatus read(TMsgPtr& msgPtr, ReadIterator& iter, std::size_t len)
    {
        Field field;
        auto es = field.read(iter, len);
        if (es != ErrorStatus::Success) {
            return es;
        }
        auto actualRemainingSize = (len - field.length());
        auto requiredRemainingSize = static_cast<std::size_t>(field.value());
        if (actualRemainingSize < requiredRemainingSize) {
            return ErrorStatus::NotEnoughData;
        }
        es = reader.read(msgPtr, iter, requiredRemainingSize);
        if (es == ErrorStatus::NotEnoughData) {
            return ErrorStatus::ProtocolError;
        }
        return es;
    } 

    ErrorStatus write(const Message& msg, WriteIterator& iter, std::size_t len) const
    {
        Field field;
        field.value() = m_next.length(msg);
        auto es = field.write(iter, len);
        if (es != ErrorStatus::Success) {
            return es;
        }
        return m_next.write(msg, iter, len - field.length());
    }

private:
    TNext m_next;
};
} // namespace comms
```

Please note, that reference to the smart pointer holding the message object is passed to the `read()` function using *undefined* type (template parameter) instead of using the `MsgPtr` internal type. Some communication protocols may serialise `SIZE` information before the `ID`, others may do the opposite. The `SIZE` layer is not aware of what other layers it wraps. If `ID` information is serialised before the `SIZE`, the `MsgPtr` type definition is probably taken from [PAYLOAD Layer](/comms-protocols-cpp/head-3/payload.md), which is defined to be `void`.

Also note, that `write()` function requires knowledge of how many bytes it will take to the next layer to serialise the message. It requires every layer to define `length(...)` member function in addition to `read()` and `write()`.

The `length()` member function of the [PAYLOAD Layer](/comms-protocols-cpp/head-3/payload.md) may be defined as:

```cpp
namespace comms
{
template <typename TMessage>
class MsgDataLayer
{
public:
    static constexpr std::size_t length(const TMessage& msg)
    {
        return msg.length();
    }
};
} // namespace comms
```

The `length()` member function of the [ID Layer](/comms-protocols-cpp/head-3/id.md) may be defined as:

```cpp
namespace comms
{
template <
    typename TField, 
    typename TAllMessages, 
    typename TNext, 
    typename... TOptions>
class MsgIdLayer
{
public:
    std::size_t length(const Message& msg) const
    {
        TField field;
        field.value() = msg.id();
        return field.length() + m_next.length(msg);
    }
};
} // namespace comms
```

And the `length()` member function of the [SIZE Layer](/comms-protocols-cpp/head-3/size.md) itself may be defined as:

```cpp
namespace comms
{
template <typename TField, typename TNext>
class MsgSizeLayer
{
public:
    std::size_t length(const Message& msg) const
    {
        TField field;
        field.value() = m_next.length(msg);
        return field.length() + field.value();
    }
};
} // namespace comms
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://alex-robenko.gitbook.io/comms-protocols-cpp/head-3/size.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
