Need realize the possibility of comparison Foo<i32> and Foo<u32>.
struct Foo<T> {
id: usize,
data: T
}
impl<T> Foo<T> {
fn new_i32(i: i32) -> Foo<i32> {
Foo {
id: 0,
data: i
}
}
fn new_u32(u: u32) -> Foo<u32> {
Foo {
id: 1,
data: u
}
}
}
The problem is that trait PartialEq can only compare the same types.
impl<T> PartialEq for Foo<T> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
And this dont work:
let a = Foo::new_u32(123);
let b = Foo::new_i32(123);
println!("{}", a == b);
Full code in play.rust-lang.org
The problem is that trait PartialEq can only compare the same types.
That's not true. It just defaults the Rhs to the same type as Self:
pub trait PartialEq<Rhs = Self> where Rhs: ?Sized {
...
}
Here's how you would implement PartialEq for Foo<L> and Foo<R> for any L and R:
impl<L, R> PartialEq<Foo<R>> for Foo<L> {
fn eq(&self, other: &Foo<R>) -> bool {
self.id == other.id
}
}
Note that I also had to change the impl block to fix some type inference errors. Final code:
struct Foo<T> {
id: usize,
data: T,
}
impl Foo<i32> {
fn new_i32(i: i32) -> Foo<i32> {
Foo { id: 0, data: i }
}
}
impl Foo<u32> {
fn new_u32(u: u32) -> Foo<u32> {
Foo { id: 1, data: u }
}
}
impl<L, R> PartialEq<Foo<R>> for Foo<L> {
fn eq(&self, other: &Foo<R>) -> bool {
self.id == other.id
}
}
fn main() {
let a = Foo::new_u32(123);
let b = Foo::new_i32(123);
println!("{}", a == b);
}
Output:
false
https://play.rust-lang.org/?gist=51166880a9ab0c49d7650588c4ed8290&version=stable&backtrace=0
Related
I have tried to reimplement LinkedList in Rust, below are my codes:
#![allow(dead_code)]
use std::cell::{RefCell, Ref, RefMut};
use std::rc::Rc;
type WrappedNode<T> = Rc<RefCell<Node<T>>>;
#[derive(Debug, PartialOrd, PartialEq, Clone)]
pub struct Node<T> where
T: Clone
{
next: Option<WrappedNode<T>>,
data: T,
}
#[derive(Debug, PartialOrd, PartialEq)]
pub struct LinkedList<T> where
T: Clone
{
head: Option<WrappedNode<T>>,
tail: Option<WrappedNode<T>>,
}
impl<T> Iterator for LinkedList<T> where
T: Clone
{
type Item = WrappedNode<T>;
fn next(&mut self) -> Option<Self::Item> {
unimplemented!()
}
}
impl<T> Node<T> where
T: Clone
{
pub fn new(data: T) -> Self {
Self {
next: None,
data,
}
}
pub fn borrow_data(self: &Self) -> &T {
&self.data
}
pub fn borrow_next(self: &Self) -> Option<Ref<Node<T>>> {
match &self.next {
Some(next_exists) => {
Some(next_exists.borrow())
},
None => {
None
}
}
}
pub fn borrow_mut_next(self: &Self) -> Option<RefMut<Node<T>>> {
match &self.next {
Some(next_exists) => {
Some(next_exists.borrow_mut())
},
None => {
None
}
}
}
pub fn set_next(self: &mut Self, next: Node<T>) {
let next_node = Rc::new(RefCell::new(next));
self.next = Some(next_node);
}
}
impl<T> LinkedList<T> where
T: Clone
{
pub fn new_empty() -> Self {
Self {
head: None,
tail: None,
}
}
pub fn new_with_node(first_node: Node<T>) -> Self {
let mut new_ll = Self::new_empty();
Self::append(&mut new_ll, first_node);
new_ll
}
pub fn append(&mut self, node: Node<T>) {
assert!(node.next.is_none()); // make sure its not joining two linkedlists
match self.tail.take() {
Some(old_tail) => {
old_tail
.borrow_mut()
.set_next(node.clone());
},
None => {
let mut node_clone = node.clone();
node_clone.next = self.tail.clone();
self.head = Some(Rc::new(RefCell::new(node_clone)));
}
}
self.tail = Some(Rc::new(RefCell::new(node)));
}
}
// CRUD -> create new, add to head tail, read head tail, update anywhere, delete anywhere, delete head tail
#[cfg(test)]
mod tests {
use super:: {Node, LinkedList};
use std::rc::Rc;
use std::cell::RefCell;
#[test]
fn test_node_ref_data() {
let node = Node::new(5);
assert_eq!(node.borrow_data(), &5);
}
#[test]
fn test_node_ref_next() {
let node = Node::new(5);
assert!(node.borrow_next().is_none());
}
#[test]
fn test_node_set_next() {
let mut node = Node::new(33);
let next_node = Node::new(34);
Node::set_next(&mut node,
next_node);
assert_eq!(node
.borrow_next()
.unwrap()
.borrow_data(), &34);
}
#[test]
fn test_ll_new_empty() {
#[derive(Debug, PartialEq, PartialOrd, Clone)]
struct NTH;
let new_ll = LinkedList::<NTH>::new_empty();
assert_eq!(new_ll, LinkedList{head: None, tail: None})
}
#[test]
fn test_ll_new_with_node() {
let new_node = Node::new(45);
let new_node_two = new_node.clone();
let new_node_three = new_node.clone();
let new_ll = LinkedList::new_with_node(new_node);
let new_node_two = Some(Rc::new(RefCell::new(new_node_two)));
let new_node_three = Some(Rc::new(RefCell::new(new_node_three)));
assert_eq!(new_ll, LinkedList{head: new_node_two, tail: new_node_three})
}
#[test]
fn test_ll_new_with_node_head_borrow_next_is_tail() {
let new_node = Node::new(45);
let new_node_two = new_node.clone();
let new_ll = LinkedList::new_with_node(new_node);
let new_node_two = Some(Rc::new(RefCell::new(new_node_two)));
assert_eq!(new_ll
.head
.unwrap()
.borrow()
.borrow_next()
.unwrap()
.borrow_data(), new_node_two.unwrap().borrow().borrow_data());
}
#[test]
fn test_ll_append_tail() {
let new_node = Node::new(45);
let new_node_two = new_node.clone();
let mut new_ll = LinkedList::new_with_node(new_node);
let new_node_two = Some(Rc::new(RefCell::new(new_node_two)));
let append_node = Node::new(77);
LinkedList::append(&mut new_ll, append_node);
assert_eq!(new_ll
.tail
.unwrap()
.borrow()
.borrow_data(), &77)
}
#[test]
fn test_ll_append_first_borrow_next() {
let new_node = Node::new(45);
let new_node_two = new_node.clone();
let mut new_ll = LinkedList::new_with_node(new_node);
let new_node_two = Some(Rc::new(RefCell::new(new_node_two)));
let append_node = Node::new(77);
LinkedList::append(&mut new_ll, append_node);
assert_eq!(new_ll
.head
.unwrap()
.borrow()
.borrow_next()
.unwrap()
.borrow_data(), &77)
}
// end of tests
}
Two tests failed, as shown below:
running 8 tests
test same_type_linked_list::tests::test_ll_new_empty ... ok
test same_type_linked_list::tests::test_ll_append_tail ... ok
test same_type_linked_list::tests::test_ll_new_with_node_head_borrow_next_is_tail ... FAILED
test same_type_linked_list::tests::test_ll_append_first_borrow_next ... FAILED
test same_type_linked_list::tests::test_ll_new_with_node ... ok
test same_type_linked_list::tests::test_node_ref_data ... ok
test same_type_linked_list::tests::test_node_set_next ... ok
test same_type_linked_list::tests::test_node_ref_next ... ok
failures:
---- same_type_linked_list::tests::test_ll_new_with_node_head_borrow_next_is_tail stdout ----
thread 'same_type_linked_list::tests::test_ll_new_with_node_head_borrow_next_is_tail' panicked at 'called `Option::unwrap()` on a `None` value', src/same_type_linked_list.rs:176:14
---- same_type_linked_list::tests::test_ll_append_first_borrow_next stdout ----
thread 'same_type_linked_list::tests::test_ll_append_first_borrow_next' panicked at 'called `Option::unwrap()` on a `None` value', src/same_type_linked_list.rs:210:16
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
same_type_linked_list::tests::test_ll_append_first_borrow_next
same_type_linked_list::tests::test_ll_new_with_node_head_borrow_next_is_tail
I suspect during the appending of a new Node<T>, concretely Node<u64>, to an empty LinkedList the self.head.next is not pointing to self.tail, despite me setting it explicitly. The error occurs when I call unwrap() on the None value which is returned from borrow_next(), an associated method of Node<T> to return a reference of the field .next. That means that new_ll.head.borrow_next() which ideally should return a reference to new_ll.tail instead returns a None, meaning that it is not pointing to new_ll.tail when a first node is appended/inserted into a completely empty LinkedList.
Looking at your code the head node is the one that you give to in
LinkedList::new_with_node()
Its calling
pub fn new_empty() -> Self {
Self {
head: None,
tail: None,
}
i.e. its initialized with no head node. So when you construct your list with a node you are adding a head
pub fn new_with_node(first_node: Node<T>) -> Self {
let mut new_ll = Self::new_empty();
Self::append(&mut new_ll, first_node);
new_ll
}
pub fn append(&mut self, node: Node<T>) {
assert!(node.next.is_none()); // make sure its not joining two linkedlists
match self.tail.take() {
Some(old_tail) => {
old_tail
.borrow_mut()
.set_next(node.clone());
},
None => {
let mut node_clone = node.clone();
node_clone.next = self.tail.clone();
self.head = Some(Rc::new(RefCell::new(node_clone)));
}
}
You are also calling append by explicitly passing the newly created list as self.
Self::append(&mut new_ll, first_node);
You could have called it
new_ll.append(first_node)
You are assuming there is another node beyond the head in your test:
assert_eq!(new_ll
.head
.unwrap()
.borrow()
.borrow_next()
.unwrap()
.borrow_data(), &77)
I know that the underlying data structure is a HashSet, but why can the get method use the &str type instead of the cookie structure?
cargo.toml
[dependencies]
cookie = "0.14"
src/main.rs
use cookie::{Cookie, CookieJar};
fn main() {
let mut jar = CookieJar::new();
jar.add(Cookie::new("a", "one"));
jar.add(Cookie::new("b", "two"));
assert_eq!(jar.get("a").map(|c| c.value()), Some("one"));
assert_eq!(jar.get("b").map(|c| c.value()), Some("two"));
jar.remove(Cookie::named("b"));
assert!(jar.get("b").is_none());
}
The authors of cookie-rs implemented the Hash and Borrow trait for the values of the HashSet.
Here's an example mimicking the same behavior:
use std::borrow::Borrow;
use std::hash::{Hash, Hasher};
use std::collections::HashSet;
#[derive(Debug, Eq)]
struct Cookie<'a> {
name: &'a str,
id: u64,
}
impl Hash for Cookie<'_> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name.hash(state);
}
}
impl PartialEq for Cookie<'_> {
fn eq(&self, other: &Cookie) -> bool {
self.name == other.name
}
}
impl Borrow<str> for Cookie<'_> {
fn borrow(&self) -> &str {
self.name
}
}
fn main() {
let mut cookies: HashSet<Cookie> = HashSet::new();
cookies.insert(Cookie {
name: "example",
id: 42,
});
println!("{:?}", cookies.get("example"));
}
That would give us:
Some(Cookie { name: "example", id: 42 })
In my program, I represent "events" with the following structure:
struct Event {
value: &'static str,
timestamp: usize,
}
So far, I used PartialEq to compare Event variables: most of the time, I consider two Events to be equal if their value is the same:
impl PartialEq for Event {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_loose_equality() {
let a = Event { value: "a-value", timestamp: 12345 };
let b = Event { value: "a-value", timestamp: 23456 };
assert_eq!(a, b);
}
}
However, in certain tests, I would like to ensure that two such variables are "strictly equals": The test should fail they have different timestamp (are not the same in respect to Eq).
As per the documentation of assert_eq!:
Asserts that two expressions are equal to each other (using PartialEq).
source
So, I am looking for an Eq equivalent, an assert_Eq_eq! in sort.
(or am I misunderstanding how Eq works and should be used?)
Here is what I fail to complete:
impl Eq for Event {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_strict_equality() {
let a = Event { value: "a-value", timestamp: 12345 };
let b = Event { value: "a-value", timestamp: 12345 };
// ???
}
}
You're swimming upstream fighting against the current. Go with the flow. Let PartialEq be strict equality and define a separate trait or method for loose equality.
#[derive(Eq, PartialEq)]
struct Event { .. }
impl Event {
fn loose_eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
#[test]
fn test_loose_equality() {
let a = Event { value: "a-value", timestamp: 12345 };
let b = Event { value: "a-value", timestamp: 23456 };
assert!(a.loose_eq(b));
}
I would create "views" of the type as appropriate:
struct Event {
value: &'static str,
timestamp: usize,
}
#[derive(Debug, PartialEq)]
struct Exact<'a> {
value: &'a &'static str,
timestamp: &'a usize,
}
impl Event {
fn exact(&self) -> Exact<'_> {
let Self { value, timestamp } = self;
Exact { value, timestamp }
}
}
fn demo(a: Event, b: Event) {
assert_eq!(a.exact(), b.exact());
}
Here I've chosen to take references to each of the fields to demonstrate the general case, but you don't need references for this specific example (&str and usize implement Copy and are small).
You could also choose to not implement PartialEq on the original type at all, and only perform comparisons through views:
assert_eq!(a.exact(), b.exact());
assert_eq!(a.loose(), b.loose());
If you need the strict equality only in tests, and your struct only has two fields, I'd simply compare these fields directly:
let a = Event { value: "a-value", timestamp: 12345 };
let b = Event { value: "a-value", timestamp: 12345 };
assert_eq!(a.value, b.value);
assert_eq!(a.timestamp, b.timestamp);
This looks like the easiest and most readable option to me.
Yes, you are misunderstanding something. Eq doesn't have any new methods over PartialEq. It's just an assertion that the implementation of PartialEq is reflexive (as well as the transitivity and symmetry assumed with PartialEq).
If you want to have a different "strict" equality, you could make your own trait (if you expect to use this a lot) or simply have a method fn strict_eq(&self, other: &Self) -> bool attached to Event.
Given such a method you could write a macro to use that method.
The full source for assert_eq! can be found here and could be easily adapted, but a (perhaps overly) simple version would be something like
macro_rules! assert_strict_eq {
($left: expr, $right: expr) => {
if !$left.strict_eq(&$right) {
panic!(r#"assertion failed: `(left == right)`
left: `{:?}`,
right: `{:?}`"#, $left, $right)
}
}
}
(example usage)
Unlike JavaScript, Rust does not support equal vs. strict equal.
However, you can achieve similar effect by implementing your own trait and macro:
pub trait StrictEq {
fn strict_eq(&self, other: &Self) -> bool;
}
macro_rules! assert_strict_eq {
($left:expr, $right:expr) => {{
match (&$left, &$right) {
(left_val, right_val) => {
assert!(left_val.strict_eq(right_val));
}
}
}};
}
The implementation for Event would be rather simple:
impl StrictEq for Event {
fn strict_eq(&self, other: &Self) -> bool {
self.value == other.value && self.timestamp == other.timestamp
}
}
EnrollmentViewModelTest
#Test
fun getUserProfile() {
val responseSnapshot = this.javaClass.getResource("/userDetailResponse.json").readText()
val user = Gson().fromJson<User>(responseSnapshot, User::class.java)
val response = Response.success(user)
val deferred = CompletableDeferred<Response<User>>(response)
coEvery { userService.getUserDetail() } returns deferred
viewModel.getUserProfile()
assert(viewModel.loadingStatus.value != null)
assert(!UITestUtil.getValue(viewModel.loadingStatus)!!)
assertEquals(false, viewModel.loadingStatus.value!!)
}
Here is EnrollmentViewModel.kt
fun getUserProfile() {
loadingStatus.postValue(true)
job = launch {
callAsync {
userService.getUserDetail()
}.onSuccess { user ->
if (user != null) {
processUserDetails(user)
}
loadingStatus.postValue(false)
}.onError {
//
}.onException {
//
}
}
}
When I debug the test case, it show that the UITestUtil.getValue(viewModel.loadingStatus)!! is false.
But weirdly, the test case does not pass, and when I print the UITestUtil.getValue(viewModel.loadingStatus)!!. It is true.
It may related to the loadingStatus.postValue(true)
After I remove it, the print result is false.
But I do not know why.
object UITestUtil {
/**
* Gets the value of a LiveData safely.
*/
#Throws(InterruptedException::class)
fun <T> getValue(liveData: LiveData<T>): T? {
var data: T? = null
val latch = CountDownLatch(1)
val observer = object : Observer<T> {
override fun onChanged(o: T?) {
data = o
latch.countDown()
liveData.removeObserver(this)
}
}
liveData.observeForever(observer)
latch.await(2, TimeUnit.SECONDS)
return data
}
}
Updated:
import com.google.gson.Gson
import kotlinx.coroutines.Deferred
import retrofit2.Response
import retrofit2.Response.success
data class VPlusResult<T : Any?>(
val response: Response<T>? = null,
val exception: Exception? = null
)
inline fun <T : Any> VPlusResult<T>.onSuccess(action: (T?) -> Unit): VPlusResult<T> {
if (response?.isSuccessful == true)
action(response.body())
return this
}
inline fun <T : Any> VPlusResult<T>.onRawSuccess(action: (response: Response<T>) -> Unit): VPlusResult<T> {
if (response?.isSuccessful == true)
action(response)
return this
}
inline fun <T : Any, TR : Any> VPlusResult<T>.map(action: (T?) -> (TR)) =
if (response?.isSuccessful == true) VPlusResult(success(action(response.body())))
else this as VPlusResult<TR>
inline fun <T : Any> VPlusResult<T>.onError(action: (String) -> Unit): VPlusResult<T> {
if (response?.isSuccessful != true) {
response?.errorBody()?.let {
action(it.string())
}
}
return this
}
inline fun <T : Any, reified G : Any> VPlusResult<T>.onErrorJson(action: (G) -> Unit): VPlusResult<T> {
if (response?.isSuccessful != true) {
response?.errorBody()?.let {
action(Gson().fromJson(it.string(), G::class.java))
}
}
return this
}
inline fun <T : Any> VPlusResult<T>.onRawError(action: (Response<T>?) -> Unit): VPlusResult<T> {
if (response?.isSuccessful != true) {
action(response)
}
return this
}
inline fun <T : Any?> VPlusResult<T>.onException(action: (Exception) -> Unit) {
exception?.let { action(it) }
}
inline fun <T : Any> VPlusResult<T>.onSadness(action: (String?) -> Unit): VPlusResult<T> {
onError {
action(it)
}.onException {
action(it.message)
}
return this
}
suspend fun <T : Any> callAsync(block: () -> Deferred<Response<T>>): VPlusResult<T> {
return try {
VPlusResult(block().await())
} catch (e: Exception) {
VPlusResult(exception = e)
}
}
Updated 2:
adding either of the following statements before assert statement will get the value false, which passes the test case.
coVerify { userService.getUserDetail() }
coVerify { viewModel.processUserDetails(user) }
Update 3:
fun loadAllTasksFromRepository_loadingTogglesAndDataLoaded()
in https://github.com/android/architecture-samples
Also works, but I try to introduce into my codes, it also failed.
#ExperimentalCoroutinesApi
#Test
fun getUserProfile4Using() {
// using TestCoroutineScope in kotlinx.coroutines.test
// Pause dispatcher so we can verify initial values
mainCoroutineRule.pauseDispatcher()
val responseSnapshot = this.javaClass.getResource("/userDetailResponse.json").readText()
val user = Gson().fromJson<User>(responseSnapshot, User::class.java)
val response = Response.success(user)
val deferred = CompletableDeferred<Response<User>>(response)
// coEvery { userService.getUserDetail() } returns deferred
viewModel.getUserProfile()
assert(viewModel.loadingStatus.value != null)
// verify { viewModel.processUserDetails(user) }
print(viewModel.loadingStatus.value)
assert(UITestUtil.getValue(viewModel.loadingStatus)!!)
assertEquals(true, viewModel.loadingStatus.value!!)
// Execute pending coroutines actions
mainCoroutineRule.resumeDispatcher()
print(viewModel.loadingStatus.value!!)
assert(!UITestUtil.getValue(viewModel.loadingStatus)!!)
assertEquals(false, viewModel.loadingStatus.value!!)
}
I'd say you should probably rewrite your test using runBlockingTest(https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/)
fun getUserProfile() = runBlockingTest{
val responseSnapshot = this.javaClass.getResource("/userDetailResponse.json").readText()
val user = Gson().fromJson<User>(responseSnapshot, User::class.java)
val response = Response.success(user)
val deferred = CompletableDeferred<Response<User>>(response)
coEvery { userService.getUserDetail() } returns deferred
viewModel.getUserProfile()
assert(viewModel.loadingStatus.value != null)
assert(!UITestUtil.getValue(viewModel.loadingStatus)!!)
assertEquals(false, viewModel.loadingStatus.value!!)
}
You won't have to use those countdownlatches etc. This approach has literally fixed all of my issues with testing coroutines, hope it helps you as well :)! If not, just let me know.
I have a method as following
public static func createAlbum(named: String, completion: (album: PHAssetCollection?) -> ()) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
}) { success, error in
completion(album: album)
}
}
}
How can i do the background task using RxSwift
complete code
https://gist.github.com/sazzadislam-dsi/d347909d284674c936e397ac423703cf
#XFreire answer is right, but for Swift 3 and RxSwift 3.1.0 I would add an extension to PHAssetCollection:
extension Reactive where Base: PHPhotoLibrary {
func createAlbum(named name: String) -> Observable<PHAssetCollection?> {
return Observable.create { observer in
self.base.performChanges({
// ...
}, completionHandler: { success, error in
if success {
// Your success logic goes here
let album = PHAssetCollection()
// ...
observer.on(.next(album))
observer.on(.completed)
} else if let error = error {
observer.on(.error(error))
} else {
// Your error type
observer.on(.error(MyErrors.Unknown))
}
})
return Disposables.create()
}
}
}
Then you can use the method like this:
PHPhotoLibrary
.shared().rx.createAlbum(named: "MyAlbum")
.subscribe(onNext: { collection in
// ...
}, onError: { error in
// ...
})
.addDisposableTo(disposeBag)
First, your function must return an Observable.
public static func rx_createAlbum(named: String)-> Observable<PHAssetCollection?>
Second, when there is an error, your function will return onError, and when success is true, your function will return onNext(album) and onCompleted().
Code:
public static func rx_createAlbum(named: String)-> Observable<PHAssetCollection?> {
return Observable.create { observer in
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
// ...
}) { success, error in
if error {
observer.onError(error)
}
else {
var album: PHAssetCollection?
if success {
let collectionFetchResult = PHAssetCollection.fetchAssetCollectionsWithLocalIdentifiers([placeholder?.localIdentifier ?? ""], options: nil)
album = collectionFetchResult.firstObject as? PHAssetCollection
}
observer.onNext(album)
observer.onCompleted()
}
}
}
return Disposables.create()
}
}