lix-rs: allow exposing ord/eq operators from rust

this is a bit of a hack, but since zngur cannot handle multiple trait
implementations per type yet we will have to commit to singles types.

Change-Id: I60e7b96bbeaa9fb87cf43662d4a9a5d44116bf47
This commit is contained in:
eldritch horrors
2026-07-08 18:04:40 +00:00
parent 9302845601
commit dd8f1843cc
4 changed files with 95 additions and 3 deletions
+3 -2
View File
@@ -2,10 +2,11 @@ use std::{error::Error, io};
use crate::ffi;
#[derive(Clone, Copy)]
#[derive(Clone, Copy, PartialEq, PartialOrd)]
pub struct TestMultiplyAddLenArgs {
pub a: u64,
pub b: u64,
pub c: Option<u64>,
}
pub trait SetB {
@@ -20,7 +21,7 @@ impl SetB for TestMultiplyAddLenArgs {
impl TestMultiplyAddLenArgs {
pub fn new(a: u64, b: u64) -> Self {
Self { a, b }
Self { a, b, c: None }
}
}
+8 -1
View File
@@ -6,14 +6,21 @@ use ::std::vec::Vec as Vec;
mod crate::ffi_test {
type TestMultiplyAddLenArgs {
#layout_conservative(size = 16, align = 8);
#layout_conservative(size = 32, align = 8);
wellknown_traits(Copy);
field a (offset = auto, type = u64);
field b (offset = auto, type = u64);
field c (offset = auto, type = Option<u64>);
fn new(u64, u64) -> TestMultiplyAddLenArgs;
fn set_b(&mut self, u64) use SetB;
fn clone(&self) -> TestMultiplyAddLenArgs;
fn eq(&self, &TestMultiplyAddLenArgs) -> bool use ::std::cmp::PartialEq;
fn lt(&self, &TestMultiplyAddLenArgs) -> bool use ::std::cmp::PartialOrd;
fn le(&self, &TestMultiplyAddLenArgs) -> bool use ::std::cmp::PartialOrd;
}
fn test_multiply_add_len(TestMultiplyAddLenArgs, &Vec<String>) -> (String, u64);
+49
View File
@@ -2,6 +2,8 @@
///@file convenience utilities for working with the rust ffi bits
#include <cassert>
#include <concepts>
#include <cstdint>
#include <exception>
#include <optional>
#include <string_view>
@@ -200,3 +202,50 @@ auto to_std(Option<Args...> r)
namespace nix {
using namespace rust::lix;
}
namespace rust {
template<typename Lhs, typename Rhs>
concept HasOpLt = requires(Lhs lhs, Rhs rhs) {
lhs.lt(rhs);
Ref<::std::remove_cvref_t<Lhs>>{};
Ref<::std::remove_cvref_t<Rhs>>{};
};
template<typename Lhs, typename Rhs>
concept HasOpLe = requires(Lhs lhs, Rhs rhs) {
lhs.le(rhs);
Ref<::std::remove_cvref_t<Lhs>>{};
Ref<::std::remove_cvref_t<Rhs>>{};
};
template<typename Lhs, typename Rhs>
concept HasOpEq = requires(Lhs lhs, Rhs rhs) {
lhs.eq(rhs);
Ref<::std::remove_cvref_t<Lhs>>{};
Ref<::std::remove_cvref_t<Rhs>>{};
};
}
// clang-format off
#define LIX_DECLARE_ORD_OPS(ns) \
namespace ns { \
template<typename Lhs, typename Rhs> requires ::rust::HasOpLt<Lhs, Rhs> \
bool operator<(const Lhs & lhs, const Rhs & rhs) { return bool(lhs.lt(rhs)); } \
template<typename Lhs, typename Rhs> requires ::rust::HasOpLe<Lhs, Rhs> \
bool operator<=(const Lhs & lhs, const Rhs & rhs) { return bool(lhs.le(rhs)); } \
template<typename Lhs, typename Rhs> requires ::rust::HasOpLt<Lhs, Rhs> \
bool operator>(const Lhs & lhs, const Rhs & rhs) { return bool(rhs.lt(lhs)); } \
template<typename Lhs, typename Rhs> requires ::rust::HasOpLe<Lhs, Rhs> \
bool operator>=(const Lhs & lhs, const Rhs & rhs) { return bool(rhs.le(lhs)); } \
}
#define LIX_DECLARE_EQ_OPS(ns) \
namespace ns { \
template<typename Lhs, typename Rhs> requires ::rust::HasOpEq<Lhs, Rhs> \
bool operator==(const Lhs & lhs, const Rhs & rhs) { return bool(lhs.eq(rhs)); } \
template<typename Lhs, typename Rhs> requires ::rust::HasOpEq<Lhs, Rhs> \
bool operator!=(const Lhs & lhs, const Rhs & rhs) { return !bool(lhs.eq(rhs)); } \
}
// clang-format on
LIX_DECLARE_ORD_OPS(rust::lix::ffi_test)
LIX_DECLARE_EQ_OPS(rust::lix::ffi_test)
+35
View File
@@ -87,4 +87,39 @@ TEST(rustSupport, testResultFromCxx)
result = test_exceptions(make_box_fn([] {}));
ASSERT_EQ(to_std_string(result), "");
}
TEST(rustSupport, testOperators)
{
using rust::lix::ffi_test::TestMultiplyAddLenArgs;
auto args1 = TestMultiplyAddLenArgs::new_(1, 2);
auto args2 = TestMultiplyAddLenArgs::new_(1, 3);
ASSERT_LT(args1, args2);
ASSERT_LE(args1, args1);
ASSERT_LE(args1, args2);
ASSERT_GT(args2, args1);
ASSERT_GE(args1, args1);
ASSERT_GE(args2, args1);
ASSERT_EQ(args1, args1);
ASSERT_NE(args1, args2);
std::map<TestMultiplyAddLenArgs, int> map{{args2, 2}, {args1, 1}};
ASSERT_EQ(map.begin()->first, args1);
ASSERT_EQ(map.begin()->second, 1);
ASSERT_EQ(map.rbegin()->first, args2);
ASSERT_EQ(map.rbegin()->second, 2);
std::set<TestMultiplyAddLenArgs> set;
set.emplace(args1);
set.emplace(args1);
set.emplace(args1);
set.emplace(args1);
ASSERT_EQ(set.size(), 1);
}
}