How do I use trait bound in Rust? - rust

I am going to use generic to pass A<B<C>>>> and Z<A<B<C>>>> to a function as one type. But I don't know how to implement trait bounds for this. The detail are as follows.
http service and https service each have listener and poll for accept. When an accept request comes in, handle_request() is called to process the request.
The http and https request processing methods are the same, but in the case of https, TlsService is additionally implemented to include tls processing. As a result, it has the following structure:
pub type RawRequest = HttpService<AccessLog<RouteService<CorsService<ProxyService>>>>;
pub struct Services {
http_service: Arc<RawRequest>,
https_service: Arc<TlsService<RawRequest>>,
http_accept_service: AcceptService,
https_accept_service: AcceptService,
}
...
fn handle_request<S>(stream: TcpStream, accesslog_sender: crossbeam_channel::Sender<String>, http_service: S) {
let connection = NewConnection {
stream,
service_builder: ServiceBuilder::new(),
};
tokio::spawn(async move {
ACCESSLOG_SENDER
.scope(accesslog_sender, async move {
if let Err(_e) = http_service.call(connection).await {
// TODO: write error
};
})
.await;
});
}
handle_request(stream, accesslog_sender, services.http_accept_service.clone());
handle_request(stream, accesslog_sender, services.https_accept_service.clone());
Question
I am going to use generic to call the same function for different types of Service.
fn handle_request<S>(
stream: TcpStream,
accesslog_sender: crossbeam_channel::Sender<String>,
http_service: S,
) {
...
}
But I get a trait bound error.
error[E0599]: no method named `call` found for type parameter `S` in the current scope
I'm new to Rust and I'm struggling with generic and trait bound. Please help me how to write

When you use a generic type like S rust will not make any assumptions about that type (expect that it has a compile time known size). Therefore you cannot really do anything on that type. For the compiler there is no way to know that a call() method exists.
This is different from how C++ handles generics where you would get long and hard to read compiler errors when using a type for S which does not have all the functionality used by the generic function.
The solution in Rust is a trait. Lets suppose both your http and https service have a call function. You can then write a trait (or more likely use one from the library your using) which says that these types have a call method. You can then use this trait as a trait bound in your function like this: handle_request<S : Name_of_the_trait>
This tells the compiler to only use types as a substitute for S which implement Name_of_the_trait and therefore you can call all the functions of this trait on S.
I guess you should read more about traits and it should become apparent what you should do in detail.
https://doc.rust-lang.org/stable/book/ch10-00-generics.html

Related

How do I inspect function arguments at runtime in Rust?

