I have the following program where I want to call the open_door function in the test module from the main function.
How can I do that?
I know that cfg(test) conditionally compiles that piece of code when using cargo test but how can I tell it to compile it everytime?
#[derive(Debug)]
struct Door {
is_open: bool,
}
impl Door {
fn new(is_open: bool) -> Door {
Door { is_open }
}
}
trait Openable {
fn open(&mut self);
}
impl Openable for Door {
fn open(&mut self) {
self.is_open = true
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn open_door() {
let mut door = Door::new(false);
println!("1: {:?}", door);
door.open();
println!("2: {:?}", door);
assert!(door.is_open);
}
}
fn main() {
println!("Hello, world!");
use tests;
tests::open_door();
}
I get the following error when trying to run the above code:
Compiling chp1 v0.1.0 (/home/ab/personal/Hands-On-Data-Structures-and-Algorithms-with-Rust/practice/chp1)
error[E0432]: unresolved import `tests`
--> practice/chp1/src/main.rs:37:9
|
37 | use tests;
| ^^^^^ no external crate `tests`
|
help: consider importing this module instead
|
37 | use core::num::bignum::tests;
| ~~~~~~~~~~~~~~~~~~~~~~~~~
For more information about this error, try `rustc --explain E0432`.
error: could not compile `chp1` due to previous error
Run with cargo test or remove #[cfg(test)] and #[test].
I adopted the below approach:
#[derive(Debug)]
struct Door {
is_open: bool,
}
impl Door {
fn new(is_open: bool) -> Door {
Door { is_open }
}
}
trait Openable {
fn open(&mut self);
}
impl Openable for Door {
fn open(&mut self) {
self.is_open = true
}
}
mod tests {
use super::*;
pub fn open_door() {
let mut door = Door::new(false);
println!("1: {:?}", door);
door.open();
println!("2: {:?}", door);
assert!(door.is_open);
}
#[test]
fn test_open_door(){
open_door();
}
}
fn main() {
println!("Hello, world!");
use tests;
tests::open_door();
}
Update (after reading the comments below):
#[derive(Debug)]
struct Door {
is_open: bool,
}
impl Door {
fn new(is_open: bool) -> Door {
Door { is_open }
}
}
trait Openable {
fn open(&mut self);
}
impl Openable for Door {
fn open(&mut self) {
self.is_open = true
}
}
pub fn open_door() {
let mut door = Door::new(false);
println!("1: {:?}", door);
door.open();
println!("2: {:?}", door);
assert!(door.is_open);
}
#[cfg(test)]
mod tests {
use super::open_door;
#[test]
fn test_open_door() {
open_door();
}
}
fn main() {
println!("Hello, world!");
open_door();
}
Related
Within the crate we can happily do something like this:
mod boundary {
pub struct EventLoop;
impl EventLoop {
pub fn run(&self) {
for _ in 0..2 {
self.handle("bundled");
self.foo();
}
}
pub fn handle(&self, message: &str) {
println!("{} handling", message)
}
}
pub trait EventLoopExtend {
fn foo(&self);
}
}
use boundary::EventLoopExtend;
impl EventLoopExtend for boundary::EventLoop {
fn foo(&self) {
self.handle("extended")
}
}
fn main() {
let el = boundary::EventLoop{};
el.run();
}
But if mod boundary were a crate boundary we get error[E0117]: only traits defined in the current crate can be implemented for arbitrary types.
I gather that a potential solution to this could be the New Type idiom, so something like this:
mod boundary {
pub struct EventLoop;
impl EventLoop {
pub fn run(&self) {
for _ in 0..2 {
self.handle("bundled");
self.foo();
}
}
pub fn handle(&self, message: &str) {
println!("{} handling", message)
}
}
pub trait EventLoopExtend {
fn foo(&self);
}
impl EventLoopExtend for EventLoop {
fn foo(&self) {
self.handle("unimplemented")
}
}
}
use boundary::{EventLoop, EventLoopExtend};
struct EventLoopNewType(EventLoop);
impl EventLoopExtend for EventLoopNewType {
fn foo(&self) {
self.0.handle("extended")
}
}
fn main() {
let el = EventLoopNewType(EventLoop {});
el.0.run();
}
But then the problem here is that the extended trait behaviour isn't accessible from the underlying EventLoop instance.
I'm still quite new to Rust, so I'm sure I'm missing something obvious, I wouldn't be surprised if I need to take a completely different approach.
Specifically in my case, the event loop is actually from wgpu, and I'm curious if it's possible to build a library where end users can provide their own "render pass" stage.
Thanks to #AlexN's comment I dug deeper into the Strategy Pattern and found a solution:
mod boundary {
pub struct EventLoop<'a, T: EventLoopExtend> {
extension: &'a T
}
impl<'a, T: EventLoopExtend> EventLoop<'a, T> {
pub fn new(extension: &'a T) -> Self {
Self { extension }
}
pub fn run(&self) {
for _ in 0..2 {
self.handle("bundled");
self.extension.foo(self);
}
}
pub fn handle(&self, message: &str) {
println!("{} handling", message)
}
}
pub trait EventLoopExtend {
fn foo<T: EventLoopExtend>(&self, el: &EventLoop<T>) {
el.handle("unimplemented")
}
}
}
use boundary::{EventLoop, EventLoopExtend};
struct EventLoopExtension;
impl EventLoopExtend for EventLoopExtension {
fn foo<T: EventLoopExtend>(&self, el: &EventLoop<T>) {
el.handle("extended")
}
}
fn main() {
let el = EventLoop::new(&EventLoopExtension {});
el.run();
}
The basic idea is to use generics with a trait bound. I think the first time I looked into this approach I was worried about type recursion. But it turns out passing the EventLoop object as an argument to EventLoopExtend trait methods is perfectly reasonable.
If I have an optional method that has to be called many many times what is better if I want to skip it: have an empty body and call it or check the bool/Option before calling it?
The following benchmark make no sense. It gave zeroes.
#![feature(test)]
extern crate test;
trait OptTrait: 'static {
fn cheap_call(&mut self, data: u8);
fn expensive_call(&mut self, data: u8);
}
type ExpensiveFnOf<T> = &'static dyn Fn(&mut T, u8);
struct Container<T: OptTrait> {
inner: T,
expensive_fn: Option<ExpensiveFnOf<T>>,
}
impl<T: OptTrait> Container<T> {
fn new(inner: T, expensive: bool) -> Self {
let expensive_fn = {
if expensive {
Some(&T::expensive_call as ExpensiveFnOf<T>)
} else {
None
}
};
Self {
inner,
expensive_fn,
}
}
}
struct MyStruct;
impl OptTrait for MyStruct {
fn cheap_call(&mut self, _data: u8) {
}
fn expensive_call(&mut self, _data: u8) {
}
}
#[cfg(test)]
mod tests {
use super::*;
use test::Bencher;
#[bench]
fn bench_always_call_empty(b: &mut Bencher) {
let mut cont = Container::new(MyStruct, false);
b.iter(|| {
cont.inner.cheap_call(0);
cont.inner.expensive_call(1);
});
}
#[bench]
fn bench_alwaws_skip_empty(b: &mut Bencher) {
let mut cont = Container::new(MyStruct, false);
b.iter(|| {
cont.inner.cheap_call(0);
if let Some(func) = cont.expensive_fn {
func(&mut cont.inner, 1);
}
});
}
}
There is a way to achieve get or create like upsert in db vocab for no required field.
In the following code playground fail because self.option is borrowed.
#[derive(Debug)]
struct A {
option: Option<i32>,
}
impl A {
fn new() -> Self {
Self { option: None }
}
fn option_or_new(&mut self) -> &i32 {
if let Some(i) = &self.option { // `self.option` is borrowed here
&i
} else {
let i = 0;
self.option = Some(i); // cannot assign to `self.option` because it is borrowed
self.option.as_ref().unwrap()
}
}
}
fn main() {
let mut a = A::new();
let i = a.option_or_new();
println!("{}",i);
}
I have to use unsafe code for resolved this issue, or does it exist an idiomatic way for that ?
You can use get_or_insert or get_or_insert_with:
impl A {
fn option_or_new(&mut self) -> &i32 {
self.option.get_or_insert(0)
}
}
Playground
I try to use panic::catch_unwind to catch some errors, but it seems no use, and there is an example:
rust:
use std::{sync::Mutex};
use wasm_bindgen::prelude::*;
use std::sync::PoisonError;
use std::panic;
pub struct CurrentStatus {
pub index: i32,
}
#[wasm_bindgen]
extern {
pub fn alert(s: &str);
}
impl CurrentStatus {
fn new() -> Self {
CurrentStatus {
index: 1,
}
}
fn get_index(&mut self) -> i32 {
self.index += 1;
self.index.clone()
}
fn add_index(&mut self) {
self.index += 2;
}
}
lazy_static! {
pub static ref FOO: Mutex<CurrentStatus> = Mutex::new(CurrentStatus::new());
}
unsafe impl Send for CurrentStatus {}
#[wasm_bindgen]
pub fn add_index() {
FOO.lock().unwrap_or_else(PoisonError::into_inner).add_index();
}
#[wasm_bindgen]
pub fn get_index() -> i32 {
let mut foo = FOO.lock().unwrap_or_else(PoisonError::into_inner);
let result = panic::catch_unwind(|| {
panic!("error happen!"); // original panic! code
});
if result.is_err() {
alert("panic!!!!!panic");
}
return foo.get_index();
}
js:
const js = import("../pkg/hello_wasm.js");
js.then(js => {
window.js = js;
console.log(js.get_index());
js.add_index();
});
I think it should catch the panic and I can call add_index then.
But In fact I can call neither after the panic.
I wish I can catch the panic from one function so when the users call other functions just all right..
Thanks very much
Sorry for newbie question. The error here is
<anon>:30:5: 30:17 error: cannot borrow immutable borrowed content as mutable
<anon>:30 routing_node.put(3);
^^^^^^^^^^^^
I have tried many things to work around this but know for sure this is a simple error. Any help much appreciated.
use std::thread;
use std::thread::spawn;
use std::sync::Arc;
struct RoutingNode {
data: u16
}
impl RoutingNode {
pub fn new() -> RoutingNode {
RoutingNode { data: 0 }
}
pub fn run(&self) {
println!("data : {}", self.data);
}
pub fn put(&mut self, increase: u16) {
self.data += increase;
}
}
fn main() {
let mut routing_node = Arc::new(RoutingNode::new());
let mut my_node = routing_node.clone();
{
spawn(move || {my_node.run(); });
}
routing_node.put(3);
}
Arc isn't allowing to mutate of it's inner state, even if container is marked as mutable. You should use one of Cell, RefCell or Mutex. Both Cell and RefCell are non-threadsafe so you should use Mutex (last paragraph in docs).
Example:
use std::thread::spawn;
use std::sync::Mutex;
use std::sync::Arc;
struct RoutingNode {
data: u16,
}
impl RoutingNode {
pub fn new() -> Self { RoutingNode { data: 0, } }
pub fn run(&self) { println!("data : {}" , self.data); }
pub fn put(&mut self, increase: u16) { self.data += increase; }
}
fn main() {
let routing_node = Arc::new(Mutex::new(RoutingNode::new()));
let my_node = routing_node.clone();
let thread = spawn(move || { my_node.lock().unwrap().run(); });
routing_node.lock().unwrap().put(3);
let _ = thread.join();
}
Playpen