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:
eldritch horrors
2026-07-17 09:56:35 +00:00
committed by Rutile
parent f91bdc9367
commit 4c4d8b8ccd
4 changed files with 166 additions and 0 deletions
+3
View File
@@ -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 {
+58
View File
@@ -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>;
}
}
+77
View File
@@ -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)
+28
View File
@@ -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);
}
}
}