Say I have a trait that looks like this:
use std::{error::Error, fmt::Debug};
use super::CheckResult;
/// A Checker is a component that is responsible for checking a
/// particular aspect of the node under investigation, be that metrics,
/// system information, API checks, load tests, etc.
#[async_trait::async_trait]
pub trait Checker: Debug + Sync + Send {
type Input: Debug;
/// This function is expected to take input, whatever that may be,
/// and return a vec of check results.
async fn check(&self, input: &Self::Input) -> anyhow::Result<Vec<CheckResult>>;
}
And say I have two implementations of this trait:
pub struct ApiData {
some_response: String,
}
pub MetricsData {
number_of_events: u64,
}
pub struct ApiChecker;
impl Checker for ApiChecker {
type Input = ApiData;
// implement check function
}
pub struct MetricsChecker;
impl Checker for MetricsChecker {
type Input = MetricsData;
// implement check function
}
In my code I have a Vec of these Checkers that looks like this:
pub struct MyServer {
checkers: Vec<Box<dyn Checker>>,
}
What I want to do is figure out, based on what Checkers are in this Vec, what data I need to fetch. For example, if it just contained an ApiChecker, I would only need to fetch the ApiData. If both ApiChecker and MetricsChecker were there, I'd need both ApiData and MetricsData. You can also imagine a third checker where Input = (ApiData, MetricsData). In that case I'd still just need to fetch ApiData and MetricsData once.
I imagine an approach where the Checker trait has an additional function on it that looks like this:
fn required_data(&self) -> HashSet<DataId>;
This could then return something like [DataId::Api, DataId::Metrics]. I would then run this for all Checkers in my vec and then I'd end up a complete list of data I need to get. I could then do some complicated set of checks like this:
let mut required_data = HashSet::new();
for checker in checkers {
required_data.union(&mut checker.required_data());
}
let api_data: Option<ApiData> = None;
if required_data.contains(DataId::Api) {
api_data = Some(get_api_data());
}
And so on for each of the data types.
I'd then pass them into the check calls like this:
api_checker.check(
api_data.expect("There was some logic error and we didn't get the API data even though a Checker declared that it needed it")
);
The reasons I want to fetch the data outside of the Checkers is:
To avoid fetching the same data multiple times.
To support memoization between unrelated calls where the arguments are the same (this could be done inside some kind of Fetcher trait implementation for example).
To support generic retry logic.
By now you can probably see that I've got two big problems:
The declaration of what data a specific Checker needs is duplicated, once in the function signature and again from the required_data function. This naturally introduces bug potential. Ideally this information would only be declared once.
Similarly, in the calling code, I have to trust that the data that the Checkers said they needed was actually accurate (the expect in the previous snippet). If it's not, and we didn't get data we needed, there will be problems.
I think both of these problems would be solved if the function signature, and specifically the Input associated type, was able to express this "required data" declaration on its own. Unfortunately I'm not sure how to do that. I see there is a nightly feature in any that implements Provider and Demand: https://doc.rust-lang.org/std/any/index.html#provider-and-demand. This sort of sounds like what I want, but I have to use stable Rust, plus I figure I must be missing something and there is an easier way to do this without going rogue with semi dynamic typing.
tl;dr: How can I inspect what types the arguments are for a function (keeping in mind that the input might be more complex than just one thing, such as a struct or tuple) at runtime from outside the trait implementer? Alternatively, is there a better way to design this code that would eliminate the need for this kind of reflection?
Your problems start way earlier than you mention:
checkers: Vec<Box<dyn Checker>>
This is an incomplete type. The associated type Input means that Checker<Input = ApiData> and Checker<Input = MetricsData> are incompatible. How would you call checkers[0].check(input)? What type would input be? If you want a collection of "checkers" then you'll need a unified API, where the arguments to .check() are all the same.
I would suggest a different route altogether: Instead of providing the input, provide a type that can retrieve the input that they ask for. That way there's no need to coordinate what type the checkers will ask for in a type-safe way, it'll be inherent to the methods the checkers themselves call. And if your primary concern is repeatedly retrieving the same data for different checkers, then all you need to do is implement caching in the provider. Same with retry logic.
Here's my suggestion:
struct DataProvider { /* cached api and metrics */ }
impl DataProvider {
fn fetch_api_data(&mut self) -> anyhow::Result<ApiData> { todo!() }
fn fetch_metrics_data(&mut self) -> anyhow::Result<MetricsData> { todo!() }
}
#[async_trait::async_trait]
trait Checker {
async fn check(&self, data: &mut DataProvider) -> anyhow::Result<Vec<CheckResult>>;
}
struct ApiAndMetricsChecker;
#[async_trait::async_trait]
impl Checker for ApiAndMetricsChecker {
async fn check(&self, data: &mut DataProvider) -> anyhow::Result<Vec<CheckResult>> {
let _api_data = data.fetch_api_data()?;
let _metrics_data = data.fetch_metrics_data()?;
// do something with api and metrics data
todo!()
}
}

Deref Mutex/RwLock to inner object with implicit locking

I have a struct Obj with a large API that I would also like to use through an Arc<RwLock<Obj>>. I have defined a struct ObjRef(Arc<RwLock<Obj>>) and want to call functions of Obj on ObjRef without needing to call .read().unwrap() or .write().unwrap() every time. (ObjRef implements Deref<Target=Arc<RwLock<Obj>>, so I only have to call objRef.read().unwrap())
I could implement all of the functions of Obj again for ObjRef in a manner like this:
impl ObjRef {
fn foo(&self, arg: Arg) -> Ret {
self.read().unwrap().foo(arg)
}
}
But doing this for every function results in a lot of boilerplate.
Implementing Deref<Target=Obj> for ObjRef does not work, because the deref implementation would be returning a reference into the RwReadLockGuard object returned by .read().unwrap() which would be dropped after deref:
impl Deref for ObjRef {
type Target = Obj;
fn deref(&self) -> &Self::Target {
let guard: RwLockReadGuard<'_, Obj> = self.0.read().unwrap();
&*guard // <- return reference to Obj referenced by guard
// guard is dropped now, reference lifetime ends
}
}
Is there a way to call the Obj Api through a low boilerplate implementation doing the locking internally?
I am thinking about introducing a trait for the Api with a default implementation of the Api and a single function to be implemented by users of the trait for getting a generic Deref<Target=Obj>, but this puts the Api under some limitations, for example using generic parameters will become much more complicated.
Is there maybe a better way, something that lets me use any Obj through a lock without explicitly calling the locking mechanism every time?
It is not possible to do this through Deref, because Deref::deref always returns a plain reference — the validity of it must only depend on the argument continuing to exist (which the borrow checker understands), not on any additional state such as "locked".
Also, adding locking generically to an interface designed without it is dangerous, because it may accidentally cause deadlocks, or allow unwanted outcomes due to doing two operations in sequence that should have been done using a single locking.
I recommend considering making your type internally an Arc<RwLock, that is,
pub struct Obj {
lock: Arc<RwLock<ObjData>>,
}
// internal helper, not public
struct ObjData {
// whatever fields Obj would have had go here
}
Then, you can define your methods once, directly on Obj, and the caller never needs to deal with the lock explicitly, but your methods can handle it exactly as needed. This is a fairly common pattern in problem domains that benefit from it, like UI objects.
If there is some reason why Obj really needs to be usable with or without the lock, then define a trait.

