From dd8f1843cc0a38ab3d38a7c0652ce771536df2a7 Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Mon, 6 Jul 2026 15:57:00 +0200 Subject: [PATCH] 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 --- lix/lix-rs/src/ffi_test.rs | 5 ++-- lix/lix-rs/src/ffi_test.zng | 9 ++++++- lix/lix-rs/utils.hh | 49 +++++++++++++++++++++++++++++++++++++ tests/unit/libutil/rust.cc | 35 ++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 3 deletions(-) diff --git a/lix/lix-rs/src/ffi_test.rs b/lix/lix-rs/src/ffi_test.rs index f352c590d..babf7acd0 100644 --- a/lix/lix-rs/src/ffi_test.rs +++ b/lix/lix-rs/src/ffi_test.rs @@ -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, } 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 } } } diff --git a/lix/lix-rs/src/ffi_test.zng b/lix/lix-rs/src/ffi_test.zng index 3fc19266e..4459e5677 100644 --- a/lix/lix-rs/src/ffi_test.zng +++ b/lix/lix-rs/src/ffi_test.zng @@ -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); 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, u64); diff --git a/lix/lix-rs/utils.hh b/lix/lix-rs/utils.hh index db7e4d45f..aba139821 100644 --- a/lix/lix-rs/utils.hh +++ b/lix/lix-rs/utils.hh @@ -2,6 +2,8 @@ ///@file convenience utilities for working with the rust ffi bits #include +#include +#include #include #include #include @@ -200,3 +202,50 @@ auto to_std(Option r) namespace nix { using namespace rust::lix; } + +namespace rust { +template +concept HasOpLt = requires(Lhs lhs, Rhs rhs) { + lhs.lt(rhs); + Ref<::std::remove_cvref_t>{}; + Ref<::std::remove_cvref_t>{}; +}; + +template +concept HasOpLe = requires(Lhs lhs, Rhs rhs) { + lhs.le(rhs); + Ref<::std::remove_cvref_t>{}; + Ref<::std::remove_cvref_t>{}; +}; + +template +concept HasOpEq = requires(Lhs lhs, Rhs rhs) { + lhs.eq(rhs); + Ref<::std::remove_cvref_t>{}; + Ref<::std::remove_cvref_t>{}; +}; +} + +// clang-format off +#define LIX_DECLARE_ORD_OPS(ns) \ + namespace ns { \ + template requires ::rust::HasOpLt \ + bool operator<(const Lhs & lhs, const Rhs & rhs) { return bool(lhs.lt(rhs)); } \ + template requires ::rust::HasOpLe \ + bool operator<=(const Lhs & lhs, const Rhs & rhs) { return bool(lhs.le(rhs)); } \ + template requires ::rust::HasOpLt \ + bool operator>(const Lhs & lhs, const Rhs & rhs) { return bool(rhs.lt(lhs)); } \ + template requires ::rust::HasOpLe \ + bool operator>=(const Lhs & lhs, const Rhs & rhs) { return bool(rhs.le(lhs)); } \ + } +#define LIX_DECLARE_EQ_OPS(ns) \ + namespace ns { \ + template requires ::rust::HasOpEq \ + bool operator==(const Lhs & lhs, const Rhs & rhs) { return bool(lhs.eq(rhs)); } \ + template requires ::rust::HasOpEq \ + 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) diff --git a/tests/unit/libutil/rust.cc b/tests/unit/libutil/rust.cc index 8815a811f..ed7db9e1e 100644 --- a/tests/unit/libutil/rust.cc +++ b/tests/unit/libutil/rust.cc @@ -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 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 set; + + set.emplace(args1); + set.emplace(args1); + set.emplace(args1); + set.emplace(args1); + + ASSERT_EQ(set.size(), 1); +} }