Cannot compile: using try_buffer_unordered with StreamExt map - rust

I'm trying to use StreamExt and TryStreamExt as follows:
use tokio::fs::File;
use tokio::io::{self, AsyncReadExt};
use futures::stream::{self, StreamExt, TryStreamExt};
async fn read_file(name: &str) -> io::Result<[u8; 10]> {
let mut f = File::open(name).await?;
let mut buffer = [0; 10];
// read up to 10 bytes... yes I know this is not safe but...
let n = f.read(&mut buffer[..]).await?;
Ok(buffer)
}
#[tokio::main]
async fn main() -> io::Result<()> {
let files = vec!["foo.txt", "bar.txt"];
let headers = stream::iter(files)
.map(|f| {
tokio::spawn(
read_file(f)
)
})
.try_buffer_unordered(8)
.try_collect()?;
println!("Got results: {:?}", headers);
Ok(())
}
A link to the playground is here:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=3edf39926c3f046f89f2d925f1a93115
The result of the async_fn and the tokio::spawn is a Result<Result<...., MyError>, JoinError>. The try_buffer_unordered does not compile after a map, which I cannot figure out. I get:
Compiling playground v0.0.1 (/playground)
error[E0599]: no method named `try_buffer_unordered` found for struct `futures::stream::Map<futures::stream::Iter<std::vec::IntoIter<&str>>, [closure#src/main.rs:19:14: 23:10]>` in the current scope
--> src/main.rs:24:10
|
24 | .try_buffer_unordered(8)
| ^^^^^^^^^^^^^^^^^^^^ method not found in `futures::stream::Map<futures::stream::Iter<std::vec::IntoIter<&str>>, [closure#src/main.rs:19:14: 23:10]>`
|
::: /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.13/src/stream/stream/map.rs:12:1
|
12 | / pin_project! {
13 | | /// Stream for the [`map`](super::StreamExt::map) method.
14 | | #[must_use = "streams do nothing unless polled"]
15 | | pub struct Map<St, F> {
... |
19 | | }
20 | | }
| | -
| | |
| |_doesn't satisfy `_: TryStreamExt`
| doesn't satisfy `_: TryStream`
|
= note: the method `try_buffer_unordered` exists but the following trait bounds were not satisfied:
`futures::stream::Map<futures::stream::Iter<std::vec::IntoIter<&str>>, [closure#src/main.rs:19:14: 23:10]>: TryStream`
which is required by `futures::stream::Map<futures::stream::Iter<std::vec::IntoIter<&str>>, [closure#src/main.rs:19:14: 23:10]>: TryStreamExt`
`&futures::stream::Map<futures::stream::Iter<std::vec::IntoIter<&str>>, [closure#src/main.rs:19:14: 23:10]>: TryStream`
which is required by `&futures::stream::Map<futures::stream::Iter<std::vec::IntoIter<&str>>, [closure#src/main.rs:19:14: 23:10]>: TryStreamExt`
`&mut futures::stream::Map<futures::stream::Iter<std::vec::IntoIter<&str>>, [closure#src/main.rs:19:14: 23:10]>: TryStream`
which is required by `&mut futures::stream::Map<futures::stream::Iter<std::vec::IntoIter<&str>>, [closure#src/main.rs:19:14: 23:10]>: TryStreamExt`
I could use buffer_unordered() but then I'm left with a stream with a double nested Result
and I was hoping to use try_buffer_unordered and try_collect().... any thoughts?
(Yes I know the read code has problems, it's just to illustrate the compile problem with StreamExt
(The alternative is something like a series of collects to try to get rid of the Results, which is ugly and uses up extra collections)

FWIW, what I was told from Tokio discord is that one cannot use try_buffer_unordered with a regular Future returned from a map. The try_* methods are intended for when the creation of the Future might not succeed, in other words something like a Result<Future, _>.

Related

Wio Terminal how to use `writeln` method in UART

I use wio_terminal crate and implement UART communication.Previously following code could build but now it couldn't.
Now I use current version 0.6.1, previously I used version 0.3
#![no_std]
#![no_main]
use panic_halt as _;
use wio_terminal as wio;
use core::fmt::Write;
use wio::hal::clock::GenericClockController;
use wio::pac::Peripherals;
use wio::prelude::*;
use wio::{entry, Pins, Sets};
#[entry]
fn main() -> ! {
let mut peripherals = Peripherals::take().unwrap();
// Init clock
let mut clocks = GenericClockController::with_external_32kosc(
peripherals.GCLK,
&mut peripherals.MCLK,
&mut peripherals.OSC32KCTRL,
&mut peripherals.OSCCTRL,
&mut peripherals.NVMCTRL,
);
// Init UART driver
let mut sets: Sets = Pins::new(peripherals.PORT).split();
let mut serial = sets.uart.init(
&mut clocks,
115200.hz(),
peripherals.SERCOM2,
&mut peripherals.MCLK,
);
// Transfer UART
writeln!(&mut serial, "this is {} example!", "UART").unwrap();
}
Partly editted, so the line of error is different
This is the error message.
error[E0599]: the method `write_fmt` exists for mutable reference `&mut wio_terminal::atsamd_hal::sercom::uart::Uart<wio_terminal::atsamd_hal::sercom::uart::Config<wio_terminal::atsamd_hal::sercom::uart::Pads<SERCOM2, IoSet2, wio_terminal::atsamd_hal::gpio::Pin<PB27, wio_terminal::atsamd_hal::gpio::Alternate<wio_terminal::atsamd_hal::gpio::C>>, wio_terminal::atsamd_hal::gpio::Pin<PB26, wio_terminal::atsamd_hal::gpio::Alternate<wio_terminal::atsamd_hal::gpio::C>>>>, wio_terminal::atsamd_hal::sercom::uart::Duplex>`, but its trait bounds were not satisfied
--> examples\6-3-uart.rs:54:5
|
54 | writeln!(&mut serial, "this is {} example!", "UART").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
::: C:\Users\\.cargo\registry\src\github.com-1ecc6299db9ec823\atsamd-hal-0.15.1\src\sercom\uart.rs:602:1
|
602 | / pub struct Uart<C, D>
603 | | where
604 | | C: ValidConfig,
605 | | D: Capability,
... |
608 | | capability: PhantomData<D>,
609 | | }
| |_- doesn't satisfy `_: core::fmt::Write`
|
= note: the following trait bounds were not satisfied:
`wio_terminal::atsamd_hal::sercom::uart::Uart<wio_terminal::atsamd_hal::sercom::uart::Config<wio_terminal::atsamd_hal::sercom::uart::Pads<SERCOM2, IoSet2, wio_terminal::atsamd_hal::gpio::Pin<PB27, wio_terminal::atsamd_hal::gpio::Alternate<wio_terminal::atsamd_hal::gpio::C>>, wio_terminal::atsamd_hal::gpio::Pin<PB26, wio_terminal::atsamd_hal::gpio::Alternate<wio_terminal::atsamd_hal::gpio::C>>>>, wio_terminal::atsamd_hal::sercom::uart::Duplex>: core::fmt::Write`
which is required by `&mut wio_terminal::atsamd_hal::sercom::uart::Uart<wio_terminal::atsamd_hal::sercom::uart::Config<wio_terminal::atsamd_hal::sercom::uart::Pads<SERCOM2, IoSet2, wio_terminal::atsamd_hal::gpio::Pin<PB27, wio_terminal::atsamd_hal::gpio::Alternate<wio_terminal::atsamd_hal::gpio::C>>, wio_terminal::atsamd_hal::gpio::Pin<PB26, wio_terminal::atsamd_hal::gpio::Alternate<wio_terminal::atsamd_hal::gpio::C>>>>, wio_terminal::atsamd_hal::sercom::uart::Duplex>: core::fmt::Write`
= note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: unused import: `core::fmt::Write`
--> uart.rs:20:5
|
20 | use core::fmt::Write;
| ^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
For more information about this error, try `rustc --explain E0599`.
warning: `sample-template` (example "6-3-uart") generated 1 warning
error: could not compile `sample-template` due to previous error; 1 warning emitted
I couldn't understand and resolve this error. Please let me know how to resolve it.