How to use PalletB to save record from PalletA without PalletA knowing anything about internals of the saving in substrate and rust

I'd like to save a record from PalletA in PalletB by simply passing the raw data and waiting for the return.
I have tried following:
// ./PalletB/lib.rs
pub trait PutInStorage {
fn put_rule_in_storage(value: u32);
}
impl<T: Trait> PutInStorage for Module<T> {
fn put_rule_in_storage(value: u32) {
SimpleCounter::put(value);
}
}
then in
// ./PalletA/lib.rs
use palletB::{PutInStorage, Trait as PalletBTrait};
///The pallet's configuration trait.
pub trait Trait: system::Trait + PalletBTrait {
/// The overarching event type.
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
type ExternalStorage: PutInStorage;
}
then I added the definition to the runtime like this:
// ./runtime/lib.rs
// near the construct_runtime macro
impl palletA::Trait for Runtime {
type Event = Event;
type ExternalStorage = palletB::Module<Runtime>;
}
So far this passes the check but not the test. The test configuration for the trait is like this:
use palletB::{PutInStorage, Trait as PalletBTrait};
impl Trait for Test {
type Event = ();
type ExternalStorage = PutInStorage;
}
and this fails with the:
type ExternalRulesStorage = PutInStorage;
^^^^^^^^^^^^ help: use `dyn`: `dyn PutInStorage`
impl Trait for Test
------------------- in this `impl` item
type Event = ();
type ExternalRulesStorage = PutInStorage;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
type ExternalRulesStorage = PutInStorage;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `pallet_rules::PutInStorage` cannot be made into an object
I tried all the suggestions the Rust compiler gives me but without any luck. Before someone asks why do I need this in my test, it's because a dispatchable fn in decl_module! checks does a certain record exists before starts processing and saving its own records. It is dependent on record to exist.
To make the compiler happy, your test config must also have an instance of PalletB, or anything else that implements PutInStorage.
Similar to what you've done already in ./runtime/lib.rs:
impl Trait for Test {
type Event = ();
type ExternalStorage = palletB::Module<Test>;
}
Note that now struct Test is the one playing the role of Runtime. I think this is the only thing that you are missing.
That being said, you seem to be on the wrong track in the overall design.
PalletA already depends on PalletB. Given that you also have a trait to link the two PutInStorage, this is not a good design. Generally, you should try and always chose one of the following:
Two pallets will depend on one another. In this case you don't need traits. If one needs to put something to the storage of the other one, you just do it directly. In your example, I assume that PalletB has a storage item called pub Foo: u32 in decl_storage and PutInStorage writes to this. If this is the case, there's no need for a trait. From PalletA you can just say: palletB::Foo::put(value).
Note that this approach should be chosen with care, otherwise you might end up with a lot of pallets depending on one another which is not good.
You decide that your pallets do NOT depend on one another, in which case you use some trait like PutInStorage. Your code seem to be aligned with this approach, except you define PalletA's Trait as pub trait Trait: system::Trait. There's no need to depend on PalletB here, and of course you can wipe it from Cargo.toml as well.

How do I create a class with multiple instantiation options

