raw: Fix span and string_view construnction from views

Change-Id: Iba65d73e4e87a792ef75360326ac76d437dd1a91
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/stdplus/raw.hpp b/src/stdplus/raw.hpp
index 885028c..d17bd89 100644
--- a/src/stdplus/raw.hpp
+++ b/src/stdplus/raw.hpp
@@ -31,6 +31,13 @@
 using copyConst =
     std::conditional_t<std::is_const_v<B>, std::add_const_t<A>, A>;
 
+/** @brief Determines if a type is a container of data
+ */
+template <typename, typename = void>
+inline constexpr bool hasData = false;
+template <typename T>
+inline constexpr bool hasData<T, std::void_t<dataType<T>>> = true;
+
 } // namespace detail
 
 /** @brief Compares two containers to see if their raw bytes are equal
@@ -149,37 +156,39 @@
  *  @param[in] t - The trivial raw data
  *  @return A view over the input with the given output integral type
  */
-template <typename CharT, typename T,
-          typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
-std::basic_string_view<CharT> asView(const T& t) noexcept
+template <typename CharT, typename T>
+std::enable_if_t<!detail::hasData<T>, std::basic_string_view<CharT>>
+    asView(const T& t) noexcept
 {
+    static_assert(std::is_trivially_copyable_v<T>);
     static_assert(sizeof(T) % sizeof(CharT) == 0);
     return {reinterpret_cast<const CharT*>(&t), sizeof(T) / sizeof(CharT)};
 }
-template <typename CharT, typename Container,
-          typename = std::enable_if_t<!std::is_trivially_copyable_v<Container>>,
-          typename = decltype(std::data(std::declval<Container>()))>
-std::basic_string_view<CharT> asView(const Container& c) noexcept
+
+template <typename CharT, typename Container>
+std::enable_if_t<detail::hasData<Container>, std::basic_string_view<CharT>>
+    asView(const Container& c) noexcept
 {
     static_assert(detail::trivialContainer<Container>);
     static_assert(sizeof(*std::data(c)) % sizeof(CharT) == 0);
     return {reinterpret_cast<const CharT*>(std::data(c)),
             std::size(c) * sizeof(*std::data(c)) / sizeof(CharT)};
 }
+
 #ifdef STDPLUS_SPAN_TYPE
 template <typename IntT, typename T,
           typename = std::enable_if_t<std::is_trivially_copyable_v<IntT>>,
-          typename = std::enable_if_t<std::is_trivially_copyable_v<T>>,
+          typename = std::enable_if_t<!detail::hasData<T>>,
           typename IntTp = detail::copyConst<IntT, T>>
 span<IntTp> asSpan(T& t) noexcept
 {
+    static_assert(std::is_trivially_copyable_v<T>);
     static_assert(sizeof(T) % sizeof(IntTp) == 0);
     return {reinterpret_cast<IntTp*>(&t), sizeof(T) / sizeof(IntTp)};
 }
 template <typename IntT, typename Container,
           typename = std::enable_if_t<std::is_trivially_copyable_v<IntT>>,
-          typename = std::enable_if_t<!std::is_trivially_copyable_v<Container>>,
-          typename = decltype(std::data(std::declval<Container>())),
+          typename = std::enable_if_t<detail::hasData<Container>>,
           typename IntTp = detail::copyConst<IntT, detail::dataType<Container>>>
 span<IntTp> asSpan(Container&& c) noexcept
 {
diff --git a/test/raw.cpp b/test/raw.cpp
index 8be8b7b..2e054bc 100644
--- a/test/raw.cpp
+++ b/test/raw.cpp
@@ -146,6 +146,15 @@
     CHECK(htole16(0) == s[3]);
 }
 
+TEST_CASE("As View View", "[AsView]")
+{
+    std::string_view sv = "ab";
+    auto s = asView<uint8_t>(sv);
+    REQUIRE(s.size() == 2);
+    CHECK(s[0] == sv[0]);
+    CHECK(s[1] == sv[1]);
+}
+
 #ifdef STDPLUS_SPAN_TYPE
 TEST_CASE("Span Extract TooSmall", "[Extract]")
 {
@@ -238,6 +247,21 @@
     CHECK(htole16(0) == s[3]);
 }
 
+TEST_CASE("As Span Span", "[AsSpan]")
+{
+    std::array<char, 2> arr = {'a', 'b'};
+    auto sp1 = span<const char>(arr);
+    auto s1 = asSpan<uint8_t>(sp1);
+    REQUIRE(s1.size() == 2);
+    CHECK(s1[0] == arr[0]);
+    CHECK(s1[1] == arr[1]);
+    auto sp2 = span<char>(arr);
+    auto s2 = asSpan<uint8_t>(sp2);
+    REQUIRE(s2.size() == 2);
+    CHECK(s2[0] == arr[0]);
+    CHECK(s2[1] == arr[1]);
+}
+
 #endif
 
 } // namespace