\~english \page iostream Input/Output stream
\~russian \page iostream Поток ввода/вывода

\~english

\~russian
%PIBinaryStream представляет собой интерфейс бинарной сериализации.
Не может быть использован в чистом виде, только в виде миксина или
готовых классов: PIByteArray и PIIOBinaryStream.


Используется для сохранения или чтения любых данных. Простые типы читаются/пишутся
как блоки памяти, если не созданы конкретные операторы. Сложные типы
([нетривиальные](https://ru.cppreference.com/w/cpp/types/is_trivially_copyable))
обязаны иметь операторы ввода/вывода, иначе возникнет ошибка компиляции.

Также поддерживаются контейнеры с типами по таким же правилам.

Перечисления интерпретируются как int, логические типы как один байт.

Операторы сохранения добавляют данные в конец потока, а операторы извлечения
берут данные из его начала.

Для облегчения написания операторов есть макросы:
 * BINARY_STREAM_FRIEND(T) - объявить операторы с доступом к приватному
 содержимому типа T, необязателен;
 * BINARY_STREAM_WRITE(T) - запись в поток, "s" - объект потока, "v" - объект типа T;
 * BINARY_STREAM_READ(T) - чтение из потока, "s" - объект потока, "v" - объект типа T.
 
Пример:
\~\code{.cpp}
#include <pibytearray.h>

class MyType {
	BINARY_STREAM_FRIEND(MyType);
public:

	void setInt(int v) {m_i = v;}
	int getInt() const {return m_i;}

	void setString(PIString v) {m_s = v;}
	PIString getString() const {return m_s;}

private:
	int m_i = 0;
	PIString m_s;

};

BINARY_STREAM_WRITE(MyType) {s << v.m_i << v.m_s; return s;}
BINARY_STREAM_READ (MyType) {s >> v.m_i >> v.m_s; return s;}

int main(int argc, char * argv[]) {
	MyType t_read, t_write;
	t_write.setInt(10);
	t_write.setString("text");

	PIByteArray data;
	data << t_write;

	piCout << data.toHex();

	data >> t_read;
	piCout << t_read.getInt() << t_read.getString();

	piCout << data.toHex();
}
\endcode

\~english Result:
\~russian Результат:
\~\code{.cpp}
0a000000040000007400650078007400
10 text

\endcode


\~english
For store/restore custom data blocks this is PIMemoryBlock class. Stream
operators of this class simply store/restore data block to/from stream:

\~russian
Для сохранения/извлечения блоков произвольных данных используется класс PIMemoryBlock.
Потоковые операторы для него просто сохраняют/извлекают блоки байтов в/из потока:

\~\code{.cpp}
float a_read[10], a_write[10];
for (int i = 0; i < 10; ++i) {
	a_read [i] = 0.f;
	a_write[i] = i / 10.f;
}

PIByteArray data;
data << PIMemoryBlock(a_write, 10 * sizeof(float));

piCout << data.toHex();

data >> PIMemoryBlock(a_read, 10 * sizeof(float));
for (int i = 0; i < 10; ++i)
	piCout << a_read[i];
\endcode

\~english Result:
\~russian Результат:
\~\code{.cpp}
00000000cdcccc3dcdcc4c3e9a99993ecdcccc3e0000003f9a99193f3333333fcdcc4c3f6666663f
0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
\endcode

\~english

\~russian
Если при чтении из потока не хватило данных (например, закончился массив или файл), то проверка
объекта потока на wasReadError() вернёт true. Рекомендуется делать эту проверку после чтения
данных для корректной обработки ошибки.
