I'm driving myself bonkers with this one, because judging by the documentation it should be painless: how do I cast a string into an &[u8]
so I can send it over the wire via TCP or UDP? The bytes!()
macro only appears to work on literals directly.
Here's the skeleton for a TCP app, cribbed entirely from other sources. Right now it works as an echo server. The stumbling block I'm having is figuring out how to print the &[u8] as a string on the terminal, or how to cast strings from io::stdin().read_line()
into &[u8] to send over the wire, chat-style.
This fails to compile on a error: mismatched types: expected `&[u8]` but found `&str` (expected vector but found &str)
:
fn run_tcp_test_server(listen_addr: SocketAddr) {
let mut acceptor = TcpListener::bind(listen_addr).listen().unwrap();
println("[ INFO ] listener is ready.");
loop {
let stream = Cell::new(acceptor.accept().unwrap());
do spawn {
println("[ INFO ] got a request.");
let mut stream = stream.take();
let mut my_read_buff = ~[0, ..1024];
match stream.read(my_read_buff) {
Some(n) => {
stream.write(my_read_buff.slice_to(n));
},
_ => ()
}
let out_msg = "Hello World\r\n";
stream.write(out_msg);
}
}
}
I also don't think the let mut my_read_buff = ~[0, ..1024]
can possibly be right, that seems like a C-style overflow waiting to happen, which I thought Rust was supposed to fix.
I'm pretty confused by this, my understanding is that &str
is &[u8]
and I'm getting snagged by the type system, but can't get past this. I've tried to implement some of the functions from the std::str::raw
in unsafe blocks but had no luck there, either.
&str
has the same representation as &[u8]
, but it has an additional invariant: the contents is always valid UTF-8, hence it is not the same type, i.e. you have to explicitly "cast" between them (a little similar to u8
and i8
having the same representation but requiring an explicit cast to use them in place). This "cast" is done with .as_bytes()
to go from &str
→ &[u8]
, and std::str::from_utf8
for the other direction (on 0.8, the reverse cast is from_utf8_slice
FWIW). The &str
→ &[u8]
cast is very, very cheap; with optimisations on it is literally zero-cost (the other direction has to check for valid UTF-8, and hence is O(n)), and with them off it is still a function call to a function with a very small number of instructions.
Hence, you need:
stream.write(out_msg.as_bytes());
(If out_msg
is always the same message you can actually use the b
prefix to get a compile-time byte literal:
stream.write(b"Hello World\r\n")
)
I also don't think the let mut my_read_buff = ~[0, ..1024] can possibly be right, that seems like a C-style overflow waiting to happen, which I thought Rust was supposed to fix.
No, vectors and slices have their length stored in them so the .read
call knows how much space it is allowed to fill, and won't/can't write beyond the end of it.
(FWIW, if your buffer is always a fixed length, you can drop the ~
, i.e. let mut my_read_buff = [0, ..1024];
, so my_read_buf
will have type [u8, .. 1024]
, i.e. a fixed length vector of 1024 u8
's. This avoids the heap allocation.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With