// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.

#pragma once
#define HAVE_IRCD_BYTE_VIEW_H

namespace ircd
{
	template<class T = string_view> struct byte_view;
	template<> struct byte_view<string_view>;
}

/// string_view -> bytes
template<class T>
struct ircd::byte_view
{
	string_view s;

	operator const T &() const
	{
		assert(sizeof(T) <= size(s));
		if(unlikely(sizeof(T) > s.size()))
			throw std::bad_cast();

		return *reinterpret_cast<const T *>(s.data());
	}

	byte_view(const string_view &s = {})
	:s{s}
	{}

	// bytes -> bytes (completeness)
	byte_view(const T &t)
	:s{byte_view<string_view>{t}}
	{}
};

/// bytes -> string_view. A byte_view<string_view> is raw data of byte_view<T>.
///
/// This is an important specialization to take note of. When you see
/// byte_view<string_view> know that another type's bytes are being represented
/// by the string_view if that type is not string_view family itself.
template<>
struct ircd::byte_view<ircd::string_view>
:string_view
{
	template<class T,
	         typename std::enable_if<!std::is_base_of<std::string_view, T>::value, int *>::type = nullptr>
	byte_view(const T &t)
	:string_view{reinterpret_cast<const char *>(&t), sizeof(T)}
	{}

	/// string_view -> string_view (completeness)
	byte_view(const string_view &t = {})
	:string_view{t}
	{}
};