Why is the downcast_ref method not found for the dyn Any type? - casting

I am trying to create my own mocking framework and I've bumped into this problem. When I try to downcast my Any type, it does not find the downcast_ref method:
use std::any::Any;
use std::collections::HashMap;
struct X;
struct Y;
fn main() {
let mut map: HashMap<&'static str, Box<Any + Sync>> = HashMap::new();
map.insert("x", Box::new(X));
map.insert("y", Box::new(Y));
get_x(map);
}
fn get_x(map: HashMap<&'static str, Box<Any + Sync>>) {
let ref any = map["x"];
let res = Any::downcast_ref::<X>(any); // Works
let res = any.downcast_ref::<X>(); // Fails
}
Playground
error[E0599]: no method named `downcast_ref` found for type `&std::boxed::Box<(dyn std::any::Any + std::marker::Sync + 'static)>` in the current scope
--> src/main.rs:18:19
|
18 | let res = any.downcast_ref::<X>();
| ^^^^^^^^^^^^
If I call it using the associated function syntax, it finds the function and works with no problem.
Why can the compiler not find the downcast_ref() method from the variable any which is a dyn Any type?

That is because Any::downcast_ref() is not implemented for dyn Any + 'static + Sync, only for:
dyn Any + 'static
dyn Any + 'static + Send
dyn Any + 'static + Send + Sync

Related

how to log size of array with ilog

I have this code and just want to log size of array :
auto owner = abi_data["owner"].as<chain::authority>();
auto arrSize = std::size(owner.keys);
ilog(arrSize);
But have an error :
error: no matching constructor for initialization of 'fc::log_message'
How can i fix it?
I understand that the c ++ methodology is very specific. Therefore, I will expand my question and thus grope the way.
how to get public key string from auto owner.
i tried :
std::string k = owner.keys[0].key
error: no viable conversion from 'eosio::chain::public_key_type' (aka 'fc::crypto::public_key') to 'std::string'
I don’t understand how I should transform all this for correct work and get correct public key and replace hardcoded old_account_name .
full code :
else if (action.name == N(newaccount)) {
auto new_account_name = abi_data["newact"].as<chain::name>().to_string();
auto creator = abi_data["creator"].as<chain::name>().to_string();
std::string old_account_name = "EOS7ea3Dj15nUkKz3diU7BmE5FV5aNKsBKL6WScwEaKzNwDp41SSU";
auto owner = abi_data["owner"].as<chain::authority>();
auto active = abi_data["active"].as<chain::authority>();
ilog("new_account_name: " + new_account_name + " ,creator: " + creator);
*m_session << "UPDATE user_address SET address = :nan WHERE crypto_currency_asset_id = :ai AND address = :oan",
soci::use(new_account_name, "nan"),
soci::use(old_account_name, "oan"),
soci::use(asset_id, "ai");
}
FIXED!
auto arrSize = sizeof(owner.keys)/sizeof(owner.keys[0]);
auto ownerPK = static_cast<std::string>(owner.keys[0].key);

problem with passing argument to QThreadPool::globalInstance()->start()

So i have this member function in AntiFlood class:
void AntiFlood::unBan()
{
QThread::msleep(5000);
std::string lineToPost = "KICK " + roomToPost +" "+ nickToPost + "\r\n";
sendIT(lineToPost);
}
and i want to pass it to:
threadpool.globalInstance()->start(unBan);
which doesnt work - results with error: no matching function for call to 'QThreadPool::start()' threadpool.globalInstance()->start(unBan);
^;
but on the other hand if i use lambda:
auto lam = [this, room, nick](){
QThread::msleep(5000);
std::string lineToPost = "KICK " + roomToPost +" "+ nickToPost + "\r\n";
sendIT(lineToPost);
};
threadpool.globalInstance()->start(lam);
it works fine.
How do i pass void AntiFlood::unBan( ) to threadpool.globalInstance()->start(), which demands std::function<void()> functionToRun ?
The basic problem you're seeing is that AntiFlood::unBan is (or at least 'appears to be') a non-static member function. That being the case it must be invoked against a valid object of type AntiFlood. Since QThreadPool::start has the signature...
void QThreadPool::start(std::function<void ()> functionToRun, int priority = 0)
you need to pass it a 'self contained' std::function<void()> which is precisely what you're done with...
auto lam = [this, room, nick]()
{
QThread::msleep(5000);
std::string lineToPost = "KICK " + roomToPost +" "+ nickToPost + "\r\n";
sendIT(lineToPost);
};
threadpool.globalInstance()->start(lam);
by capturing this in the lambda.
In short, I'd say the way you're doing things currently is the correct/accepted way.

How to recover the concrete type from Any

Code:
use std::fmt::Debug;
use std::any::Any;
fn any_to_u16(value: &dyn Any)
{
let v = value as u16;
}
fn main()
{
let x = true;
any_to_u16(&x);
}
Erorr :
error[E0606]: casting `&(dyn std::any::Any + 'static)` as `u16` is invalid
--> src/lib.rs:6:13
|
6 | let v = value as u16;
| ^^^^^^^^^^^^
|
= help: cast through a raw pointer first
Playground
How to fix?
You must use Any::downcast_ref:
use std::any::Any;
fn any_to_u16(value: &dyn Any)
{
if let Some(value) = value.downcast_ref::<bool>().map(|b| *b as u16) {
// value is a `bool`
assert_eq!(value, 1);
}
}
fn main()
{
let x = true;
any_to_u16(&x);
}

Designing unit tests when `Result` is not `Copy`