syn::ItemFn.to_token_stream hidden/guarded?

I thought I'd try to write a basic function decorator that logs the input and output of functions as they are called. I have many functions that have roughly the same signature, and I'd like to log the io of common part. That is, think of adding a decorator like this
#[my_decorator]
foo(<unknown initial args>, final_arg: T) -> R {BODY}
would effectively turn foo into
foo(<unknown initial args>, final_arg: T) -> R {
let result = {BODY};
debug!("final_arg is {:?}" final_arg)
debug!("return value is {:?}" result)
result
}
I spent today searching around for best approaches to this and it appears that the best way would be to define a #[proc_macro_attribute]
I am at the following sanity-checking stub (which the documentation here would suggest is valid)
use proc_macro::TokenStream;
use syn;
use syn::ItemFn;
#[proc_macro_attribute]
pub fn log_io(_attr: TokenStream, item: TokenStream) -> TokenStream {
let item_fn: ItemFn = syn::parse_macro_input!(item);
item_fn.to_token_stream()
}
Which IIUC should be the No-Op decorator. But the compiler gives
error[E0599]: no method named `to_token_stream` found for struct `ItemFn` in the current scope
--> src/lib.rs:8:13
|
8 | item_fn.to_token_stream()
| ^^^^^^^^^^^^^^^ method not found in `ItemFn`
|
::: /Users/arthurtilley/.cargo/registry/src/github.com-1ecc6299db9ec823/quote-1.0.21/src/to_tokens.rs:59:8
|
59 | fn to_token_stream(&self) -> TokenStream {
| --------------- the method is available for `ItemFn` here
|
= help: items from traits can only be used if the trait is in scope
help: one of the expressions' fields has a method of the same name
|
8 | item_fn.sig.to_token_stream()
| ++++
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
|
1 | use syn::__private::ToTokens;
|
Adding the suspicious looking use syn::__private::ToTokens; the compiler then gives
error[E0308]: mismatched types
--> src/lib.rs:9:5
|
7 | pub fn log_io(_attr: TokenStream, item: TokenStream) -> TokenStream {
| ----------- expected `proc_macro::TokenStream` because of return type
8 | let item_fn: ItemFn = syn::parse_macro_input!(item);
9 | item_fn.to_token_stream()
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `proc_macro::TokenStream`, found struct `TokenStream2`
None of this is mentioned in the documentation https://docs.rs/syn/latest/syn/struct.ItemFn.html so I'm a little stumped.
EDIT: #Shelvacu I'm using
syn = {version ="*" ("1.0.99"), features = ["full", "printing", "extra-traits"]}
proc-macro2 = "*" ("1.0.43")
If you click on TokenStream in fn to_token_stream you'll notice that it returns proc_macro2::TokenStream which is different from proc_macro::TokenStream that your function is defined to return. You can read more about this in the proc-macro2 docs. The way to convert proc_macro2::TokenStream to proc_macro::TokenStream as recommended in the docs is:
proc_macro::TokenStream::from(output)
In your case, this should work:
#[proc_macro_attribute]
pub fn log_io(_attr: TokenStream, item: TokenStream) -> TokenStream {
let item_fn: ItemFn = syn::parse_macro_input!(item);
proc_macro::TokenStream::from(item_fn.to_token_stream());
}
Also, you should import ToTokens trait from quote::ToTokens (from the quote crate) as the syn re-export is marked private.

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.

How to use zbus to list block devices?

I want to list all the available block devices in the system using a dbus implementation called zbus.
The UDisks2 documentation mentions a method call on org.freedesktop.UDisks2.Manager interface called GetBlockDevices which accepts IN a{sv} options, OUT ao block_objects for method parameters.
Using zbus, I write:
use std::error::Error;
use std::result::Result;
use zbus::{Connection, Proxy};
fn main() -> Result<(), Box<dyn Error>> {
let connection = Connection::new_system()?;
let p = Proxy::new(
&connection,
"org.freedesktop.UDisks2",
"/org/freedesktop/UDisks2/Manager",
"org.freedesktop.UDisks2.Manager",
)?;
let resp: Vec<zvariant::ObjectPath> = p.call("GetBlockDevices", &std::collections::HashMap::<String, zvariant::Value>::new())?;
dbg!(resp);
Ok(())
}
As far as I understand, zvariant Values represent a DBus Variant. However I get the following error:
error: implementation of `serde::de::Deserialize` is not general enough
--> src/main.rs:13:45
|
13 | let resp: Vec<zvariant::ObjectPath> = p.call("GetBlockDevices", &std::collections::HashMap::<String, zvariant::Value>::new())?;
| ^^^^ implementation of `serde::de::Deserialize` is not general enough
|
::: /home/adnan338/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.115/src/de/mod.rs:531:1
|
531 | / pub trait Deserialize<'de>: Sized {
532 | | /// Deserialize this value from the given Serde deserializer.
533 | | ///
534 | | /// See the [Implementing `Deserialize`][impl-deserialize] section of the
... |
569 | | }
570 | | }
| |_- trait `serde::de::Deserialize` defined here
|
= note: `std::vec::Vec<zvariant::object_path::ObjectPath<'_>>` must implement `serde::de::Deserialize<'0>`, for any lifetime `'0`...
= note: ...but `std::vec::Vec<zvariant::object_path::ObjectPath<'_>>` actually implements `serde::de::Deserialize<'1>`, for some specific lifetime `'1`
What's causing this and how can I avoid this error?
Firstly, thanks for trying out our crate. The issue is that zbus::Proxy::call expects the return value to be an owned one, while you're deserializing to an unowned type. Both of the the following work:
// OwnedObjectPath require zvariant >= 2.2.0
let resp: Vec<zvariant::OwnedObjectPath> = p.call(
"GetBlockDevices",
&std::collections::HashMap::<String, zvariant::Value>::new(),
)?;
let resp = p.call_method(
"GetBlockDevices",
&std::collections::HashMap::<String, zvariant::Value>::new(),
)?;
let resp: Vec<zvariant::ObjectPath> = resp.body()?;

