What should a parameter which can be a string or a stream look like?
What do you want to do with this parameter? I.e. what interface do you need? Have you considered Either
? Or converting the string to a stream beforehand?
I want to be able to read it character by character.
You can convert a string to a Stream<Item = char>
via futures::stream::iter(string.chars())
. Example.
This seems fine, but it is not a part of the standard library.
What Stream
trait are you using, if you are not using the futures
library? There is no Stream
trait in the standard library, only the unstable AsyncIterator
.
There is std::io::Read, but I do not know what I should ideally do.
You can use String::as_bytes
to access the underlying byte slice &[u8]
, which implements Read
. I wouldn't use Read
to read a buffer "character by character" though, as this is non-trivial for UTF-8 scalar values, which is what char
s in Rust are. I'd use Iterator<Item = char>
instead.
Can file streams be passed down as std::iter::Iterator before being read?
yes.
in rust, the API to read files is provided by the std::io::Read
trait, which has a bytes()
method that gives you an iterator. the iterator yields items of type Result<u8, std::io::Error>
.
there's an example in the documentation of Read::bytes()
you can take a look:
The problem with this is that it is different from std::fmt::Bytes that is what String::bytes
returns.
of course it's different, every iterator is a distinct type. what's common is they all implement the Iterator
trait,
if you want static dispatch, use a generic type with Iterator
as bound. if you want dynamic dispatch, use a trait object.
however, since reading from a file is fallible due to the nature of doing IO, the associated Item
type is different. it's up to you to decide how to handle the IO error while reading from the file.
for example, this example uses Result::unwrap
so it would panic on error while reading the file:
// this function takes an iterator of bytes as argument
fn foo<I>(bytes: I) where I: Iterator<Item = u8> {
for b in bytes {
// do something with `b`
}
}
fn main() {
let s = String::from("hello world!");
foo(s.bytes());
use std::io::Read;
let f = std::fs::File::open("/tmp/my_file.txt").expect("open file");
foo(f.bytes().map(Result::unwrap));
}