How to compile this rust code using GATs? - rust

I wrote the rust code using generic associated types like below:
#![feature(generic_associated_types)]
pub trait Foo {
type Arg<N: Clone>;
fn foo<N: Clone>(arg: Self::Arg<N>) {
println!("hello");
}
}
pub fn call_foo<N: Clone, F: Foo<Arg<N> = N>>() {
// I want to create this Box value here
let a = Box::new(1);
F::foo(a);
}
This code causes the following compilation error:
error[E0283]: type annotations needed
--> core/src/utils.rs:33:5
|
33 | F::foo(a);
| ^^^^^^ cannot infer type for type parameter `N` declared on the associated function `foo`
|
= note: cannot satisfy `_: Clone`
note: required by a bound in `Foo::foo`
--> core/src/utils.rs:26:15
|
26 | fn foo<N: Clone>(arg: Self::Arg<N>) {
| ^^^^^ required by this bound in `Foo::foo`
help: consider specifying the type argument in the function call
|
33 | F::foo::<N>(a);
| +++++
And when I fix the code following the help message, I got another error:
error[E0308]: mismatched types
--> core/src/utils.rs:33:17
|
31 | pub fn call_foo<N: Clone, F: Foo<Arg<N> = N>>() {
| - this type parameter
32 | let a = Box::new(1);
33 | F::foo::<N>(a);
| ----------- ^ expected type parameter `N`, found struct `Box`
| |
| arguments to this function are incorrect
|
= note: expected type parameter `N`
found struct `Box<{integer}>`
note: associated function defined here
--> core/src/utils.rs:26:8
|
26 | fn foo<N: Clone>(arg: Self::Arg<N>) {
| ^^^ -----------------
F::foo::<Box<usize>>(a) also causes the same error error[E0308]: mismatched types .
Can I compile this code?

Related

Define variable of type TimeZone

The following compiles and runs fine:
use chrono_tz::Tz;
use chrono::{TimeZone, NaiveDate};
use arrow2::temporal_conversions::parse_offset;
fn my_func(tz: &str) -> (){
let ndt = NaiveDate::from_ymd_opt(2018, 9, 28).unwrap().and_hms_opt(2, 30, 0).unwrap();
match parse_offset(&tz) {
Ok(time_zone) => {
println!("converted: {:?}", time_zone.from_utc_datetime(&ndt));
},
Err(_) => match tz.parse::<Tz>() {
Ok(time_zone) => {
println!("converted: {:?}", time_zone.from_utc_datetime(&ndt));
}
Err(error) => panic!("Problem opening the file: {:?}", error)
},
};
}
fn main() {
let time_zone = "Asia/Seoul";
my_func(&time_zone);
}
Noticed though that I'm doing
println!("converted: {:?}", time_zone.from_utc_datetime(&ndt));
twice.
I've tried refactoring to
use chrono_tz::Tz;
use chrono::{TimeZone, NaiveDate};
use arrow2::temporal_conversions::parse_offset;
fn my_func(tz: &str) -> (){
let ndt = NaiveDate::from_ymd_opt(2018, 9, 28).unwrap().and_hms_opt(2, 30, 0).unwrap();
let parsed_time_zone: TimeZone = match parse_offset(&tz) {
Ok(time_zone) => {
time_zone
},
Err(_) => match tz.parse::<Tz>() {
Ok(time_zone) => {
time_zone
}
Err(error) => panic!("Problem opening the file: {:?}", error)
},
};
println!("converted: {:?}", parsed_time_zone.from_utc_datetime(&ndt));
}
fn main() {
let time_zone = "Asia/Seoul";
my_func(&time_zone);
}
and get a long error:
error[E0782]: trait objects must include the `dyn` keyword
--> src/main.rs:7:27
|
7 | let parsed_time_zone: TimeZone = match parse_offset(&tz) {
| ^^^^^^^^
|
help: add `dyn` keyword before this trait
|
7 | let parsed_time_zone: dyn TimeZone = match parse_offset(&tz) {
| +++
error[E0191]: the value of the associated type `Offset` (from trait `TimeZone`) must be specified
--> src/main.rs:7:27
|
7 | let parsed_time_zone: TimeZone = match parse_offset(&tz) {
| ^^^^^^^^ help: specify the associated type: `TimeZone<Offset = Type>`
error[E0038]: the trait `TimeZone` cannot be made into an object
--> src/main.rs:7:27
|
7 | let parsed_time_zone: TimeZone = match parse_offset(&tz) {
| ^^^^^^^^ `TimeZone` cannot be made into an object
|
= note: the trait cannot be made into an object because it requires `Self: Sized`
= note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
error[E0308]: mismatched types
--> src/main.rs:9:13
|
9 | time_zone
| ^^^^^^^^^ expected trait object `dyn TimeZone`, found struct `FixedOffset`
|
= note: expected trait object `dyn TimeZone`
found struct `FixedOffset`
error[E0308]: mismatched types
--> src/main.rs:13:17
|
13 | time_zone
| ^^^^^^^^^ expected trait object `dyn TimeZone`, found enum `Tz`
|
= note: expected trait object `dyn TimeZone`
found enum `Tz`
error: the `from_utc_datetime` method cannot be invoked on a trait object
--> src/main.rs:18:50
|
18 | println!("converted: {:?}", parsed_time_zone.from_utc_datetime(&ndt));
| ^^^^^^^^^^^^^^^^^
|
::: /home/marcogorelli/.cargo/registry/src/github.com-1ecc6299db9ec823/chrono-0.4.23/src/offset/mod.rs:205:21
|
205 | pub trait TimeZone: Sized + Clone {
| ----- this has a `Sized` requirement
Some errors have detailed explanations: E0038, E0191, E0308, E0782.
For more information about an error, try `rustc --explain E0038`.
error: could not compile `tmp` due to 6 previous errors
I've tried the suggestion to do
let parsed_time_zone: dyn TimeZone = match parse_offset(&tz) {
but then it still errors with
error[E0191]: the value of the associated type `Offset` (from trait `TimeZone`) must be specified
--> src/main.rs:7:31
|
7 | let parsed_time_zone: dyn TimeZone = match parse_offset(&tz) {
| ^^^^^^^^ help: specify the associated type: `TimeZone<Offset = Type>`
How can I just parse tz as TimeZone, without specified whether it's Tz or FixedOffset, and then use it in the rest of the function?
You can't refactor this easily. Rust is strongly typed, and your two time_zone variables aren't the same type. One is chrono::FixedOffset, the other is chrono_tz::Tz.
If you do want to store both of them in the same variable, you have two possibilities:
trait object references (&dyn TimeZone)
Boxed trait objects (Box<dyn TimeZone).
dyn Timezone itself cannot directly be the type of a variable. It doesn't have a known size, because it could be any actual type of any size. Therefore you need one of the indirections above.
Both are non-ideal for your case though:
&dyn TimeZone won't work because someone has to own the actual object. You can't return a reference to a variable of an inner scope, as it gets dropped earlier than the reference does.
Box<dyn TimeZone> would work, no problem, but it introduces overhead: It will cause a heap allocation where the actual object will be put. The reason, as described earlier, is that a dyn object doesn't have a known size. Therefore, with Box, the actual object gets moved to the heap, and on the stack is the Box object, which has a known size.
So what I would do is: don't worry. The code duplication you have here is really minimal. I don't think it's worth the trouble.
Further detail I noticed after I wrote this answer:
TimeZone is : Sized, which means it isn't object safe and dyn TimeZone is disallowed entirely. So not even Box<dyn TimeZone> would work.

Cannot determine return type for grpc stream

I am trying to implement a simple stream rpc using tonic and grpc. I have been following the routeguide tutorial.
When I try to return a tokio_stream::wrappers::ReceiverStream from my stream method I get compile error indicating I should return a Result wrapped by a ReceiverStream.
warning: unused manifest key: package.author
Compiling prng_generator v0.1.0 (/home/babbleshack/projects/prng_generator)
error[E0308]: mismatched types
--> src/bin/server.rs:51:46
|
51 | Ok(Response::new(ReceiverStream::new(rx)))
| ^^ expected enum `Result`, found struct `PrngResponse`
|
= note: expected struct `tokio::sync::mpsc::Receiver<Result<PrngResponse, Status>>`
found struct `tokio::sync::mpsc::Receiver<PrngResponse>`
note: return type inferred to be `tokio::sync::mpsc::Receiver<Result<PrngResponse, Status>>` here
--> src/bin/server.rs:41:67
|
41 | ) -> Result<Response<Self::PRNGServiceRequestStream>, Status> {
| ___________________________________________________________________^
42 | | let (mut tx, rx) = mpsc::channel(4);
43 | | let response_data = self.data.clone();
44 | |
... |
51 | | Ok(Response::new(ReceiverStream::new(rx)))
52 | | }
| |_____^
For more information about this error, try `rustc --explain E0308`.
error: could not compile `prng_generator` due to previous error
When I wrap my return channel in a Result I get a contradicting error message:
error[E0308]: mismatched types
--> src/bin/server.rs:51:46
|
51 | Ok(Response::new(ReceiverStream::new(Ok(rx))))
| ^^^^^^ expected struct `tokio::sync::mpsc::Receiver`, found enum `Result`
|
= note: expected struct `tokio::sync::mpsc::Receiver<Result<PrngResponse, Status>>`
found enum `Result<tokio::sync::mpsc::Receiver<PrngResponse>, _>`
note: return type inferred to be `tokio::sync::mpsc::Receiver<Result<PrngResponse, Status>>` here
--> src/bin/server.rs:41:67
|
41 | ) -> Result<Response<Self::PRNGServiceRequestStream>, Status> {
| ___________________________________________________________________^
42 | | let (mut tx, rx) = mpsc::channel(4);
43 | | let response_data = self.data.clone();
44 | |
... |
51 | | Ok(Response::new(ReceiverStream::new(Ok(rx))))
52 | | }
| |_____^
Here is my proto:
use std::sync::Arc;
use tokio::sync::mpsc;
use tonic::{Request, Response, Status};
use tokio_stream::wrappers::ReceiverStream;
pub mod types {
tonic::include_proto!("types");
}
use types::prng_service_server::PrngService;
use types::{PrngRequest, PrngResponse};
And the implementing rust code:
use std::sync::Arc;
use tokio::sync::mpsc;
use tonic::{Request, Response, Status};
use tokio_stream::wrappers::ReceiverStream;
pub mod types {
tonic::include_proto!("types");
}
use types::prng_service_server::PrngService;
use types::{PrngRequest, PrngResponse};
#[derive(Debug, Default)]
pub struct PRNGServiceImpl{
data: Arc<Vec<PrngResponse>>,
}
#[tonic::async_trait]
impl PrngService for PRNGServiceImpl {
type PRNGServiceRequestStream = ReceiverStream<Result<PrngResponse, Status>>;
async fn prng_service_request(
&self,
request: Request<PrngRequest>,
) -> Result<Response<Self::PRNGServiceRequestStream>, Status> {
let (mut tx, rx) = mpsc::channel(256);
let response_data = self.data.clone();
tokio::spawn(async move {
for response in &response_data[..] {
Ok(tx.send(response.clone()).await.unwrap());
}
println!(" /// done sending");
});
Ok(Response::new(ReceiverStream::new(rx)))
//Ok(Response::new(ReceverStream::new(Ok(rx))))
}
}
How do I determine what my return type should be here?
The error message indicates that your return type declares a stream that produces Result<PrngResponse, Status> values, but the stream you have given it produces PrngResponse values. Your attempt to fix the solution wraps the receiver channel in a Result, which is not the same thing.
To fix this, you need to change the type that rx is inferred to be. It's inferred to be a stream of PrngResponse because of the tx.send() call, which sends a PrngResponse, so you can fix this by sending a Result instead:
tx.send(Ok(response.clone()))
The compiler points at the returned value and not the tx.send() line because the problem is the mismatch between the declared return type of the function and what it actually returns. The compiler could probably figure out that this is due to the tx.send() invocation, but in many cases type inference uses information spread out over multiple lines and there may not be one single line responsible for the inferred type of the returned value.
One way you could trace the problem to its source is to provide an explicit type somewhere matching the return type. For example:
let (mut tx, rx) = mpsc::channel::<Result<PrngResponse, Status>>(256);
This change would resolve the return type issue, and the compiler would have then pointed at the tx.send() line indicating that the sent value is not a Result.

Constraint associated type of a generic associated type

I have a type Builder with a Generic Associated Type (GAT) InstanceForBuilder<'a>.
I'd like to write a function (build_with_42_for_bool<Builder>) that constraints the Builder to only those cases where Builder::InstanceForBuilder<'a>::InstanceProperty == bool (for all 'a).
I've been playing around for a while to get the syntax around this for <'a> right, but haven't been able to make this work.
The lifetime can't be a template argument of the function itself, because the reference only lives inside it.
Is this possible at all yet, given that GAT is an unstable feature?
playground
#![feature(generic_associated_types)]
// Trait definitions.
trait Builder {
type InstanceForBuilder<'a>: Instance<'a>;
fn build<'a>(&self, val: &'a usize) -> Self::InstanceForBuilder<'a>;
}
trait Instance<'a> {
// Some functions will only work when the instance has some concrete associated type.
type InstanceProperty;
}
fn build_with_42_for_bool<B: Builder>(builder: B)
where
// TODO: What do I put here to make this work?
for<'a> B::InstanceForBuilder<'a>: Instance<'a, InstanceProperty = bool>,
{
builder.build(&42);
// Do some testing here. The Instance won't be returned.
}
// Now try it out.
struct MyBuilder;
struct MyInstance<'a> {
val: &'a usize,
}
impl Builder for MyBuilder {
type InstanceForBuilder<'a> = MyInstance<'a>;
fn build<'a>(&self, val: &'a usize) -> Self::InstanceForBuilder<'a> {
MyInstance { val }
}
}
impl<'a> Instance<'a> for MyInstance<'a> {
type InstanceProperty = bool;
}
fn main() {
let builder = MyBuilder;
build_with_42_for_bool(builder); // TODO: Doesn't work
}
In my actual code, build_with_42_for_bool is a helper for testing that constructs the arguments passed to build in a specific way. For now I'll probably just inline that function everywhere, since the only problem is how to specify the lifetime of this one function. The code itself works fine.
Here's the full error:
Compiling pairwise-aligner v0.1.0 (/home/philae/git/eth/git/astar-pairwise-aligner)
error[E0271]: type mismatch resolving `for<'a> <<_ as Builder>::InstanceForBuilder<'a> as Instance<'a>>::InstanceProperty == bool`
--> examples/test.rs:45:5
|
45 | build_with_42(builder); // TODO: Doesn't work
| ^^^^^^^^^^^^^ expected `bool`, found associated type
|
= note: expected type `bool`
found associated type `<<_ as Builder>::InstanceForBuilder<'_> as Instance<'_>>::InstanceProperty`
= help: consider constraining the associated type `<<_ as Builder>::InstanceForBuilder<'_> as Instance<'_>>::InstanceProperty` to `bool`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
note: required by a bound in `build_with_42`
--> examples/test.rs:19:53
|
16 | fn build_with_42<B: Builder>(builder: B)
| ------------- required by a bound in this
...
19 | for<'a> B::InstanceForBuilder<'a>: Instance<'a, InstanceProperty = bool>,
| ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `build_with_42`
error[E0271]: type mismatch resolving `for<'a> <MyBuilder as Builder>::InstanceForBuilder<'a> == <MyBuilder as Builder>::InstanceForBuilder<'a>`
--> examples/test.rs:45:5
|
45 | build_with_42(builder); // TODO: Doesn't work
| ^^^^^^^^^^^^^ type mismatch resolving `for<'a> <MyBuilder as Builder>::InstanceForBuilder<'a> == <MyBuilder as Builder>::InstanceForBuilder<'a>`
|
note: expected this to be `<MyBuilder as Builder>::InstanceForBuilder<'a>`
--> examples/test.rs:32:35
|
32 | type InstanceForBuilder<'a> = MyInstance<'a>;
| ^^^^^^^^^^^^^^
= note: expected associated type `<MyBuilder as Builder>::InstanceForBuilder<'a>`
found struct `MyInstance<'a>`
help: a method is available that returns `<MyBuilder as Builder>::InstanceForBuilder<'a>`
--> examples/test.rs:8:5
|
8 | fn build<'a>(&self, val: &'a usize) -> Self::InstanceForBuilder<'a>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider calling `Builder::build`
note: required by a bound in `build_with_42`
--> examples/test.rs:19:40
|
16 | fn build_with_42<B: Builder>(builder: B)
| ------------- required by a bound in this
...
19 | for<'a> B::InstanceForBuilder<'a>: Instance<'a, InstanceProperty = bool>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `build_with_42`
For more information about this error, try `rustc --explain E0271`.
error: could not compile `pairwise-aligner` due to 2 previous errors
The correct syntax to do what you want is:
where B::InstanceForBuilder::InstanceProperty = bool
there's no need to introduce the for<'a> lifetime because the value of the associated type is not allowed to depend on the lifetime parameter. If you compile this code, you'll find that you get another error:
error: equality constraints are not yet supported in `where` clauses
--> src/main.rs:19:5
|
19 | B::InstanceForBuilder::InstanceProperty = bool,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not supported
|
= note: see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
There's no immediate workaround for this. If you badly need this, you may be able to write a new trait, implement it only for bool, and then constrain things to that trait. That will get messy quickly though.
The answer from DreamConspiracy is a little outdated. I'd like to reuse the example codes from him to show a compiled solution
Instead of
where B::InstanceForBuilder::InstanceProperty = bool
You should write
fn build_with_42_for_bool_instance<'a, B, I>(builder: B)
where
B : Builder<InstanceForBuilder<'a>=I>,
I : Instance<'a, InstanceProperty=bool>,
{
builder.build(&42);
}

How to fix the trait `parity_scale_codec::codec::WrapperTypeEncode` is not implemented for `Hash`

I am trying to define Substrate runtime-api. I am using substrate master branch for dependencies.
Here is code
#![cfg_attr(not(feature = "std"), no_std)]
use codec::Codec;
use codec::{Encode, Decode};
sp_api::decl_runtime_apis! {
/// The API to verify barcode
pub trait BarcodeScannerApi<Hash> where
Hash: Codec, {
/// Verify barcode
fn is_valid_barcode(barcode: Hash) -> bool;
}
}
While building code, I am getting below error:
error[E0277]: the trait bound `Hash: parity_scale_codec::codec::WrapperTypeEncode` is not satisfied
--> pallets/barcode-scanner/runtime-api/src/lib.rs:6:1
|
6 | / sp_api::decl_runtime_apis! {
7 | | /// The API to verify barcode
8 | | pub trait BarcodeScannerApi<Hash> where
9 | | Hash: Codec, {
... |
12 | | }
13 | | }
| |_^ the trait `parity_scale_codec::codec::WrapperTypeEncode` is not implemented for `Hash`
|
= note: required because of the requirements on the impl of `sp_api::Encode` for `Hash`
= note: required because of the requirements on the impl of `sp_api::Encode` for `&Hash`
= note: required by `sp_api::Encode::encode`
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider further restricting this bound
|
9 | Hash: Codec + parity_scale_codec::codec::WrapperTypeEncode, {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Please help me to fix this.

Declaring a hashmap (storageMap) in substrate

I want to create a StorageMap in substrate and am following this example to do that. The purpose of the storage map is to have a HashMap where the key will be the account ID of the user and the value will be the count of how many times an invalid transaction has been done. For example:
Adkqwd4324dqlwdOqwdd: 2,
XCvqwd4324dqlwdOqwdd: 0,
Adkqwd4324dqlwdOqwPu: 0,
Xcvqwd4324dqlwdOqwdd: 1
My current decl_storage macro inside transaction_payment>src>lib.rs looks like this:
decl_storage! {
/// StorageMap to keep track of invalid transactions
trait Store for Module<T: Trait> as InvalidTransactionCount {
InvalidTransactionCount get(fn invalid_transaction_count): map hasher(identity) T::AccountId => u32;
}
/// already present in the substrate master code
trait Store for Module<T: Config> as TransactionPayment {
pub NextFeeMultiplier get(fn next_fee_multiplier): Multiplier = Multiplier::saturating_from_integer(1);
StorageVersion build(|_: &GenesisConfig| Releases::V2): Releases;
}
}
However, when I compile this code, I am getting errors related to NextFeeMultiplier because it is not being initialized properly due to the error in the decl_storage macro because of InvalidTransactionCount StorageMap. Full traceback of error is given below:
error: unexpected token
--> frame/transaction-payment/src/lib.rs:242:2
|
242 | trait Store for Module<T: Config> as TransactionPayment {
| ^^^^^
error[E0433]: failed to resolve: use of undeclared type `NextFeeMultiplier`
--> frame/transaction-payment/src/lib.rs:259:4
|
259 | NextFeeMultiplier::mutate(|fm| {
| ^^^^^^^^^^^^^^^^^ use of undeclared type `NextFeeMultiplier`
error[E0433]: failed to resolve: use of undeclared type `NextFeeMultiplier`
--> frame/transaction-payment/src/lib.rs:446:3
|
446 | NextFeeMultiplier::get().saturating_mul_int(Self::weight_to_fee(weight))
| ^^^^^^^^^^^^^^^^^ use of undeclared type `NextFeeMultiplier`
error[E0599]: no function or associated item named `next_fee_multiplier` found for struct `Module<T>` in the current scope
--> frame/transaction-payment/src/lib.rs:414:27
|
249 | / decl_module! {
250 | | pub struct Module<T: Config> for enum Call where origin: T::Origin {
251 | | /// The fee to be paid for making a transaction; the per-byte portion.
252 | | const TransactionByteFee: BalanceOf<T> = T::TransactionByteFee::get();
... |
304 | | }
305 | | }
| |_- function or associated item `next_fee_multiplier` not found for this
...
414 | let multiplier = Self::next_fee_multiplier();
| ^^^^^^^^^^^^^^^^^^^ function or associated item
not found in `Module<T>`
warning: unused import: `StorageMap`
--> frame/transaction-payment/src/lib.rs:46:2
|
46 | StorageMap,
| ^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
error: aborting due to 4 previous errors; 1 warning emitted
Some errors have detailed explanations: E0433, E0599.
For more information about an error, try `rustc --explain E0433`.
error: could not compile `pallet-transaction-payment`
If I remove the InvalidTransactionCount trait Store from the decl_storage, then the code is being compiled fine.
Any help in identifying the correct way to declare a storage map inside the decl_storage macro will be highly appreciated. Thanks!
This line only can be written once. In the decl_module macro.
trait Store for Module<T: Config> as TransactionPayment {
If you want multi storage item just:
decl_storage! {
trait Store for Module<T: Trait> as InvalidTransactionCount {
InvalidTransactionCount get(fn invalid_transaction_count): map hasher(identity) T::AccountId => u32;
pub NextFeeMultiplier get(fn next_fee_multiplier): Multiplier = Multiplier::saturating_from_integer(1);
StorageVersion build(|_: &GenesisConfig| Releases::V2): Releases;
}
}

Resources