I am reading Learning Rust With Entirely Too Many Linked Lists, specifically the chapter about a persistent singly-linked stack.
I am having difficulty understanding use of take in the drop function.
Without it, I get the same logs in drop.
use std::rc::Rc;
use std::fmt;
type Link<T> = Option<Rc<Node<T>>>;
#[derive(Debug)]
pub struct List<T>
where
T: fmt::Debug,
{
head: Link<T>,
}
#[derive(Debug)]
struct Node<T>
where
T: fmt::Debug,
{
val: T,
next: Link<T>,
}
impl<T> List<T>
where
T: fmt::Debug,
{
pub fn new() -> Self {
List { head: None }
}
pub fn append(&self, val: T) -> List<T> {
List {
head: Some(Rc::new(Node {
val: val,
next: self.head.clone(),
})),
}
}
}
impl<T> Drop for List<T>
where
T: fmt::Debug,
{
fn drop(&mut self) {
println!("1 : {:?}", self);
let mut curr_list = self.head.take();
println!("2");
while let Some(node) = curr_list {
println!("3");
match Rc::try_unwrap(node) {
Err(_) => {
println!("4");
break;
}
Ok(ref mut x) => {
println!("5");
curr_list = x.next.take()
}
}
println!("6");
}
println!("7");
}
}
fn main() {
let list = List::new().append(1).append(2);
let _list2 = list.append(3);
let _list3 = list.append(3);
let _list4 = list.append(3);
let _list5 = list.append(3);
}
Playground
It outputs:
1 : List { head: Some(Node { val: 1, next: None }) }
2
3
4 : stopping at 1
7
1 : List { head: None }
2
7
1 : List { head: Some(Node { val: 3, next: Some(Node { val: 2, next: Some(Node { val: 1, next: None }) }) }) }
2
3
5: dropping 3
6
3
4 : stopping at 2
7
1 : List { head: Some(Node { val: 3, next: Some(Node { val: 2, next: Some(Node { val: 1, next: None }) }) }) }
2
3
5: dropping 3
6
3
4 : stopping at 2
7
1 : List { head: Some(Node { val: 3, next: Some(Node { val: 2, next: Some(Node { val: 1, next: None }) }) }) }
2
3
5: dropping 3
6
3
4 : stopping at 2
7
1 : List { head: Some(Node { val: 3, next: Some(Node { val: 2, next: Some(Node { val: 1, next: None }) }) }) }
2
3
5: dropping 3
6
3
4 : stopping at 2
7
1 : List { head: Some(Node { val: 2, next: Some(Node { val: 1, next: None }) }) }
2
3
5: dropping 2
6
3
5: dropping 1
6
7
The first and second 1 : List { is because of first line in main, which is destroying temp lists created. The next 3 1 : List { are lists getting dropped in reverse order of creation. Finally the shared list of size 2 is dropped.
Even if I remove take from line : curr_list = x.next.take() and remove ref mut for x in fn drop I still get the same output.
What is x there and why does take() have no effects?
I earlier thought that take would change the original list by setting the next to None, but that is not possible as that will invalidate the list for other people who have references.
Implementing drop on Node :
impl<T> Drop for Node<T> where T: fmt::Debug {
fn drop(&mut self) {
println!("Node drop : {:?}", self.val);
}
}
so, Just after Ok(ref mut x) block, Node x is dropped.
Related
I was working on a leetcode problem, where I need to merge the elements in the list
input: [0,3,1,0,4,5,2,0]
output: [4,11]
I have submitted the code by creating a new Linkedlist, but couldn't come up with in place solution in Rust. Where did I go wrong?
// Definition for singly-linked list.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>
}
impl ListNode {
#[inline]
fn new(val: i32) -> Self {
ListNode {
next: None,
val
}
}
}
struct Solution;
impl Solution {
pub fn merge_nodes(head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
if head.is_none() {return None}
type Bl = Box<ListNode>;
let mut dummy: Bl = Box::new(ListNode::new(0));
// Assuming first element is 0 & non-empty list
let mut src_tail: &mut Bl = &mut head.unwrap();
let mut res_tail: &mut Bl = &mut dummy;
let mut sum = 0;
// LOOPING src list till end
while let Some(ref mut node) = src_tail.next {
sum += node.val;
// if zero then append the accumulated sum to res_tail
if node.val == 0 {
res_tail.next = Some(Box::new(ListNode::new(sum)));
sum = 0;
if let Some(ref mut post) = res_tail.next {
res_tail = post;
}
}
src_tail = node;
}
dummy.next
}
pub fn merge_nodes_in_place(head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
type List = Box<ListNode>;
if head.is_none() {return None}
let res = head.clone();
let mut start: List = head.unwrap();
while let Some(node) = start.next {
let mut sum = 0;
let mut end: List = node;
while end.val != 0 {
sum += end.val;
let tail = end.next.take();
match tail {
Some(next_node) => {
end = next_node.next.unwrap();
},
None => ()
}
}
// end is pointing to 0th Node or next item is None
end.val = sum;
if end.next.is_none() {break;}
start = end.next.unwrap();
}
res
}
}
fn main() {
let a = Some(Box::new(ListNode { val: 0, next: None }));
let a = Some(Box::new(ListNode { val: 2, next: a }));
let a = Some(Box::new(ListNode { val: 5, next: a }));
let a = Some(Box::new(ListNode { val: 4, next: a }));
let a = Some(Box::new(ListNode { val: 0, next: a }));
let a = Some(Box::new(ListNode { val: 1, next: a }));
let a = Some(Box::new(ListNode { val: 3, next: a }));
let head = Some(Box::new(ListNode { val: 0, next: a }));
println!("{:?}", Solution::merge_nodes(head));
// Some(ListNode { val: 4, next: Some(ListNode { val: 11, next: None }) })
let a = Some(Box::new(ListNode { val: 0, next: None }));
let a = Some(Box::new(ListNode { val: 2, next: a }));
let a = Some(Box::new(ListNode { val: 5, next: a }));
let a = Some(Box::new(ListNode { val: 4, next: a }));
let a = Some(Box::new(ListNode { val: 0, next: a }));
let a = Some(Box::new(ListNode { val: 1, next: a }));
let a = Some(Box::new(ListNode { val: 3, next: a }));
let head = Some(Box::new(ListNode { val: 0, next: a }));
println!("{:?}", Solution::merge_nodes_in_place(head));
}
impl Solution {
fn consume_next_node(cursor: &mut ListNode)->Option<&mut ListNode> {
let next = cursor.next.as_mut()?;
if next.next.is_none() || next.val != 0 {
cursor.val += next.val;
let nextnext = next.next.take();
cursor.next = nextnext;
Some(cursor)
} else {
cursor.next.as_mut().map(|b| &mut **b)
}
}
pub fn merge_nodes_in_place(mut head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
let mut cursor: Option<&mut ListNode> = head.as_mut().map(|b| &mut **b);
while let Some(node) = cursor {
cursor = Solution::consume_next_node(node);
}
head
}
}
I am new to GraphQL and I've been trying to come up with a simple query but I'm not getting the results I need.
Basically, I am writing a mutation to delete a row when the following conditions are met:
(A = a AND B = b) OR (A = b AND B = a)
However, I can't seem to figure out how to write it.
I tried doing something like:
delete_links(where: {_or: {_and: {a: {_eq: a}, b: {_eq: b}}}, {_and: {a: {_eq: b}, b: {_eq: a}}}) {
affected_rows
}
}
I am using Hasura on postgresql.
Basically I have a table called Links storing:
link_a | link_b
The problem is a link between item 9 and 2 in link can either be:
link_a | link_b
2 | 9
or
link_a | link_b
9 | 2
Hence I want my delete mutation to delete BOTH cases. However I cant seem to do a query (A = a AND B = b) OR (A = b AND B = a)
Since _or, _and is array. So, your mutation should look like this:
# in this example: typeof A = Int, typeof B = Int
mutation delete_links($a: Int, $b: Int) {
delete_links(
where: {
_or: [
{ A: { _eq: $a }, B: { _eq: $b } }
{ A: { _eq: $b }, B: { _eq: $a } }
]
}
) {
affected_rows
}
}
# if you'd like to use additional _and
mutation delete_links($a: Int, $b: Int) {
delete_links(
where: {
_or: [
{ _and: [{ A: { _eq: $a } }, { B: { _eq: $b } }] }
{ _and: [{ A: { _eq: $b } }, { B: { _eq: $a } }] }
]
}
) {
affected_rows
}
}
types.json:
{
"WorkerId": {
"_enum": {
"Single": "Single",
"Double": "Double"
}
},
"Single": "u8",
"Double": "(u8, u8)",
}
substrate code:
#[pallet::storage]
#[pallet::getter(fn worker_infos)]
pub type WorkerInfos<T: Config> = StorageMap<_, Twox64Concat, WorkerId, WorkerInfo, ValueQuery>;
pub enum WorkerId {
Single(u8),
Double(u8, u8),
}
I want to query worker_infos by WorkerId in polkadot.js:
workerIds = [1,2]
api.query[wrpc][wcallable]
.multi(workerIds, (results) => {
...
})
.then((unsub) => {
...
})
.catch(console.error);
Error info:
REGISTRY: Error: Unable to create Enum via index 2, in Single, Double
Any ideas on this? How to pass workerIds(enum type) in polkadot.js?
{ Single: 1 } or { Double: [2, 3] }
Suppose I have record like this:
{
id: 1,
statistics: {
stat1: 1,
global: {
stat2: 3
},
stat111: 99
}
}
I want to make update on record with object:
{
statistics: {
stat1: 8,
global: {
stat2: 6
},
stat4: 3
}
}
And it should be added to current record as delta. So, the result record should looks like this:
{
id: 1,
statistics: {
stat1: 9,
global: {
stat2: 9
},
stat4: 3,
stat111: 99
}
}
Is it possible to make this with one query?
Do you want something generic or something specific?
Specific is easy, this is the generic case:
const updateValExpr = r.expr(updateVal);
const updateStats = (stats, val) => val
.keys()
.map(key => r.branch(
stats.hasFields(key),
[key, stats(key).add(val(key))],
[key, val(key)]
))
.coerceTo('object')
r.table(...)
.update(stats =>
updateStats(stats.without('global'), updateValExpr.without('global'))
.merge({ global: updateStats(stats('global'), updateValExpr('global'))
)
There might be some bugs here sincce it's untested but the solution key point is the updateStats function, the fact that you can get all the keys with .keys() and that coerceTo('object') transforms this array: [['a',1],['b',2]] to this object: { a: 1, b: 2 },
Edit:
You can do it recursively, although with limited stack (since you can't send recursive stacks directly, they resolve when the query is actually built:
function updateStats(stats, val, stack = 10) {
return stack === 0
? {}
: val
.keys()
.map(key => r.branch(
stats.hasFields(key).not(),
[key, val(key)],
stats(key).typeOf().eq('OBJECT'),
[key, updateStats(stats(key), val(key), stack - 1)],
[key, stats(key).add(val(key))]
)).coerceTo('object')
}
r.table(...).update(row => updateStats(row, r(updateVal)).run(conn)
// test in admin panel
updateStats(r({
id: 1,
statistics: {
stat1: 1,
global: {
stat2: 3
},
stat111: 99
}
}), r({
statistics: {
stat1: 8,
global: {
stat2: 6
},
stat4: 3
}
}))
I am running the following test:
describe("objects", function () {
it("should equal", function () {
var a = {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
x: 3
}
}
};
var b = {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
x: 4
}
}
};
a.should.deep.equal(b);
});
});
The test fails as expected, but the error message is not at all helpful.
AssertionError: expected { Object (a, b, ...) } to deeply equal { Object (a, b, ...) }
How would I get it so that it outputs a prettified json comparison instead?
Libraries I am currently using:
karma 0.12.1
karma-mocha 0.1.6
karma-mocha-reporter 0.3.0
karma-chai 0.1.0
You can change where the message gets truncated with the following:
chai.config.truncateThreshold = 0
So for your example:
var chai = require('chai');
var expect = chai.expect;
chai.config.truncateThreshold = 0;
describe.only("objects", function () {
it("should equal", function () {
var a = {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
x: 3
}
}
};
var b = {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
x: 4
}
}
};
expect(a).to.deep.equal(b);
});
});
Which will result in:
AssertionError: expected { a: 1, b: 2, c: { a: 1, b: 2, c: { a: 1, b: 2, x: 3 } } } to deeply equal { a: 1, b: 2, c: { a: 1, b: 2, c: { a: 1, b: 2, x: 4 } } }
+ expected - actual
"b": 2
"c": {
"a": 1
"b": 2
+ "x": 4
- "x": 3
}
}
}
The mocha reporter has an option for this: showDiff: true
You can stick this in your karma config:
config.set({
frameworks: [ 'mocha', 'chai', ... ],
plugins: [
require('karma-mocha'),
require('karma-chai'),
require('karma-mocha-reporter'),
...
],
reporters: [ 'mocha', ... ],
mochaReporter: {
showDiff: true, // <-- This!
},
...
});
You can use assert-diff library to show only the difference when test fails.
var assert = require('assert-diff');
describe("objects", function () {
it("should equal", function () {
var a = {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
x: 3
}
}
};
var b = {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
x: 4
}
}
};
assert.deepEqual(a, b);
});
});
this will give you an error with the difference
1) objects should equal:
AssertionError: { a: 1, b: 2, c: { a: 1, b: 2, c: { a: 1, b: 2, x: 3 } } } deepEqual { a: 1, b: 2, c: { a: 1, b: 2, c: { a: 1, b: 2, x: 4 } } }
{
c: {
c: {
- x: 4
+ x: 3
}
}
}