I want to build a class in Rust that allows for variety and convenience in its instantiation similar to the way that std::net::TcpStream can be provided multiple inputs to its connect method.
I have the following tests, but very little idea of the structs or traits I need to build to achieve this result.
#[cfg(test)]
mod test {
use super::Ipv4Network;
use std::net::Ipv4Addr;
#[test]
fn instantiation() {
let net_addr = Ipv4Addr::new(10, 0, 0, 0);
let net_mask = Ipv4Addr::new(255, 255, 255, 240);
// Instantiate an Ipv4Network using two Ipv4Addrs.
let with_addrs = Ipv4Network::new(net_addr, net_mask);
// Instantiate an Ipv4Network using an Ipv4Addr and a prefix integer.
let with_addr_prefix = Ipv4Network::new(net_addr, 28);
// Instantiate an Ipv4Network using two strings.
let with_strings = Ipv4Network::new("10.0.0.0", "255.255.255.240");
// Instantiate an Ipv4Network using a string and a prefix integer.
let with_prefix = Ipv4Network::new("10.0.0.0", 28);
// Instantiate an Ipv4Network using a string with CIDR notation.
let with_cidr = Ipv4Network::new("10.0.0.0/28");
}
}
My understanding is that std::net::TcpStream accomplishes its multiple connect inputs through the ToSocketAddrs trait, the source of which can be found here. How exactly std::net:TcpStream::connect uses ToSocketAddrs isn't clear to me, but I imagine I should be able to define an Ipv4Network as follows:
pub struct Ipv4Network {
addr: Ipv4Addr,
mask: Ipv4Addr,
}
If that's true then how do I go about creating a trait (say ToIpv4Network) that functions like ToSocketAddrs does for std::net:TcpStream?
What should the meat of
impl ToIpv4Network for (Ipv4Addr, Ipv4Addr) {
...
}
look like? Is that even the right path to start going down?
That's a reasonable place to start working from. I think one of your issues is that the interfaces you have defined are going to be difficult to accomplish as written by using a trait.
So, let's talk about the way that ToSocketAddrs works. First, let's just quickly note and then ignore the fact that the ToSocketAddrs trait returns an Iterator of SocketAddrs. We're ignoring it because it's actually irrelevant to the question at hand.
Here's the body of the trait declaration:
pub trait ToSocketAddrs {
type Iter: Iterator<Item=SocketAddr>;
fn to_socket_addrs(&self) -> Result<Self::Iter>;
}
The purpose of this trait is to allow it to be used as a trait bound in a generic function/struct. Broadly speaking, trait bounds are a way of writing a generic but getting the Rust compiler to ensure that the type that ends up instantiating the generic implements the behavior defined by that trait (or traits.
In the case of ToSocketAddrs this means that a type can (potentially) be converted to a SocketAddr. The code that is called inside of connect then makes use of the to_socket_addrs function defined on the trait.
As a brief aside, I said potentially because to_socket_addrs returns a Result which can take on values of Ok(<success-type>) and Err(<failure-type>), which is probably a good pattern to model your trait on.
This is the key point that relates to why I think your desired interface is maybe not ideal (or implementable, Rust doesn't directly support arity, or any other type of function overloading). Passing a trait bound generic parameter is the easiest way to accomplish your goal.

Trait with methods that take generic parameters [duplicate]

When compiling the following code:
trait RenderTarget {}
struct RenderWindow;
impl RenderTarget for RenderWindow {}
trait Drawable {
fn draw<RT: RenderTarget>(&self, target: &mut RT);
}
fn main() {
let mut win = RenderWindow;
let mut vec: Vec<Box<Drawable>> = Vec::new();
for e in &vec {
e.draw(&mut win);
}
}
I get the error:
error: the trait `Drawable` is not implemented for the type `Drawable` [E0277]
src/main.rs:15 e.draw(&mut win);
^~~~~~~~~~~~~~
What is the error message trying to tell? Also, how to fix it?
There's a related question but the solution there was to modify the trait A (which corresponds to Drawable in my case), but that's not possible here since Drawable is from an external library.
Update: fixed object safety rules to the 1.0 version of them. Namely, by-value self makes method object-unsafe no longer.
This error happens because of object safety.
In order to be able to create a trait object out of a trait, the trait must be object-safe. A trait is object-safe if both of these statements hold:
it does not have Sized requirement, as in trait Whatever: Sized {};
all its methods are object-safe.
A method is object-safe if both of these statements are true:
it has where Self: Sized requirement, as in fn method() where Self: Sized;
none of the following statements holds:
this method mentions Self in their signature in any form, even under a reference, except associated types;
this method is static;
this method is generic.
These restrictions are in fact fairly natural if you think more of them.
Remember that when values are made into trait objects, actual information of their type is erased, including their size. Therefore, trait objects can only be used through a reference. References (or other smart pointers, like Box or Rc), when applied to trait objects, become "fat pointers" - along with the pointer to the value, they also contain a pointer to the virtual table for that value.
Because trait objects can only be used through a pointer, by-value self methods can't be called on them - you'd need the actual value in order to call such methods. This was a violation of object safety at one point, which meant that traits with such methods couldn't be made trait objects, however, even before 1.0 the rules had been tweaked to allow by-value self methods on trait objects. These methods still can't be called, though, due to the reason described above. There are reasons to expect that in the future this restriction will be lifted because it currently leads to some quirks in the language, for example, the inability to call Box<FnOnce()> closures.
Self can't be used in methods which should be called on trait objects precisely because trait objects have their actual type erased, but in order to call such methods the compiler would need to know this erased type.
Why static methods can't be called on trait objects, I guess, is obvious - static methods by definition "belong" to the trait itself, not to the value, so you need to know the concrete type implementing the trait to call them. More concretely, regular methods are dispatched through a virtual table stored inside a trait object, but static methods do not have a receiver, so they have nothing to dispatch on, and for this reason they can't be stored in a virtual table. Thus they are uncallable without knowing the concrete type.
Generic trait methods can't be called for another reason, more technical than logical, I think. In Rust generic functions and methods are implemented through monomorphization - that is, for each instantiation of a generic function with a concrete set of type parameters the compiler generate a separate function. For the language user it looks like that they're calling a generic function; but on the lowest level for each set of type parameters there is a separate copy of the function, specialized to work for the instantiated types.
Given this approach, in order to call generic methods on a trait object you would need its virtual table to contain pointers to virtually each and every possible instantiation of the generic method for all possible types, which is, naturally, impossible because it would require infinite number of instantiations. And so calling generic methods on trait objects is disallowed.
If Drawable is an external trait, then you're stuck - it is impossible to do what you want, that is, to call draw() on each item in a heterogeneous collection. If your set of drawables is statically known, you can create a separate collection for each drawable type or, alternatively, create your own enum which would contain a variant for each drawable type you have. Then you can implement Drawable for the enum itself, which would be fairly straightforward.
I refer to Vladimir's excellent answer which explains Object's safety, however I am afraid than in the middle of the discussion the concrete problem at hand was forgotten.
As Vladimir mentions, the issue is that a method generic over types (generic over lifetimes is fine) renders the trait it belongs to unusable for run-time polymorphism; this, in Rust, is called Object Safety.
The simplest fix, therefore, is to remove the generic parameter of the method!
trait RenderTarget {}
struct RenderWindow;
impl RenderTarget for RenderWindow {}
trait Drawable {
fn draw(&self, target: &mut RenderTarget);
}
fn main() {
let mut win = RenderWindow;
let mut vec: Vec<Box<Drawable>> = Vec::new();
for e in &vec {
e.draw(&mut win);
}
}
The main difference between:
fn draw<RT: RenderTarget>(&self, target: &mut RT)
and
fn draw(&self, target: &mut RenderTarget)
is that the latter requires RenderTarget to be Object Safe too as it is now used in a run-time polymorphism situation (so, no static method, no generic method, no Self, ...).
Another (more technical) difference is that the former is "monorphised" at compile-time (that is RT is substituted with the real type and all relevant optimizations applied) whereas the latter is not (and so, no such optimizations occur).
If you're stuck with what you're given, there are two options you could try.
In this case, you can't, but if you were given an unsized RenderTarget
trait Drawable {
fn draw<RT: RenderTarget + ?Sized>(&self, target: &mut RT);
}
you could implement
trait DrawableDynamic {
fn draw(&self, target: &mut RenderTarget);
}
impl<T: Drawable> DrawableDynamic for T {
fn draw(&self, target: &mut RenderTarget) {
Drawable::draw(self, target)
}
}
to redirect the types you're given to an object-safe dynamically dispatched alternative. It looks like such a change could be made upstream, since you can't really use the fact that RT is sized.
The other doesn't allow you to put arbitrary Drawables in your Vec, but should work without allowing unsized types upstream. This is to use an enum to wrap the possible values of the vector:
enum AllDrawable {
Square(Square),
Triangle(Triangle)
}
impl Drawable for AllDrawable {
fn draw<RT: RenderTarget>(&self, target: &mut RT) {
match *self {
AllDrawable::Square(ref x) => x.draw(target),
AllDrawable::Triangle(ref x) => x.draw(target),
}
}
}
One might want to add From implementations and such; you might find it easier if using wrapped_enum! which will automatically implement those for you.

Resources