dncurrency/nano/lib/stream.hpp
Piotr Wójcik daf5b1e52c
Fix deprecation warning about using char_traits<uint8_t> (#4298)
Create an implementation of char_traits to replace deprecated equivalent in the standard library.
2023-09-28 17:03:00 +01:00

90 lines
2.7 KiB
C++

#pragma once
#include <nano/lib/char_traits.hpp>
#include <nano/lib/utility.hpp>
#include <boost/endian/conversion.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <streambuf>
#include <string>
#include <vector>
namespace nano
{
// We operate on streams of uint8_t by convention
using stream = std::basic_streambuf<uint8_t, uint8_char_traits>;
using bufferstream = boost::iostreams::stream_buffer<boost::iostreams::basic_array_source<uint8_t>, uint8_char_traits>;
using vectorstream = boost::iostreams::stream_buffer<boost::iostreams::back_insert_device<std::vector<uint8_t>>, uint8_char_traits>;
// Read a raw byte stream the size of `T' and fill value. Returns true if there was an error, false otherwise
template <typename T>
bool try_read (nano::stream & stream_a, T & value_a)
{
static_assert (std::is_standard_layout<T>::value, "Can't stream read non-standard layout types");
auto amount_read (stream_a.sgetn (reinterpret_cast<uint8_t *> (&value_a), sizeof (value_a)));
return amount_read != sizeof (value_a);
}
// A wrapper of try_read which throws if there is an error
template <typename T>
void read (nano::stream & stream_a, T & value)
{
auto error = try_read (stream_a, value);
if (error)
{
throw std::runtime_error ("Failed to read type");
}
}
inline void read (nano::stream & stream_a, std::vector<uint8_t> & value_a, size_t size_a)
{
value_a.resize (size_a);
if (stream_a.sgetn (value_a.data (), size_a) != size_a)
{
throw std::runtime_error ("Failed to read this number of bytes");
}
}
template <typename T>
void write (nano::stream & stream_a, T const & value_a)
{
static_assert (std::is_standard_layout<T>::value, "Can't stream write non-standard layout types");
auto amount_written (stream_a.sputn (reinterpret_cast<uint8_t const *> (&value_a), sizeof (value_a)));
(void)amount_written;
debug_assert (amount_written == sizeof (value_a));
}
inline void write (nano::stream & stream_a, std::vector<uint8_t> const & value_a)
{
auto amount_written (stream_a.sputn (value_a.data (), value_a.size ()));
(void)amount_written;
debug_assert (amount_written == value_a.size ());
}
inline bool at_end (nano::stream & stream)
{
uint8_t junk;
auto end (nano::try_read (stream, junk));
return end;
}
/*
* We use big endian as standard for all network communications
*/
template <typename T>
void write_big_endian (nano::stream & stream, T const & value)
{
nano::write (stream, boost::endian::native_to_big (value));
}
template <typename T>
void read_big_endian (nano::stream & stream, T & value)
{
T tmp;
nano::read (stream, tmp);
value = boost::endian::big_to_native (tmp);
}
}