lix-rs: enable iterators
we don't support range-based iteration yet because it's a huge hassle to make c++ and rust iteration styles meet in any reasonable way. this is a good start to make rust collections *actually* usable though, so here we go. `into_iter` is not explicitly supported, but can be used regardless. Change-Id: Iebb76c9409059bc81623e5be81ac2656b1ec5138
This commit is contained in:
@@ -11,6 +11,9 @@ type [u8] {
|
||||
|
||||
fn as_ptr(&self) -> *const u8;
|
||||
fn len(&self) -> usize;
|
||||
|
||||
fn iter(&self) -> ::std::slice::Iter<u8>;
|
||||
fn iter_mut(&mut self) -> ::std::slice::IterMut<u8>;
|
||||
}
|
||||
|
||||
type str {
|
||||
|
||||
@@ -44,6 +44,33 @@ mod ::std::option {
|
||||
|
||||
fn unwrap(self) -> String;
|
||||
}
|
||||
|
||||
type Option<u8> {
|
||||
#layout_conservative(size = 2, align = 1);
|
||||
|
||||
constructor Some(u8);
|
||||
constructor None;
|
||||
|
||||
fn unwrap(self) -> u8;
|
||||
}
|
||||
|
||||
type Option<&u8> {
|
||||
#layout_conservative(size = 8, align = 8);
|
||||
|
||||
constructor Some(&u8);
|
||||
constructor None;
|
||||
|
||||
fn unwrap(self) -> &u8;
|
||||
}
|
||||
|
||||
type Option<&mut u8> {
|
||||
#layout_conservative(size = 8, align = 8);
|
||||
|
||||
constructor Some(&mut u8);
|
||||
constructor None;
|
||||
|
||||
fn unwrap(self) -> &mut u8;
|
||||
}
|
||||
}
|
||||
|
||||
mod ::std::result {
|
||||
@@ -60,6 +87,20 @@ mod ::std::result {
|
||||
}
|
||||
}
|
||||
|
||||
mod ::std::slice {
|
||||
type Iter<u8> {
|
||||
#layout_conservative(size = 16, align = 8);
|
||||
|
||||
fn next(&mut self) -> ::std::option::Option<&u8>;
|
||||
}
|
||||
|
||||
type IterMut<u8> {
|
||||
#layout_conservative(size = 16, align = 8);
|
||||
|
||||
fn next(&mut self) -> ::std::option::Option<&mut u8>;
|
||||
}
|
||||
}
|
||||
|
||||
mod ::std::string {
|
||||
type String {
|
||||
#layout_conservative(size = 24, align = 8);
|
||||
@@ -79,4 +120,21 @@ mod ::std::vec {
|
||||
fn push(&mut self, String);
|
||||
fn len(&self) -> usize;
|
||||
}
|
||||
|
||||
type Vec<u8> {
|
||||
#layout_conservative(size = 24, align = 8);
|
||||
|
||||
fn new() -> Vec<u8>;
|
||||
fn push(&mut self, u8);
|
||||
fn len(&self) -> usize;
|
||||
fn as_ref(&self) -> &[u8];
|
||||
fn as_mut(&mut self) -> &mut [u8];
|
||||
fn into_iter(self) -> IntoIter<u8>;
|
||||
}
|
||||
|
||||
type IntoIter<u8> {
|
||||
#layout_conservative(size = 32, align = 8);
|
||||
|
||||
fn next(&mut self) -> ::std::option::Option<u8>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,6 +224,73 @@ concept HasOpEq = requires(Lhs lhs, Rhs rhs) {
|
||||
Ref<::std::remove_cvref_t<Lhs>>{};
|
||||
Ref<::std::remove_cvref_t<Rhs>>{};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct OptionArg;
|
||||
template<typename T>
|
||||
struct OptionArg<Option<T>>
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
concept IsOption = requires { typename OptionArg<T>::type; };
|
||||
|
||||
template<typename T>
|
||||
concept Iterator = requires(T t) {
|
||||
{ t.next() } -> IsOption;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
struct iterator_end
|
||||
{};
|
||||
|
||||
template<typename Iter>
|
||||
class iterator
|
||||
{
|
||||
using step_type = decltype(to_std(::std::declval<Iter>().next()));
|
||||
|
||||
Iter rs;
|
||||
step_type current;
|
||||
|
||||
public:
|
||||
using iterator_category = ::std::input_iterator_tag;
|
||||
using difference_type = void;
|
||||
using value_type = step_type::value_type;
|
||||
using reference = value_type &;
|
||||
using pointer = value_type *;
|
||||
|
||||
explicit iterator(Iter rs) : rs(::std::move(rs))
|
||||
{
|
||||
++*this;
|
||||
}
|
||||
|
||||
pointer operator->()
|
||||
{
|
||||
return &*current;
|
||||
}
|
||||
reference operator*()
|
||||
{
|
||||
return *current;
|
||||
}
|
||||
|
||||
iterator & operator++()
|
||||
{
|
||||
current = to_std(rs.next());
|
||||
return *this;
|
||||
}
|
||||
|
||||
void operator++(int)
|
||||
{
|
||||
++*this;
|
||||
}
|
||||
|
||||
bool operator==(iterator_end) const
|
||||
{
|
||||
return !current.has_value();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
@@ -245,7 +312,17 @@ concept HasOpEq = requires(Lhs lhs, Rhs rhs) {
|
||||
template<typename Lhs, typename Rhs> requires ::rust::HasOpEq<Lhs, Rhs> \
|
||||
bool operator!=(const Lhs & lhs, const Rhs & rhs) { return !bool(lhs.eq(rhs)); } \
|
||||
}
|
||||
#define LIX_DECLARE_ITERATORS(ns) \
|
||||
namespace ns { \
|
||||
template<::rust::Iterator T> \
|
||||
auto begin(T & rs) { return ::rust::detail::iterator{::std::move(rs)}; } \
|
||||
template<::rust::Iterator T> \
|
||||
auto end(const T & rs) { return ::rust::detail::iterator_end{}; } \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
LIX_DECLARE_ORD_OPS(rust::lix::ffi_test)
|
||||
LIX_DECLARE_EQ_OPS(rust::lix::ffi_test)
|
||||
|
||||
LIX_DECLARE_ITERATORS(rust::std::slice)
|
||||
LIX_DECLARE_ITERATORS(rust::std::vec)
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include <cstdint>
|
||||
#include <gtest/gtest.h>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace nix {
|
||||
|
||||
@@ -122,4 +124,30 @@ TEST(rustSupport, testOperators)
|
||||
|
||||
ASSERT_EQ(set.size(), 1);
|
||||
}
|
||||
|
||||
TEST(rustSupport, iterators)
|
||||
{
|
||||
auto vec = rust::Vec<uint8_t>::new_();
|
||||
vec.push(1);
|
||||
vec.push(2);
|
||||
vec.push(3);
|
||||
vec.push(4);
|
||||
vec.push(5);
|
||||
|
||||
int i = 0;
|
||||
for (auto u : vec.as_ref().iter()) {
|
||||
EXPECT_EQ(*u, ++i);
|
||||
}
|
||||
for (auto u : vec.as_mut().iter_mut()) {
|
||||
(*u)++;
|
||||
}
|
||||
i = 1;
|
||||
for (auto u : vec.as_ref().iter()) {
|
||||
EXPECT_EQ(*u, ++i);
|
||||
}
|
||||
i = 1;
|
||||
for (auto u : vec.into_iter()) {
|
||||
EXPECT_EQ(u, ++i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user