# 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](payload), 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](payload) 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](id) 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](size) 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
```
