I want to write an application in Rust that deals with input from terminal and I want to prevent it from crashing/being killed by running out of memory. It displays a prompt, processes a command and displays prompt again.
Basically I am looking for read_line_max(n) or read_until(delimiter, max_chars) API where at most n bytes or until delimiter is reached are read.
Possibilities I considered:
for io::stdin().lock().take(n).lines() takes n bytes total at most, I want unlimited chars but limit line size.
for io::stdin().lock().lines().take(n) limits number of lines
for line in io::stdin().lock().lines() {
let line = line?.chars().take(n);
println!("{}", respond_to(line));
}
too late, hogging 50GB of memory, kill imminent
I found out that BufReader used to have .chars() iterator that could be used in this way but it was removed.
With io::stdin().lock().read(buff) there is an issue with bytes vs chars but it may be my best bet. And then try to throw it into a String to check UTF-8 validity but that seems like something I would do in C and very unidiomatic.
Actually while writing this I quickly put together this thing:
let inp = io::stdin();
let mut bufinp = inp.lock();
let mut linebytes = [0_u8; 10];
loop {
match bufinp.read(&mut linebytes) {
Ok(bytes_read) => {
match String::from_utf8(linebytes[..bytes_read].to_vec()) {
Ok(line) => println!("processed line: {}", &line),
Err(err) => eprintln!("utf8 err: {:?}", err),
}
},
Err(err) => {
eprintln!("line read err: {:?}", err);
}
}
}
So... that kind of does what I want but I have some issues with it:
1) I need to trim the '\n' if input is smaller than buffer.
2) It doesn't clear rest of the stdin if input is larger than buffer. I'm guessing I need to put a skip_while() there at the end so that it doesn't spill over to the next read. Is there a nicer way to clear it?
3) It may split graphemes while I could in in fact handle those additional 3 bytes. I don't really care about reading up until specific hard limit. I just want to prevent the input/memory usage from being "too much".
4) It's just too low-level and complicated and not in line with "make good and safe choices easy to code and unsafe ones less available" which makes me think I'm not doing it right. But at least cat /dev/zero | ./target/debug/test doesn't result in SIGQUIT anymore.
I find it strange that a language that prides itself on safety wouldn't provide a fool-proof way to deal with potentially large input. Am I missing something or thinking too much about it? Every article I found just closes its eyes and fires read_to_end() or read_line() without much thought.
How should I read user input safely and idiomatically?
This question already has answers here:
How do I write a Rust unit test that ensures that a panic has occurred?
(8 answers)
Closed 3 years ago.
I'm looking for a way to assert that a piece of code panics, and that the panic message contains a particular string. I came up with the following which appears to work:
let actual = std::panic::catch_unwind(|| decode(notation.to_string()));
assert!(actual.is_err());
let err = *(actual.unwrap_err().downcast::<String>().unwrap());
assert!(err.contains("Invalid"));
I know that I can use #[should_panic] and that it lets me specify a message to check for, but I only want to partially match the exact error message.
Use #[should_panic(expected = "substring of panic message")]
Example
fn some_panic_function() {
panic!("abc substring of panic message abc");
}
#[test]
#[should_panic(expected = "substring of panic message")]
fn test_some_panic_function() {
some_panic_function();
}
From this https://doc.rust-lang.org/book/ch11-01-writing-tests.html
I am learning Rust by just coding right after the first 4 chapters of The Book. Getting started I am still getting used to how borrowing and sharing work and how we can take advantage of them in code.
This snippet of code is supposed to prompt user for an IP address, and if enter is pressed, then to return the loopback address. It works fine, but I am curious to know how this could be improved in any ways, because I definitely know it can. Thank you!
fn prompt_host() -> String {
let mut input_text = String::new();
println!(" input host IP, press enter for loopback:");
io::stdin()
.read_line(&mut input_text)
.expect(" ERROR: failed to read from stdin");
let len = input_text.len();
input_text.truncate(len - 1);
if input_text == "" {
return String::from("127.0.0.1");
}
return input_text as String;
}
Just some hints:
I think I would return something related to std::net::IpAddr instead of String (if there's a type for your needs, I would use it).
std::net::IpAddr implements FromStr, so you can use input_text.parse() and obtain a Result<IpAddr, Err> (since the conversion from string may fail).
I would use trim to get rid of spaces.
I would use is_empty to test if the string is empty. - Or even cover this case by just using parse.
There are (at least) two places that may fail: read_line and parse, so I would think about returning an Option<IpAddr> or even Result<IpAddr, ErrorType> for an appropriate ErrorType.
I'm working on an online judge for algorithm contests. I want to include support for many programming languages, but i don't know all of them. I have to make test sources, but i don't know all of these languages.
I want the equivalent of this code:
#include <stdio.h>
int main () {
int a, b;
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
scanf("%d%d", &a, &b);
printf("%d", a + b);
return 0;
}
In this programming languages.
I want to read from file input.txt two numbers, each on a line, and write the sum of them to the output file output.txt
Thank you.
EDIT Please don't tell me that Visual Basic .NET is not a functional language. I know it.
Haskell:
main = do
[astr, bstr] <- fmap lines (readFile "input.txt")
writeFile "output.txt" $ show (read astr + read bstr)
Or to sum all lines:
main = writeFile "output.txt" . show . sum . map read . lines =<< readFile "input.txt"
In F#:
System.IO.File.ReadAllLines "input.txt" |> Seq.sumBy int |> string
|> fun s -> System.IO.File.WriteAllText("output.txt", s)
An F# version that assumes that the input file contains just two lines (with numbers):
open System.IO
let [| astr; bstr |] = File.ReadAllLines "input.txt"
File.WriteAllText("output.txt", string (int astr + int bstr))
This is a bit simpler than Jon's version, but it is a more direct solution (and behaves the same as Haskell solution posted by others).
There are a ton of ways of doing this in Scala.
val f = (as : Array[String]) => as(0).toInt + as(1).toInt
io.Source.fromFile("C:/myfile.xtx").getLines().toStream match {
case line1 #:: _ => println(f(line1.split(","))
}
You could also do...
val splitLine = (_ : String).split(",")
val printSum = (as : Array[String]) => println(as(0).toInt + as(1).toInt)
val sums = io.Source.fromFile("C:/f.xtx").getLines() map (splitLine andThen printSum)
sums.head //start printing as Iterator is lazy
But then since side-effects should generally be avoided, you would probably want to make your functions pure
val sumLine = (as : Array[String]) => as(0).toInt + as(1).toInt
val sums = io.Source.fromFile("C:/f.xtx").getLines() map (splitLine andThen sumLine)
println(sums.head)
Some answers here seem confused about what the C code does. The C code is not particularly useful. It takes a file like
42
1776
this is any sort of random junk
because the program never reads this far
and produces a file containing
1818
and that is it. IMO, this is a lousy example for showing the power of functional languages because it does so little--one instance of one operation, basically. Yawn. With about the same amount of work, you could take a file with two columns of numbers and produce a file that had their sum in one column as an output. With a tiny bit more work, you could handle any conceivable error in the input.
But, fair enough, if this is the job at hand, one way to accomplish this in Scala is:
val pw = new java.io.PrintWriter("output.txt")
val num = scala.io.Source.fromFile("input.txt").getLines().map(_.toInt)
pw.print(num.next+num.next)
pw.close // Only use this line if execution continues (e.g. in REPL)
Racket Scheme:
(define (simpleSum)
(let* ((input (map string->number (file->lines "input.txt")))
(a (first input)) (b (second input)))
(write-to-file (number->string (+ a b)) "output.txt")))
I don't think scala has its advantage in such simple scenario, including all its fancy features and its api. It's better to use java library. java.util.Scanner has provided the useful nextInt() which can work in many cases and PrintWriter is the fastest output mechniasm in java.
val in = new Scanner(new FileInputStream("input.txt"))
val out = new PrintWriter("output.txt")
out.println((in.nextInt + in.nextInt))
out.close
in.close
And also, I'm curious about which online judge you're working on :)
Here is the VB.NET implementation:
Dim FileLines() as string = system.io.file.readalllines("input.txt")
system.io.file.WriteAllText("output.txt", ctype(FileLines(0), integer) + ctype(FileLines(1), integer))
Visual Basic is not a functional language, unless you use some of the LINQ features.
I've created a command line tool that parses JSON from reddit's front page. After being able to successfully list all of the submission titles; I want to be able to prompt and wait for numeric selection to go deeper into the post.
Btw, I'm fairly new to the language and I'm creating this for fun. I don't really know how to even properly ask this question because I've never developed for a compiler.
What about plain ol' C:
int selection;
do
{
fseek(stdin, 0, SEEK_END);
printf("Select and ID: ");
}
while (scanf("%i", &selection) == 0);
Sorry that I have no method for you to check out. However, you may at your discretion read the man page for scanf (and for fseek, now that I added it— sorry for the non-working snippet earlier!). If you want a small exercise, try to find out why it's necessary to have the fseek call.
Though don't forget to #include <stdio.h>.