I'm facing compiler errors with dynamic traits in a scenario where I either have a std::net::TcpStream
or an native_tls::TlsStream<TcpStream>
. The idea for my algorithm is the following:
- create TCP stream in var "tcp"
- if scheme is https => replace same var with new
TlsStream<TcpStream>
. - Write and receive data on stream.
The important traits I need are std::io::Read
and std::io::Write
. Therefore I thought, I just model my "tcp" var as Box<dyn Read + Write>
. But no matter how I tried, I always got compilation errors. Below you can see a minimal example, that doesn't compile.
use std::net::{IpAddr, Ipv4Addr, TcpStream};
use std::io::{Write as IoWrite, Read as IoRead};
use native_tls::TlsConnector;
fn main() {
let use_https = true;
// IP of "example.com".
let ip_addr = std::net::IpAddr::V4(Ipv4Addr::new(85, 13, 155, 159));
let port = if use_https { 443 } else { 80 };
let tcp_stream = TcpStream::connect((ip_addr, port)).unwrap();
let tcp_stream = maybe_connect_to_tls(tcp_stream, use_https);
}
fn maybe_connect_to_tls(tcp: TcpStream, use_https: bool) -> Box<dyn IoRead + IoWrite> {
if use_https {
let tls = TlsConnector::new().unwrap();
let tcp = tls.connect("example.com", tcp).unwrap();
Box::new(tcp)
} else {
Box::new(tcp)
}
}
This is the error I get when I try to compile it:
error[E0225]: only auto traits can be used as additional traits in a trait object
--> src/main.rs:14:78
|
14 | fn maybe_connect_to_tls(tcp: TcpStream, use_https: bool) -> Box<dyn IoRead + IoWrite> {
| ------ ^^^^^^^ additional non-auto trait
| |
| first non-auto trait
|
= help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: std::io::Read + std::io::Write {}`
= note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
I also tried maybe_connect_to_tls<T>(tcp: TcpStream, use_https: bool) -> Box<T> where T: IoWrite + IoRead + ?Sized
but whatever I try leads to other compilation failures..
Any idea how I can solve this? I want a common stream object and it should be invisible to the application what the specific implementation is.