I have a unit test for a container type I'm working on implementing:
#[test]
fn test_get_mut_normal_tail() -> Result<(), ListError> {
let mut actual_list: ArrayList<u64> = ArrayList::new();
let expected_list: ArrayList<u64> = ArrayList {
elems: vec![1, 2, 3, 8],
};
actual_list.append(1)?;
actual_list.append(2)?;
actual_list.append(3)?;
actual_list.append(4)?;
let actual_res: Result<&mut u64, ListError> = actual_list.get_mut(3);
let expected_res: Result<&mut u64, ListError> = Ok(&mut 4);
let elem = actual_res.unwrap();
*elem *= 2;
assert_eq!(actual_list, expected_list);
assert_eq!(actual_res, expected_res);
Ok(())
}
However, rustc complains with:
error[E0382]: borrow of moved value: `actual_res`
--> src\arraylist.rs:358:9
|
351 | let actual_res: Result<&mut u64, ListError> = actual_list.get_mut(3);
| ---------- move occurs because `actual_res` has type `std::result::Result<&mut u64, list::ListError>`, which does not implement the `Copy` trait
...
354 | let elem = actual_res.unwrap();
| ---------- value moved here
...
358 | assert_eq!(actual_res, expected_res);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
Which I don't understand, because the Result docs indicate that Result implements Copy (provided both of the contained types do also). Clearly &mut u64 implements Copy and my ListError type derives it also:
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ListError {
OutOfBounds,
Impossible,
}
The code for ArrayList::get_mut() is here, if relevant:
fn get_mut(&mut self, pos: usize) -> Result<&mut T, ListError> {
if pos >= self.elems.len() { /* bounds check */
return Err(ListError::OutOfBounds);
}
match self.elems.get_mut(pos) {
Some(elem) => Ok(elem),
None => Err(ListError::OutOfBounds)
}
}
In summary, I have two questions:
How do I fix this error?
Is there an underlying issue in either my test or my implementation?
&mut u64 does not actually implement copy. &mut T cannot implement copy to prevent creating multiple simultaneous mutable borrows.
Documentation for reference: https://doc.rust-lang.org/std/primitive.reference.html#trait-implementations
In answer to 1, you can fix the error by using assert_eq!(elem, 4); instead of assert_eq!(actual_res, expected_res);. Or you could use Result::map to modify and return a new result
let actual_res: Result<&mut u64, ListError> = actual_list.get_mut(3).map(|elem| {
*elem *= 2;
elem
};

How do I get the X window class given a window ID with rust-xcb?

I'm trying to use rust-xcb to get a window's class given a window ID.
fn get_class(conn: &xcb::Connection, id: &i32) {
let window: xcb::xproto::Window = *id as u32;
let class_prop: xcb::xproto::Atom = 67; // XCB_ATOM_WM_CLASS from xproto.h
let cookie = xcb::xproto::get_property(&conn, false, window, class_prop, 0, 0, 2);
match cookie.get_reply() {
Ok(reply) => {
let x: &[std::os::raw::c_void] = reply.value();
println!("reply is {:?}", x[0]);
}
Err(err) => println!("err {:?}", err),
}
}
The documentation is kind of sparse and hasn't been incredibly helpful, though I did find this bit about the GetPropertyReply and of the xcb_get_property_reply_t it wraps.
I looked at this answer in JavaScript but I don't know what the ctypes equivalent in Rust is. I tried just casting the &[c_void] as a &str or String:
...
Ok(reply) => {
let len = reply.value_len() as usize;
let buf = reply.value() as &str;
println!("{}", buf.slice_unchecked(0, len)); // this seems redundant
}
...
but it returns
error: non-scalar cast: `&[_]` as `&str`
I tried casting the &[c_void] as a &[u8] and then collecting the Vec into a String, which sort of works:
...
Ok(reply) => {
let value : &[u8] = reply.value();
let buf : String = value.into_iter().map(|i| *i as char).collect();
println!("\t{:?}", buf);
}
...
but I'm now getting weird results. for example , when I use xprop on Chrome I see "google-chrome" but for me it is only showing "google-c", and "roxterm" is showing up as "roxterm\u{0}". I'm guessing "\u{0}" is something Unicode related but I'm not sure, and I don't know why stuff is being concatenated either. Maybe I have to check the reply again?
Here's my updated function:
fn get_class(conn: &Connection, id: &i32) -> String {
let window: xproto::Window = *id as u32;
let long_length: u32 = 8;
let mut long_offset: u32 = 0;
let mut buf = Vec::new();
loop {
let cookie = xproto::get_property(
&conn,
false,
window,
xproto::ATOM_WM_CLASS,
xproto::ATOM_STRING,
long_offset,
long_length,
);
match cookie.get_reply() {
Ok(reply) => {
let value: &[u8] = reply.value();
buf.extend_from_slice(value);
match reply.bytes_after() {
0 => break,
_ => {
let len = reply.value_len();
long_offset += len / 4;
}
}
}
Err(err) => {
println!("{:?}", err);
break;
}
}
}
let result = String::from_utf8(buf).unwrap();
let results: Vec<&str> = result.split('\0').collect();
results[0].to_string()
}
There were three main parts to this question:
I put xproto::get_property() in a loop so I could check reply.bytes_after() and accordingly adjust long_offset. I think with an appropriate long_length there will usually only be one read, but just being safe.
As #peter-hall said, converting &[u8] -> String should be done using String::from_utf8, which needs a Vec; so I let mut buf = Vec::new() and buf.extend_from_slice over the loop before creating the result string with String::from_utf8(buf).unwrap()
According to this random page WM_CLASS is actually two consecutive null-terminated strings, so I split the result by \0 and grab the first value.
I might've just been looking in the wrong place, but xcb has absolutely terrible documentation..