How do I pass a struct with type parameters as a function argument?

How do I pass an instance of EcsClient with the signature impl<P, D> EcsClient<P, D> where P: ProvideAwsCredentials, D: DispatchSignedRequest to a function as a reference in Rust? My attempt is thus:
extern crate rusoto;
use std::default::Default;
use rusoto::{ DefaultCredentialsProvider, Region };
use rusoto::ecs::{ EcsClient };
use rusoto::default_tls_client;
fn get_task_definition_revisions(client: &EcsClient) {
// Use EscClient instance here
}
fn main() {
let provider = DefaultCredentialsProvider::new().unwrap();
let client = EcsClient::new(default_tls_client().unwrap(), provider, Region::EuWest1).unwrap();
get_task_definition_revisions(&client);
}
This gives me the following error:
error[E0243]: wrong number of type arguments: expected 2, found 0
--> src/main.rs:9:43
|
9 | fn get_task_definition_revisions(client: &EcsClient) {
| ^^^^^^^^^ expected 2 type arguments
My attempted fix for this is such:
extern crate rusoto;
use std::default::Default;
use rusoto::{
DefaultCredentialsProvider,
Region,
ProvideAwsCredentials,
DispatchSignedRequest
};
use rusoto::ecs::{ EcsClient, ListTaskDefinitionsRequest };
use rusoto::default_tls_client;
fn get_task_definition_revisions(client: &EcsClient<ProvideAwsCredentials, DispatchSignedRequest>) {
// Use EcsClient instance here
}
fn main() {
let provider = DefaultCredentialsProvider::new().unwrap();
let client = EcsClient::new(default_tls_client().unwrap(), provider, Region::EuWest1);
get_task_definition_revisions(&client);
}
Which gives me:
error[E0277]: the trait bound `rusoto::ProvideAwsCredentials + 'static: std::marker::Sized` is not satisfied
--> src/main.rs:14:1
|
14 | fn get_task_definition_revisions(client: &EcsClient<P, D>) {
| _^ starting here...
15 | | let defs = client.list_task_definitions(&ListTaskDefinitionsRequest {
16 | | family_prefix: None,
17 | | max_results: None,
18 | | next_token: None,
19 | | sort: None,
20 | | status: Some("ACTIVE".to_string()),
21 | | });
22 | | }
| |_^ ...ending here: the trait `std::marker::Sized` is not implemented for `rusoto::ProvideAwsCredentials + 'static`
|
= note: `rusoto::ProvideAwsCredentials + 'static` does not have a constant size known at compile-time
= note: required by `rusoto::ecs::EcsClient`
error[E0277]: the trait bound `rusoto::DispatchSignedRequest + 'static: std::marker::Sized` is not satisfied
--> src/main.rs:14:1
|
14 | fn get_task_definition_revisions(client: &EcsClient<P, D>) {
| _^ starting here...
15 | | let defs = client.list_task_definitions(&ListTaskDefinitionsRequest {
16 | | family_prefix: None,
17 | | max_results: None,
18 | | next_token: None,
19 | | sort: None,
20 | | status: Some("ACTIVE".to_string()),
21 | | });
22 | | }
| |_^ ...ending here: the trait `std::marker::Sized` is not implemented for `rusoto::DispatchSignedRequest + 'static`
|
= note: `rusoto::DispatchSignedRequest + 'static` does not have a constant size known at compile-time
= note: required by `rusoto::ecs::EcsClient`
This feels like a rabbit hole I shouldn't be going down.
I've also tried changing the function signature to accept generics, however the EcsClient is a struct not a trait. Googling doesn't provide much help because I don't know the correct terms to search for.
This question seems to imply that I should be able to declare a function like fn my_func(client: &EcsClient) { ... } and it will work, so why doesn't the above example?
The problem is that EcsClient is not a type, it's a blueprint to build a type (also known as "type constructor").
As a result, you cannot use just EcsClient when a type is required, be it in functions or for struct members; instead, each time, you must use it to build a type by specifying its generic parameters.
Thus, the first step is to introduce the type parameters:
fn get_task_definition_revisions<P, D>(client: &EcsClient<P, D>) {}
Now, however, the compiler will complain that the P and D are insufficiently constrained: EcsClient only accept a very specific kind of P and D!
The next step, thus, is to look-up the bounds that are specified for P and D in the definition of EcsClient and apply them. It's just copy/paste at this point:
fn get_task_definition_revisions<P, D>(client: &EcsClient<P, D>)
where P: ProvideAwsCredentials,
D: DispatchSignedRequest
{
}
And then you're golden.
If you need more capabilities of P or D for this specific function, feel free to constrain them adequately by adding more bounds using +:
fn get_task_definition_revisions<P, D>(client: &EcsClient<P, D>)
where P: ProvideAwsCredentials + 'static,
D: DispatchSignedRequest
{
}
If you wonder why Rust chose to have you repeat the bounds for P and D when it could perfectly infer them, it's because it cares about you. More specifically, it cares about you 6 months from now, and the next maintainer to come. So, taking the stance that you write once and read many, it forces you to copy the bounds so that later you don't have to wonder what they are, and drill down recursively in each type/function used to painfully aggregate all the pieces. In Rust, the next time you read the function, you'll have all the information right there.
I was understanding the syntax incorrectly. It seems that P and D are placeholders, like T would be. I need to specify what those types are, so the signature now looks like this:
fn get_task_definition_revisions<P: ProvideAwsCredentials, D: DispatchSignedRequest>(client: &EcsClient<P, D>) {
...
}
I don't use P or D in the function body, but they must be declared.
The full example now looks like:
extern crate rusoto;
use std::default::Default;
use rusoto::{
DefaultCredentialsProvider,
Region,
ProvideAwsCredentials,
DispatchSignedRequest
};
use rusoto::ecs::{ StringList, EcsClient, ListTaskDefinitionsRequest };
use rusoto::default_tls_client;
fn get_task_definition_revisions<P: ProvideAwsCredentials, D: DispatchSignedRequest>(client: &EcsClient<P, D>) {
let res = client.list_task_definitions(&ListTaskDefinitionsRequest {
family_prefix: None,
max_results: None,
next_token: None,
sort: None,
status: Some("ACTIVE".to_string()),
});
// ...
}
fn main() {
let provider = DefaultCredentialsProvider::new().unwrap();
let client = EcsClient::new(default_tls_client().unwrap(), provider, Region::EuWest1);
get_task_definition_revisions(&client);
}
I'm still not entirely sure why this works or is required but I hope this answer helps someone else.

Resources