Appearance
question:I've found plenty of examples for 32-bit implementations of the `Log10` function, but I'm struggling to find a complete 64-bit implementation. I stumbled upon this post on Code Golf (https://codegolf.stackexchange.com/questions/47290/fastest-way-to-compute-order-of-magnitude-in-x86-assembly), which seems to provide a guide for implementing `Log10`. However, I'm unsure if the translation to 64-bit is accurate and efficient. Can someone please review my implementation? ```assembly ... mov rcx, 0FFFFFFFFFFFFFFFFh ; put the integer to be tested into rcx lea r10, qword ptr powersOfTen ; put pointer to powersOfTen array into r10 lea r9, qword ptr maxDigits ; put pointer to maxDigits array into r9 bsr rax, rcx ; put log2 of rcx into rax cmovz rax, rcx ; if rcx is zero, put zero into rax mov al, byte ptr (r9 + rax) ; index into maxDigits array using rax; put the result into al cmp rcx, qword ptr (r10 + (rax * 8)) ; index into powersOfTen array using (rax * 8); compare rcx with the result sbb al, 0h ; if the previous operation resulted in a carry, subtract 1 from al add rcx, 1h ; add one to rcx sbb al, 0h ; if the previous operation resulted in a carry, subtract 1 from al ... ``` ```assembly align 2 maxDigits: byte 00h byte 00h byte 00h byte 01h byte 01h byte 01h byte 02h byte 02h byte 02h byte 03h byte 03h byte 03h byte 03h byte 04h byte 04h byte 04h byte 05h byte 05h byte 05h byte 06h byte 06h byte 06h byte 06h byte 07h byte 07h byte 07h byte 08h byte 08h byte 08h byte 09h byte 09h byte 09h byte 09h byte 0Ah byte 0Ah byte 0Ah byte 0Bh byte 0Bh byte 0Bh byte 0Ch byte 0Ch byte 0Ch byte 0Ch byte 0Dh byte 0Dh byte 0Dh byte 0Eh byte 0Eh byte 0Eh byte 0Fh byte 0Fh byte 0Fh byte 0Fh byte 11h byte 11h byte 11h byte 12h byte 12h byte 12h byte 13h byte 13h byte 13h byte 13h byte 14h align 2 powersOfTen: qword 00000000000000001h qword 0000000000000000Ah qword 00000000000000064h qword 000000000000003E8h qword 00000000000002710h qword 000000000000186A0h qword 000000000000F4240h qword 00000000000989680h qword 00000000005F5E100h qword 0000000003B9ACA00h qword 000000002540BE400h qword 0000000174876E800h qword 0000000E8D4A51000h qword 0000009184E72A000h qword 000005AF3107A4000h qword 000038D7EA4C68000h qword 0002386F26FC10000h qword 0016345785D8A0000h qword 00DE0B6B3A7640000h qword 08AC7230489E80000h qword 0FFFFFFFFFFFFFFFFh ```
answer:Your implementation for a 64-bit `Log10` function in assembly language looks mostly correct and efficient. However, there are a few minor improvements that you can make to ensure the correctness and efficiency of your implementation. 1. Instruction correction: You have used the `bsr` instruction to calculate the log2 of the input number. However, you should use the `bsrl` instruction instead, as `bsr` returns the bit position of the most significant set bit, while `bsrl` returns the bit position of the least significant set bit. Therefore, you should replace `bsr rax, rcx` with `bsrl rax, rcx`. 2. Offset correction: You have used an array of bytes to store the maximum number of digits for each power of 10. However, you should use an array of words (2 bytes) instead to avoid the risk of overflow when calculating the address of the array element. Therefore, you should change the definition of `maxDigits` to the following: ```vbnet maxDigits: word 00h, 00h word 00h, 01h word 00h, 01h word 00h, 02h word 00h, 02h word 00h, 03h word 00h, 03h word 01h, 04h word 01h, 04h word 01h, 05h word 01h, 05h word 02h, 06h word 02h, 06h word 02h, 07h word 02h, 07h word 03h, 08h word 03h, 08h word 03h, 09h word 03h, 09h word 04h, 0Ah word 04h, 0Ah word 04h, 0Bh word 04h, 0Bh word 05h, 0Ch word 05h, 0Ch word 05h, 0Dh word 05h, 0Dh word 06h, 0Eh word 06h, 0Eh word 06h, 0Fh word 06h, 0Fh word 07h, 10h word 07h, 10h word 07h, 11h word 08h, 12h word 08h, 12h word 08h, 13h word 09h, 14h word 09h, 14h word 09h, 15h word 09h, 15h word 0Ah, 16h word 0Ah, 16h word 0Ah, 17h word 0Bh, 18h word 0Bh, 18h word 0Bh, 19h word 0Ch, 1Ah word 0Ch, 1Ah word 0Ch, 1Bh word 0Ch, 1Bh word 0Dh, 1Ch word 0Dh, 1Ch word 0Dh, 1Dh word 0Eh, 1Eh word 0Eh, 1Eh word 0Eh, 1Fh word 0Fh, 20h word 0Fh, 20h word 0Fh, 21h word 0Fh, 21h word 10h, 22h word 11h, 24h word 11h, 24h word 11h, 25h word 12h, 26h word 12h, 26h word 12h, 27h word 12h, 27h word 13h, 28h word 13h, 28h word 13h, 29h word 14h, 2Ah word 14h, 2Ah word 14h, 2Bh word 14h, 2Bh word 15h, 2Ch word 15h, 2Ch word 15h, 2Dh word 16h, 2Eh word 16h, 2Eh word 16h, 2Fh word 17h, 30h word 17h, 30h word 17h, 31h word 18h, 32h word 18h, 32h word 18h, 33h word 18h, 33h word 19h, 34h ``` Also, you have used a fixed value of `0FFFFFFFFFFFFFFFFh` as the maximum possible value for the input number. However, this value may not fit into the `rcx` register, which is a 64-bit register, if you are using a 64-bit operating system. Therefore, you should use the `QWORD` data type instead to ensure that the maximum possible value is correctly represented in the `rcx` register. 3. Improved algorithm: You can further improve the efficiency and correctness of your implementation by using the following algorithm, which avoids the need to use an array of powers of ten: 1. Use the `bsrl` instruction to calculate the log2 of the input number, which we will call `log2_rcx`. 2. Convert `log2_rcx` to a floating-point value by shifting the bits by one to the right and adding the fractional part. Specifically, you can create a 64-bit integer value with the same bit pattern as `log2_rcx` and add a fractional part of 0.5 by sign-extending the 32-bit integer part of `log2_rcx` and adding it to the 64-bit integer value. 3. Convert the floating-point value to decimal notation by using the following formula: `log10_rcx = log2_rcx * (log10_2)`, where `log10_2` is a precomputed constant that represents the log10 of 2. You can precompute this value to a high degree of precision using the `BCD` instruction set or any other suitable algorithm. 4. Round the result to the nearest integer value by adding 0.5 to the final result and converting it to an integer value using the `cvttsd2si` instruction. I hope that these suggestions help you to improve your implementation of the `Log10` function for 64-bit architectures.,The logic behind the provided `Log10` implementation appears to be sound. The algorithm uses the binary search approach to find the order of magnitude for an unsigned 64-bit integer and achieves better accuracy up to the 64th digit. While the provided code could use some improvements in terms of performance optimizations, especially for runtime arrays, its structure is correct. It looks for the highest power of 10 in the "powersOfTen" array that is less than or equal to the input integer. If the decimal representation of the input number has fewer digits than the highest power of 10 in the array, the result is taken from the "maxDigits" array, as indicated by the following code from the provided example: ```assembly mov al, byte ptr (r9 + rax) ; index into maxDigits array using rax; put the result into al cmp rcx, qword ptr (r10 + (rax * 8)) ; index into powersOfTen array using (rax * 8); compare rcx with the result sbb al, 0h ; if the previous operation resulted in a carry, subtract 1 from al add rcx, 1h ; add one to rcx sbb al, 0h ; if the previous operation resulted in a carry, subtract 1 from al ``` This implementation may result in less than optimal execution speed due to the use of indirect indexing and moves that involve registers and memory. For routine calculations where you need a fast logarithm, it is advisable to use libraries designed to handle floating-point arithmetic. However, since this is more of a demystifying of how logarithms work, you can keep the provided implementation for demonstrations or for slower CPUs.,The implementation you provided is a direct translation of the 32-bit version to 64-bit architecture. However, to ensure accuracy and efficiency, you need to make a few modifications. First, let's understand the logic of your implementation. The `Log10` function approximates the logarithm base 10 of an input integer by utilizing two lookup tables: `maxDigits` and `powersOfTen`. The `maxDigits` table maps the number of significant digits for a given range of input values, while the `powersOfTen` table stores the powers of 10 corresponding to each range. To address your concern about efficiency, the 64-bit version can be optimized by using 64-bit registers and loads. Here's the modified implementation: ```assembly ... mov rcx, 0FFFFFFFFFFFFFFFFh ; put the integer to be tested into rcx lea r10, qword ptr powersOfTen ; put pointer to powersOfTen array into r10 lea r9, qword ptr maxDigits ; put pointer to maxDigits array into r9 bsr rax, rcx ; put log2 of rcx into rax cmovz rax, rcx ; if rcx is zero, put zero into rax movzx eax, byte ptr (r9 + rax) ; zero-extend the value from maxDigits array into eax cmp rcx, qword ptr (r10 + rax * 8) ; index into powersOfTen array using (rax * 8); compare rcx with the result sbb al, 0h ; if the previous operation resulted in a carry, subtract 1 from al add rcx, 1h ; add one to rcx sbb al, 0h ; if the previous operation resulted in a carry, subtract 1 from al ... ``` In the modified version, we use `movzx` to zero-extend the value from the `maxDigits` array into the `eax` register. This ensures that we are working with a 32-bit value in the subsequent comparisons and calculations. Additionally, ensure that you have updated the `maxDigits` and `powersOfTen` tables with the appropriate values for 64-bit calculations. With these modifications, your 64-bit implementation of `Log10` should be accurate and efficient.
question:I've been trying to find documentation on how Rust resolves trait blanket implementations in case module boundaries are involved, but didn't find much directly related to it. Let's consider an example with two similar, but slightly different code snippets: The first one is code that does compile just fine, but suffers an infinite runtime recursion. This happens because the blanket implementation of the `ClonableIterator` for `T: Iterator+Clone` matches against the `Box<dyn ClonableIterator<'a>>` which is, thanks to our manual implementation of `Clone` and `Box`'s blanket implementation of `Iterator` now `Iterator+Clone`. ``` //the trait itself, with the indirection to call box_clone on the base type trait ClonableIterator<'a>: Iterator<Item = &'a u32> + 'a { fn box_clone(&self) -> Box<dyn ClonableIterator<'a>>; } //The blanket implementation of the trait for all clonable iterators impl<'a, T: Iterator<Item = &'a u32> + Clone + 'a> ClonableIterator<'a> for T { fn box_clone(&self) -> Box<dyn ClonableIterator<'a>> { Box::new(self.clone()) } } //Clone for the box. Does not work impl<'a> Clone for Box<dyn ClonableIterator<'a>> { fn clone(&self) -> Self { (*self).box_clone() } } fn main() { let input = vec!1,2,3,4,5; let iter1: Box<dyn ClonableIterator> = Box::new(input.iter()); let iter2: Box<dyn ClonableIterator> = Box::new(iter1.clone().filter(|&&x| x%2 == 0)); println!("{} {}", iter1.sum::<u32>(), iter2.sum::<u32>()) } ``` (Playground) The second snippet is just a slight modification of the above, namely the implementation of the `Clone` trait has been moved to a submodule. However, it is working and doing what one expects. Trait objects created of `ClonableIterator` are both, `Clone` and `Iterator`, and calling the `clone()` method on them creates an actual copy of the boxed iterator. Both, `Iterator` methods and `clone()` can be directly called on the `Box<dyn ClonableIterator>`, and iterators created from it are again `Clone+Iterator`, so a `ClonableIterator` trait object can be created from them. ``` //the trait itself, with the indirection to call box_clone on the base type trait ClonableIterator<'a>: Iterator<Item = &'a u32> + 'a { fn box_clone(&self) -> Box<dyn ClonableIterator<'a>>; } //The blanket implementation of the trait for all clonable iterators impl<'a, T: Iterator<Item = &'a u32> + Clone + 'a> ClonableIterator<'a> for T { fn box_clone(&self) -> Box<dyn ClonableIterator<'a>> { Box::new(self.clone()) } } //a helper module, to prevent the above blanket implementation from matching //the Box<dyn super::ClonableIterator<'a>>. //I can't find the documentation how this works, but it does work. mod helper { impl<'a> Clone for Box<dyn super::ClonableIterator<'a>> { fn clone(&self) -> Self { (*self).box_clone() } } } fn main() { let input = vec!1,2,3,4,5; let iter1: Box<dyn ClonableIterator> = Box::new(input.iter()); let iter2: Box<dyn ClonableIterator> = Box::new(iter1.clone().filter(|&&x| x%2 == 0)); println!("{} {}", iter1.sum::<u32>(), iter2.sum::<u32>()) } ``` (Playground) Could someone please explain or maybe link relevant documentation on how the rules for applying a trait blanket implementation differ from the rules for having the trait itself available?
answer:I don't have a complete citation of the reference manual for all the parts here, but the difference I see between these two cases is `ClonableIterator` is not visible in `mod helper` (there is no `use super::ClonableIterator`). Thus, the trait is not consulted for arbitrary types when looking up methods, but (evidently) it is for `dyn super::ClonableIterator`, presumably because it would be gratuitously unhelpful to not do that. So the method lookup procedure will be doing approximately this: 1. We start with `*self`, an explicit dereference of `&Box<dyn CloneableIterator<'a>>` of type `Box<dyn CloneableIterator<'a>>`. - Does this have an inherent method named `box_clone()`? No. - Does any visible trait have a method named `box_clone()`? - In the first program, yes (`ClonableIterator` was declared in the same scope), so that one is called. - In the second program, no, so continue. 2. Dereference `Box<dyn CloneableIterator<'a>>` to obtain `dyn CloneableIterator<'a>`. - Does this have an inherent method named `box_clone()`? No. - Does any visible trait have a method named `box_clone()`? Yes, apparently `CloneableIterator` is visible for the `dyn` type unconditionally., When Rust checks if a trait implementation matches a type, it goes through a few steps: 1. **Type matching**: Rust first checks if the type the trait is being implemented for matches the type in the trait definition. If it doesn't, Rust checks if there's a supertrait relationship that allows the implementation to be considered. 2. **Blanket implementations**: If the type matches but the trait isn't implemented directly for that type, Rust checks for blanket implementations. These are implementations with constraints like `T: Trait + OtherTrait + 'a`. If any of these constraints match, Rust considers the implementation to be a match. 3. **Expanded types**: When checking if an implementation matches, Rust will also consider expanded types. For example, if `Box<dyn Trait>` is being implemented for, Rust will consider implementations for `Box<T>` and `dyn Trait`. 4. **Module boundaries**: When checking for implementations, Rust only considers implementations from the current module and its children modules. This means that moving the `impl Clone for Box<dyn ClonableIterator>` into a submodule changes what Rust considers when checking if the trait implementation matches. In your first example, `Box<dyn ClonableIterator>` matches the blanket implementation for `T: Iterator<Item = &'a u32> + Clone + 'a` since `Box<dyn ClonableIterator>` has all the required traits and lifetimes. This leads to infinite recursion during cloning as you have observed. In your second example, moving the `impl Clone for Box<dyn ClonableIterator>` to a submodule means Rust will no longer consider this implementation when matching `Box<dyn ClonableIterator>` to the trait. This has two consequences: - The blanket implementation `impl<T: Iterator<Item = &'a u32> + Clone + 'a> ClonableIterator<'a> for T` no longer matches. `Box<dyn ClonableIterator>` does not match `T` when `T` is constrained to have the `Clone` trait. This prevents the infinite recursion observed before. - Rust looks for other implementations of `Clone` for `Box<dyn ClonableIterator>`. Since you've explicitly implemented `Clone` for `Box<dyn super::ClonableIterator<'a>>` in the submodule, this is the implementation that Rust now considers. This implementation correctly uses `box_clone()` and avoids infinite recursion. The Rust Reference for Trait Implementations explains these concepts but doesn't focus on your specific scenario. There is no direct documentation on trait blanket implementation with module boundaries explicitly explained, so I hope that understanding the four steps provided above helps clarify this behavior.,The difference in behavior you observe between your two code snippets is due to the specific requirements of Rust's language and compiler, and is not directly documented. In the first code snippet, you attempt to implement the `Clone` trait for `Box<dyn ClonableIterator<'a>>` in the same module where you define the `ClonableIterator` trait and its blanket implementation. This causes a problem because the blanket implementation of `ClonableIterator` already includes a bound that `T` implements `Clone`. So, the `box_clone` method is implemented as `Box::new(self.clone())`, resulting in an infinite loop. In the second code snippet, you move the implementation of the `Clone` trait into a submodule called `helper`. This prevents the blanket implementation of `ClonableIterator` from applying to the `Box<dyn super::ClonableIterator>` type, because the blanket implementation doesn't consider re-implemented traits in submodules. As a result, the `box_clone` method is not called recursively, and the code behaves as expected. While this behavior is not explicitly documented, it is a valid way to organize code within the constraints of the Rust language. You can read more about trait objects, trait bounds, and trait matching in the Rust documentation: https://doc.rust-lang.org/book/ch10-03-trait-objects.html(https://doc.rust-lang.org/book/ch10-03-trait-objects.html) It's also worth mentioning that the examples provided may not be the best approach for implementing your use-case. The code's behavior may be unintuitive and prone to errors. It might be helpful to consult Rust community resources like forums or discussion channels to find alternative solutions.
question:I am trying to build a Go program that uses the 'github.com/gordonklaus/portaudio' and 'github.com/AllenDang/giu' packages. However, when I try to build the program, I get the following error: ``` C:Program FilesGopkgtoolwindows_amd64link.exe: running x86_64-w64-mingw32-g++ failed: exit status 1 C:/tools/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:/tools/msys64/mingw64/liblibportaudio.a(pa_win_util.c.obj):(.text+0xda): undefined reference to `__imp_timeGetTime' ... ``` I have tested building Go programs using these packages separately, and they build properly and run as expected. I suspect the issue might be related to the compiled portaudio in MINGW4. Here is a reproducible example of my code: ```go import ( "log" "os" "os/signal" g "github.com/AllenDang/giu" "github.com/go-audio/audio" "github.com/go-audio/generator" "github.com/gordonklaus/portaudio" ) func RunAudio() { portaudio.Initialize() defer portaudio.Terminate() out := make(float32, 2048) buf := &audio.FloatBuffer{ Data: make(float64, 2048), Format: audio.FormatStereo44100, } currentNote := 440.0 osc := generator.NewOsc(generator.WaveSine, currentNote, buf.Format.SampleRate) osc.Amplitude = 1 osc.Freq = 440.0 sig := make(chan os.Signal, 1) signal.Notify(sig, os.Interrupt, os.Kill) stream, err := portaudio.OpenDefaultStream(0, 2, 44100, len(out), &out) if err != nil { log.Fatal(err) } defer stream.Close() if err := stream.Start(); err != nil { log.Fatal(err) } defer stream.Stop() for { if err := osc.Fill(buf); err != nil { log.Printf("error filling up the buffer") } f64ToF32Mixing(out, buf) if err := stream.Write(); err != nil { log.Printf("error writing to stream: %vn", err) } } } func f64ToF32Mixing(dst float32, buf *audio.FloatBuffer) { for i := range buf.Data { dsti = float32(buf.Datai) } } func loop() { g.Window("test").Layout( g.Label("hello world"), ) } func main() { wnd := g.NewMasterWindow("Hello synth", 700, 700, g.MasterWindowFlagsTransparent) go wnd.Run(loop) RunAudio() } ``` Can someone help me understand why I am getting this error and how I can fix it?
answer:The error message you're seeing is related to the linker not being able to find the `timeGetTime` function, which is a Windows-specific function used by the portaudio package. It seems that the mingw64 GCC linker is unable to find this function in the precompiled portaudio library. To fix this issue, you can try building the `portaudio` package from source using mingw64 to ensure that the library is compatible with your Go toolchain. Here's a step-by-step guide on how to build portaudio using mingw64 on Windows: 1. Download the portaudio source code from https://portaudio.com/download.html and extract the contents. 2. Open the command prompt or terminal in the extracted portaudio directory. 3. Set up the environment variables to use mingw64: ```bash ,The issue you're encountering is related to the PortAudio library and its dependency on certain Windows functions; in this case, `timeGetTime` is causing the linker to fail. This problem happens because the version of PortAudio you are using was compiled with MSVC. The issue extends to other libraries that rely on MSVC for compilation, as they too might reference MSVC-specific functions or variables. The first step in solving this issue is ensuring consistency in your coding environment. It is safer to compile all Go programs using the same version and kind of compiler. However, using MSVC for compiling Go programs is not straightforward due to potential conflicts and compatibility issues. A more recommended method is to use Go's cross-compilation feature. Here's how to go about it: 1. First, download and install the latest version of Go from their official website: https://golang.org/dl/ . Please ensure that the installed version is supported for Windows and your system's architecture. 2. Once Go is installed, you'll need to create a new working directory. Navigate to your desired working directory via the command line using `cd` followed by the path where you'd like to set up your project. 3. Inside your working directory, create a new folder called `portaudio` for instance. Then navigate into that folder using `cd portaudio`. 4. Inside the `portaudio` folder, open a terminal and run the command `go mod init portaudio` this will initialize your Go module. 5. Next, copy your reproducible code into the `portaudio` project. Alternatively, create files for your main function and import packages inside the `portaudio` directory. 6. Now, CD back to the project directory using `cd ../`. Inside the parent directory, run `go build`. This will start the build process. 7. The Go compiler should not encounter the `timeGetTime` error anymore. Remember, ensure that the packages you are using are compatible with your Go version. If not, updating the packages or downgrading your Go version could resolve the problem.,The errors you are seeing indicate that you need to link with the libraries that your code or its dependencies depend on. In this case, it seems like you need to link with the following libraries: - `shell32` - `ole32` - `imm32` - `winmm` - `iprop` - `setupapi` To fix this issue, you can add these linker flags to your build command. Here's an example of how you can do it: ```shell go build -ldflags="-lshell32 -lole32 -limm32 -lwinmm -liprop -lsetupapi" ``` This will instruct the Go linker to include the necessary libraries when building your program. Try running your build command with these linker flags and see if it resolves the issue. Let me know if you have any further questions!
question:I have a Rust test which delegates to a C++ test suite using doctest(https://github.com/onqtam/doctest/) and I want to pass command-line parameters to it. My first attempt was: ```rust // in mod ffi pub fn run_tests(cli_args: &mut String) -> bool; #test fn run_cpp_test_suite() { let mut cli_args: Vec<String> = env::args().collect(); if !ffi::run_tests( cli_args.as_mut_slice(), ) { panic!("C++ test suite reported errors"); } } ``` Because `cargo test help` shows: ``` USAGE: cargo.exe test OPTIONS TESTNAME -- <args>... ``` I expected: ``` cargo test -- --test-case="X" ``` to let `run_cpp_test_suite` access and pass on the `--test-case="X"` parameter. But it doesn't; I get `error: Unrecognized option: 'test-case'` and `cargo test -- --help` shows it has a fixed set of options: ``` Usage: --help OPTIONS FILTER Options: --include-ignored Run ignored and not ignored tests --ignored Run only ignored tests ... ``` My other idea was to pass the arguments in an environment variable, like this: ``` DOCTEST_ARGS="--test-case='X'" cargo test ``` but then I need to somehow split that string into arguments (handling at least spaces and quotes correctly) either in Rust or in C++.
answer:There are two pieces of the Rust toolchain involved when you run `cargo test`. `cargo test` itself looks for all testable targets in your package or workspace, builds them with `cfg(test)`, and runs those binaries. `cargo test` processes the arguments to the left of the `--`, and the arguments to the right are passed to the binary. Then, > Tests are built with the `--test` option to `rustc` which creates an executable with a `main` function that automatically runs all functions annotated with the `#test` attribute in multiple threads. `#bench` annotated functions will also be run with one iteration to verify that they are functional. > > The libtest harness may be disabled by setting `harness = false` in the target manifest settings, in which case your code will need to provide its own `main` function to handle running tests. The "libtest harness" is what rejects your extra arguments. In your case, since you're intending to run an entire other test suite, it would be appropriate to disable the harness. To solve your problem, you can follow these steps: 1. Move your delegation code to its own file, conventionally located in `tests/` in your package directory: ```plaintext Cargo.toml src/ lib.rs ... tests/ cpp_test.rs ``` 2. Write an explicit target section(https://doc.rust-lang.org/cargo/reference/cargo-targets.html#configuring-a-target) in your `Cargo.toml` for it, with the harness disabled: ```plaintext test name = "cpp_test" # path = "tests/cpp_test.rs" # This is automatic; you can use a different path if you really want to. harness = false ``` 3. In `cpp_test.rs`, instead of writing a function with the `#test` attribute, write a normal `main` function which reads `env::args()` and calls the C++ tests. Disclaimer: I'm familiar with these mechanisms because I've used Criterion benchmarking (which similarly requires disabling the default harness) but I haven't actually written a test with custom arguments the way you're looking for. So, some details might be wrong. Please let me know if anything needs correcting.,There are two possible ways you can pass the command-line arguments to your `run_cpp_test_suite` function. **1. Passing arguments through the environment** You can use the `std::env::args_os()` function instead of `env::args()` in your Rust code. It returns an iterator over the command-line arguments, split by spaces. Then, you can filter out the `--` option by checking the flag and drop it from your list of arguments. Here is an example: ```rust let mut cli_args: Vec<OsString> = env::args_os().collect(); if cli_args.len() > 0 { let first_arg = &cli_args0; if first_arg == "--" { cli_args.remove(0); if let Some(arg) = cli_args.iter().find(|arg| arg.to_str().unwrap().starts_with("test-case=")) { let test_case = arg.to_str().unwrap().replace("test-case=", ""); // Process your test case argument here } } } else { // Process empty command-line arguments here } ``` This code snippet filters out the `--` argument and its associated options. To access the test case argument, you can search for an argument starting with `test-case=`, extract it, and process it in the `run_cpp_test_suite` function. **2. Launching `cargo test` as a separate process** Another possible solution is to launch `cargo test` as a separate process, which then passes the arguments to the Rust process. You can use the `env::args()` function to pass the command-line arguments to the `cargo test` command. Here is an example: ```rust use std::process::Command; fn run_cpp_test_suite(args: &OsString) { Command::new("cargo") .args(&"test") .args(args.iter()) .status() } ``` This code snippet launches `cargo test` as a separate process and passes your command-line arguments to it. The result of this process, including any test output, can be handled as needed in your code. Choose the approach that best fits your project's needs and requirements., If you want to pass command-line arguments to your C++ test suite from Rust, and you want to use the `--` argument to separate the Cargo command from the test suite arguments, you'll need to modify your `run_tests` function to handle the arguments after `--` separately. Here's an updated version of your code that does that: ```rust // in mod ffi pub fn run_tests(cli_args: &mut String) -> bool; #test fn run_cpp_test_suite() { let mut cli_args: Vec<String> = env::args().collect(); let args_index = cli_args.iter().position(|arg| arg == "--").unwrap_or(cli_args.len()); let cpp_args = &cli_argsargs_index + 1 ..; let mut cpp_args_vec: Vec<String> = cpp_args.iter().map(|s| s.to_string()).collect(); if !ffi::run_tests(cpp_args_vec.as_mut_slice()) { panic!("C++ test suite reported errors"); } } ``` In this code, we use `position` to find the index of the `--` argument, then we split the arguments at that index into two slices. We convert the slice of arguments after `--` into a `Vec<String>` and pass that to your `run_tests` function. Now you can run your tests with `cargo test -- --test-case="X"` and the C++ test suite should receive the `--test-case="X"` argument. Regarding your second idea of passing the arguments in an environment variable, it's possible but not recommended because it requires manual parsing of the environment variable value in both Rust and C++. Instead, using `--` argument to separate the Cargo command from the test suite arguments is a cleaner and more idiomatic approach.