Add const-converter and Container support to Span
diff --git a/include/rive/assets/file_asset_contents.hpp b/include/rive/assets/file_asset_contents.hpp
index 10546d2..917bbb0 100644
--- a/include/rive/assets/file_asset_contents.hpp
+++ b/include/rive/assets/file_asset_contents.hpp
@@ -9,11 +9,11 @@
         std::vector<uint8_t> m_Bytes;
 
     public:
-        const Span<const uint8_t> bytes() const;
+        Span<const uint8_t> bytes() const;
         StatusCode import(ImportStack& importStack) override;
         void decodeBytes(Span<const uint8_t> value) override;
         void copyBytes(const FileAssetContentsBase& object) override;
     };
 } // namespace rive
 
-#endif
\ No newline at end of file
+#endif
diff --git a/include/rive/span.hpp b/include/rive/span.hpp
index 9aa8319..abfae67 100644
--- a/include/rive/span.hpp
+++ b/include/rive/span.hpp
@@ -6,7 +6,6 @@
 #define _RIVE_SPAN_HPP_
 
 #include "rive/rive_types.hpp"
-#include <vector>
 
 /*
  *  Span : cheap impl of std::span (which is C++20)
@@ -26,9 +25,11 @@
         assert(ptr <= ptr + size);
     }
 
-    // We don't modify vec, but we don't want to say const, since that would
-    // change .data() to return const T*, and we don't want to change it.
-    Span(std::vector<T>& vec) : Span(vec.data(), vec.size()) {}
+    // Handle Span<foo> --> Span<const foo>
+    template <typename U,
+              typename = typename std::enable_if<std::is_same<const U, T>::value>::type>
+    constexpr Span(const Span<U>& that) : Span(that.data(), that.size()) {}
+    constexpr Span(const Span&) = default;
 
     constexpr T& operator[](size_t index) const {
         assert(index < m_Size);
@@ -61,6 +62,12 @@
     }
 };
 
+template <typename Container>
+inline auto toSpan(Container& c)
+        -> Span<typename std::remove_reference<decltype(*(c.data()))>::type> {
+    return {c.data(), c.size()};
+}
+
 } // namespace rive
 
 #endif
diff --git a/src/assets/file_asset_contents.cpp b/src/assets/file_asset_contents.cpp
index e12c804..d4c0340 100644
--- a/src/assets/file_asset_contents.cpp
+++ b/src/assets/file_asset_contents.cpp
@@ -24,6 +24,6 @@
     assert(false);
 }
 
-const Span<const uint8_t> FileAssetContents::bytes() const {
-    return Span<const uint8_t>(&m_Bytes[0], m_Bytes.size());
-}
\ No newline at end of file
+Span<const uint8_t> FileAssetContents::bytes() const {
+    return toSpan(m_Bytes);
+}
diff --git a/src/core/binary_reader.cpp b/src/core/binary_reader.cpp
index b115e65..1a735ee 100644
--- a/src/core/binary_reader.cpp
+++ b/src/core/binary_reader.cpp
@@ -62,7 +62,7 @@
 
     const uint8_t* start = m_Position;
     m_Position += length;
-    return Span<const uint8_t>(start, length);
+    return {start, length};
 }
 
 double BinaryReader::readFloat64() {
diff --git a/src/importers/file_asset_importer.cpp b/src/importers/file_asset_importer.cpp
index d8488fe..9c69728 100644
--- a/src/importers/file_asset_importer.cpp
+++ b/src/importers/file_asset_importer.cpp
@@ -12,7 +12,7 @@
     m_FileAsset(fileAsset), m_FileAssetResolver(assetResolver) {}
 
 void FileAssetImporter::loadContents(const FileAssetContents& contents) {
-    Span<const uint8_t> data = contents.bytes();
+    auto data = contents.bytes();
     if (m_FileAsset->decode(data.begin(), data.size())) {
         m_LoadedContents = true;
     }
@@ -27,4 +27,4 @@
 
     // Note that it's ok for an asset to not resolve (or to resolve async).
     return StatusCode::Ok;
-}
\ No newline at end of file
+}
diff --git a/src/shapes/mesh.cpp b/src/shapes/mesh.cpp
index a51114c..ded4edc 100644
--- a/src/shapes/mesh.cpp
+++ b/src/shapes/mesh.cpp
@@ -90,16 +90,14 @@
         uv[index++] = vertex->u();
         uv[index++] = vertex->v();
     }
-    m_UVRenderBuffer = makeBufferF32(Span<const float>(uv.data(), uv.size()));
-    m_IndexRenderBuffer = makeBufferU16(
-        Span((const uint16_t*)m_IndexBuffer->data(), m_IndexBuffer->size()));
+    m_UVRenderBuffer = makeBufferF32(toSpan(uv));
+    m_IndexRenderBuffer = makeBufferU16(toSpan(*m_IndexBuffer));
 }
 
 void Mesh::update(ComponentDirt value) {
     if (hasDirt(value, ComponentDirt::Vertices)) {
         if (skin() != nullptr) {
-            skin()->deform(
-                Span((Vertex**)m_Vertices.data(), m_Vertices.size()));
+            skin()->deform({(Vertex**)m_Vertices.data(), m_Vertices.size()});
         }
         m_VertexRenderBuffer = nullptr;
     }
@@ -112,15 +110,14 @@
                 float opacity) {
     if (m_VertexRenderBuffer == nullptr) {
 
-        std::vector<float> vertices = std::vector<float>(m_Vertices.size() * 2);
+        std::vector<float> vertices(m_Vertices.size() * 2);
         std::size_t index = 0;
         for (auto vertex : m_Vertices) {
             auto translation = vertex->renderTranslation();
             vertices[index++] = translation[0];
             vertices[index++] = translation[1];
         }
-        m_VertexRenderBuffer =
-            makeBufferF32(Span((const float*)vertices.data(), vertices.size()));
+        m_VertexRenderBuffer = makeBufferF32(toSpan(vertices));
     }
 
     if (skin() == nullptr) {
@@ -133,4 +130,4 @@
                             m_IndexRenderBuffer,
                             blendMode,
                             opacity);
-}
\ No newline at end of file
+}
diff --git a/test/span_test.cpp b/test/span_test.cpp
index c59c532..661415b 100644
--- a/test/span_test.cpp
+++ b/test/span_test.cpp
@@ -8,15 +8,6 @@
 
 using namespace rive;
 
-namespace {
-    class baseclass {};
-    class subclass : public baseclass {};
-} // namespace
-
-static void function(Span<int> span) {}
-static void function(Span<baseclass*> span) {}
-static void function(Span<subclass*> span) {}
-
 TEST_CASE("basics", "[span]") {
     Span<int> span;
     REQUIRE(span.empty());
@@ -52,12 +43,21 @@
     REQUIRE(sub.size() == 0);
 }
 
-TEST_CASE("vector-integration", "[span]") {
-    std::vector<int> vi;
-    std::vector<baseclass*> vb;
-    std::vector<subclass*> vs;
+static void funca(Span<int> span) {}
+static void funcb(Span<const int> span) {}
 
-    function(vi);
-    function(vb);
-    function(vs);
+TEST_CASE("const-and-containers", "[span]") {
+    const int carray[] = {1, 2, 3, 4};
+    funcb({carray, 4});
+
+    int array[] = {1, 2, 3, 4};
+    funca({array, 4});
+    funcb({array, 4});
+
+    std::vector<const int> cv;
+    funcb(ToSpan(cv));
+
+    std::vector<int> v;
+    funca(ToSpan(v));
+    funcb(ToSpan(v));
 }