Getting Variable from other function - rust

I don't know how to get (_s) variable from other function. Maybe there is a way to reformat this script, so it could work or any other way.
fn shapes(data: usize) {
let romb = "hello";
let s_array = [romb];
let mut items_array = -1;
print!("{}", s_array[data]);
if items_array == _s { //<-------this _s variable is not in this function, so it doesn't work
} else {
println!("error");
}
for x in &s_array {
items_array = items_array + 1;
}
print!("{}", items_array);
}
fn main() {
let mut _s = String::new();
let _b1 = std::io::stdin()
.read_line(&mut _s)
.expect("failed to read line");
let mut _s = _s.trim_end();
let _s_int = _s.parse::<usize>().unwrap();
shapes(_s_int);
}

You need to add another parameter to your shapes function to pass _s. So extend the prototype of your function like:
fn shapes(data: usize, _s: String) {
//Use _s here
}
to call it like:
shapes(_s_int, _s);

Related

How to fix this "borrowed value does not live long enough" error?

I'm writing a program that detects duplicate frames in h264 encoded video. I'm using the ac-ffmpeg crate Here's my code:
use std::fs::File;
use ac_ffmpeg::{
codec::{
video::{frame::Planes, VideoDecoder},
CodecParameters, Decoder,
},
format::{
demuxer::{Demuxer, DemuxerWithStreamInfo},
io::IO,
muxer::{Muxer, OutputFormat},
},
Error,
};
fn open_input(path: &str) -> Result<DemuxerWithStreamInfo<File>, Error> {
let input = File::open(path)
.map_err(|err| Error::new(format!("unable to open input file {}: {}", path, err)))?;
let io = IO::from_seekable_read_stream(input);
Demuxer::builder()
.build(io)?
.find_stream_info(None)
.map_err(|(_, err)| err)
}
fn open_output(path: &str, elementary_streams: &[CodecParameters]) -> Result<Muxer<File>, Error> {
let output_format = OutputFormat::guess_from_file_name(path)
.ok_or_else(|| Error::new(format!("unable to guess output format for file: {}", path)))?;
let output = File::create(path)
.map_err(|err| Error::new(format!("unable to create output file {}: {}", path, err)))?;
let io = IO::from_seekable_write_stream(output);
let mut muxer_builder = Muxer::builder();
for codec_parameters in elementary_streams {
muxer_builder.add_stream(codec_parameters)?;
}
muxer_builder.build(io, output_format)
}
fn plane_difference(planes1: &Planes, planes2: &Planes) -> u64 {
6
}
fn remove_duplicate_frames(input: &str, output: &str) -> Result<(), Error> {
let mut demuxer = open_input(input)?;
let (stream_index, (stream, _)) = demuxer
.streams()
.iter()
.map(|stream| (stream, stream.codec_parameters()))
.enumerate()
.find(|(_, (_, params))| params.is_video_codec())
.ok_or_else(|| Error::new("no video stream"))?;
let mut decoder = VideoDecoder::from_stream(stream)?.build()?;
let mut packet_count = 0;
let mut prev_planes: Option<Planes> = None;
let mut diffs = Vec::<(i64, u64)>::new();
while let Some(packet) = demuxer.take()? {
if packet.stream_index() != stream_index {
continue;
}
decoder.push(packet.clone())?;
if let Some(frame) = decoder.take()? {
let planes = frame.planes();
match prev_planes {
Some(prev) => {
let diff = plane_difference(&planes, &prev);
diffs.push((packet.dts().timestamp() / 1000, diff));
}
None => (),
};
prev_planes = Some(planes);
}
if packet_count > 2000 {
break;
}
packet_count += 1;
}
diffs.sort_by(|a, b| b.1.cmp(&a.1));
dbg!(diffs);
Ok(())
}
with dependency ac-ffmpeg = "0.17.4".
The problem is this gives an error that frame does not live long enough:
error[E0597]: `frame` does not live long enough
--> src/main.rs:106:26
|
106 | let planes = frame.planes();
| ^^^^^^^^^^^^^^ borrowed value does not live long enough
107 |
108 | match prev_planes {
| ----------- borrow later used here
...
117 | }
| - `frame` dropped here while still borrowed
My understanding of this error is that frame is borrowed, which via planes ends up in prev_planes. But at the end of every loop the value is dropped so it doesn't exist for the next iteration. Is that correct? And how can I solve that? I tried cloning various things in this code but I'm not able to fix the error.
VideoFrame doesn't allow you to take the planes, it only allows you to borrow them from the frame.
You can see that because a lifetime is attached to the planes:
pub fn planes(&self) -> Planes<'_>
The '_ lifetime says it's identical to the lifetime of the &self reference, meaning it is borrowed from self.
If you want to store the planes, store the frame that contains them instead:
use std::fs::File;
use ac_ffmpeg::{
codec::{
video::{frame::Planes, VideoDecoder, VideoFrame},
CodecParameters, Decoder,
},
format::{
demuxer::{Demuxer, DemuxerWithStreamInfo},
io::IO,
muxer::{Muxer, OutputFormat},
},
Error,
};
fn open_input(path: &str) -> Result<DemuxerWithStreamInfo<File>, Error> {
let input = File::open(path)
.map_err(|err| Error::new(format!("unable to open input file {}: {}", path, err)))?;
let io = IO::from_seekable_read_stream(input);
Demuxer::builder()
.build(io)?
.find_stream_info(None)
.map_err(|(_, err)| err)
}
fn open_output(path: &str, elementary_streams: &[CodecParameters]) -> Result<Muxer<File>, Error> {
let output_format = OutputFormat::guess_from_file_name(path)
.ok_or_else(|| Error::new(format!("unable to guess output format for file: {}", path)))?;
let output = File::create(path)
.map_err(|err| Error::new(format!("unable to create output file {}: {}", path, err)))?;
let io = IO::from_seekable_write_stream(output);
let mut muxer_builder = Muxer::builder();
for codec_parameters in elementary_streams {
muxer_builder.add_stream(codec_parameters)?;
}
muxer_builder.build(io, output_format)
}
fn plane_difference(planes1: &Planes, planes2: &Planes) -> u64 {
6
}
fn remove_duplicate_frames(input: &str, output: &str) -> Result<(), Error> {
let mut demuxer = open_input(input)?;
let (stream_index, (stream, _)) = demuxer
.streams()
.iter()
.map(|stream| (stream, stream.codec_parameters()))
.enumerate()
.find(|(_, (_, params))| params.is_video_codec())
.ok_or_else(|| Error::new("no video stream"))?;
let mut decoder = VideoDecoder::from_stream(stream)?.build()?;
let mut packet_count = 0;
let mut prev_frame: Option<VideoFrame> = None;
let mut diffs = Vec::<(i64, u64)>::new();
while let Some(packet) = demuxer.take()? {
if packet.stream_index() != stream_index {
continue;
}
decoder.push(packet.clone())?;
if let Some(frame) = decoder.take()? {
let planes = frame.planes();
match prev_frame {
Some(prev) => {
let diff = plane_difference(&planes, &prev.planes());
diffs.push((packet.dts().timestamp() / 1000, diff));
}
None => (),
};
prev_frame = Some(frame);
}
if packet_count > 2000 {
break;
}
packet_count += 1;
}
diffs.sort_by(|a, b| b.1.cmp(&a.1));
dbg!(diffs);
Ok(())
}
You need to keep the frame itself from one loop iteration to the next instead of the planes. So have a prev_frame variable instead of prev_planes:
let mut prev_frame = None;
let mut diffs = Vec::<(i64, u64)>::new();
while let Some(packet) = demuxer.take()? {
if packet.stream_index() != stream_index {
continue;
}
decoder.push(packet.clone())?;
if let Some(frame) = decoder.take()? {
let planes = frame.planes();
match prev_frame {
Some(prev) => {
let diff = plane_difference(&planes, &prev.planes());
diffs.push((packet.dts().timestamp() / 1000, diff));
}
None => (),
};
prev_frame = Some(frame);
}
}
It's a bit tricky to reproduce this, so I'll try to answer from the top of my head.
Did you try:
let planes = frame.planes().to_owned();
Mainly you're giving ownership of planes (i.e. the child), while the parent (frame) goes out of scope.
Why to_owned? (if the child is a ref, clone will return a ref, so we use to_owned instead since it converts a ref type to an owned type where it's allowed to transfer ownership.
The solution should be either:
let planes = frame.planes().to_owned(); // line 106
or
prev_planes = Some(planes.clone()); // line 116
If none of these work, try updating your question with their outputs. It'll make it easier to answer.

"Cannot infer type - type annotations needed", but the type is already known

I've been practicing on LC where I hit the following issue.
pub fn largest_rectangle_area(heights: Vec<i32>) -> i32 {
let mut widths = vec![(0usize, heights.len()); heights.len()];
let mut stack = vec![];
for (idx, &x) in heights.iter().enumerate() {
while let Some(&pos) = stack.last() {
if x >= heights[pos] {
break;
}
widths[pos].1 = idx;
stack.pop();
}
stack.push(idx);
}
todo!()
}
error[E0282]: type annotations needed
--> src/lib.rs:11:13
|
11 | widths[pos].1 = idx;
| ^^^^^^^^^^^ cannot infer type
|
= note: type must be known at this point
What's even stranger is that if I do a widths[pos] = (0, idx); first, then the error disappears:
pub fn largest_rectangle_area(heights: Vec<i32>) -> i32 {
let mut widths = vec![(0, heights.len()); heights.len()];
let mut stack = vec![];
for (idx, &x) in heights.iter().enumerate() {
while let Some(&pos) = stack.last() {
if x >= heights[pos] {
break;
}
widths[pos] = (0, idx); // do a full update
stack.pop();
}
stack.push(idx);
}
stack.clear();
for (idx, &x) in heights.iter().enumerate().rev() {
while let Some(&pos) = stack.last() {
if x >= heights[pos] {
break;
}
widths[pos].0 = idx + 1; // now it's fine to use `.0`
stack.pop();
}
stack.push(idx);
}
todo!()
}
Am I missing something, or is this a bug in the compiler ?
Update
# Ă–mer Erden discovered, that it fails to infer the type of pos which should be usize as it's coming from enumerate() indirectly.
It seems pretty strange because it fails to infer the type of pos when doing widths[pos].1 = idx;, but succeeds when doing widths[pos] = (0, idx);
He also managed to create more minimal MCVE:
fn _some_fn() {
let mut widths = vec![(0usize, 0usize); 100];
let mut stack = vec![];
//let mut stack:Vec<usize> = vec![]; //why explicit type definition needed
let a = stack.pop().unwrap();
let idx = 0usize;
widths[a].1 = idx;
stack.push(idx);
}
Bug Report
https://github.com/rust-lang/rust/issues/90252
I dont know why the compiler is unable to elide the type, but you can manually annotate it with some easy changes:
pub fn largest_rectangle_area(heights: Vec<i32>) -> i32 {
let mut widths = vec![(0usize, heights.len()); heights.len()];
let mut stack = vec![];
for (idx, &x) in heights.iter().enumerate() {
while let Some(&pos) = stack.last() {
if x >= heights[pos] {
break;
}
let at_pos: &mut (usize, usize) = &mut widths[pos];
at_pos.1 = idx;
stack.pop();
}
stack.push(idx);
}
todo!()
}
Playground

Error: use of moved value: `path`. How to correct this code?

I get this error while compiling my code: please help me.
use of moved value: `path`
value used here after moverustc(E0382)
main.rs(16, 9): move occurs because `path` has type `std::result::Result`, which does not implement the `Copy` trait
main.rs(18, 32): `path` moved due to this method call
main.rs(19, 29): value used here after move
fn main() -> std::io::Result<()> {
let paths = fs::read_dir("./").unwrap();
let mut text = String::new();
let mut idx = 0;
for path in paths {
// let path_str = path.unwrap().path().display().to_string();
let path_str = if path.unwrap().path().is_dir() {
path.unwrap().path().display().to_string()
}
else {
let mut path = path.unwrap().path().display().to_string();
path.push_str("[file]");
path
};
let path_trimed = path_str.trim_start_matches("./");
idx += 1;
println!("{} -> file/folder: {}", idx + 1, path_trimed);
text.push_str(&path_trimed);
text.push_str("\n");
}
// println!("{}", text);
// writing the string to file
let mut file = fs::File::create("file_list.txt")?;
file.write_all(&text.as_bytes())?;
Ok(())
}
I think the problem is that you're unwrapping path many times, each unwrapping borrows the variable path, so you rust will complain when you try to unwrap a second time.
I suggest you try to unwrap it just once:
use std::fs;
use std::io::Write;
fn main() -> std::io::Result<()> {
let paths = fs::read_dir("./").unwrap();
let mut text = String::new();
let mut idx = 0;
for path in paths {
// let path_str = path.unwrap().path().display().to_string();
let path = path.unwrap().path();
let path_str = if path.is_dir() {
path.display().to_string()
} else {
let mut path = path.display().to_string();
path.push_str("[file]");
path
};
let path_trimed = path_str.trim_start_matches("./");
idx += 1;
println!("{} -> file/folder: {}", idx + 1, path_trimed);
text.push_str(&path_trimed);
text.push_str("\n");
}
// println!("{}", text);
// writing the string to file
let mut file = fs::File::create("file_list.txt")?;
file.write_all(&text.as_bytes())?;
Ok(())
}

How to use a clone in a Rust thread

In this rust program, inside the run function, I am trying to pass the "pair_clone" as a parameter for both threads but I keep getting a mismatched type error? I thought I was passing the pair but it says I'm passing an integer instead.
use std::sync::{Arc, Mutex, Condvar};
fn producer(pair: &(Mutex<bool>, Condvar), num_of_loops: u32) {
let (mutex, cv) = pair;
//prints "producing"
}
}
fn consumer(pair: &(Mutex<bool>, Condvar), num_of_loops: u32) {
let (mutex, cv) = pair;
//prints "consuming"
}
}
pub fn run() {
println!("Main::Begin");
let num_of_loops = 5;
let num_of_threads = 4;
let mut array_of_threads = vec!();
let pair = Arc ::new((Mutex::new(true), Condvar::new()));
for pair in 0..num_of_threads {
let pair_clone = pair.clone();
array_of_threads.push(std::thread::spawn( move || producer(&pair_clone, num_of_loops)));
array_of_threads.push(std::thread::spawn( move || consumer(&pair_clone, num_of_loops)));
}
for i in array_of_threads {
i.join().unwrap();
}
println!("Main::End");
}
You have two main errors
The first: you are using the name of the pair as the loop index. This makes pair be the integer the compiler complains about.
The second: you are using one copy while you need two, one for the producer and the other for the consumer
After Edit
use std::sync::{Arc, Mutex, Condvar};
fn producer(pair: &(Mutex<bool>, Condvar), num_of_loops: u32) {
let (mutex, cv) = pair;
//prints "producing"
}
fn consumer(pair: &(Mutex<bool>, Condvar), num_of_loops: u32) {
let (mutex, cv) = pair;
//prints "consuming"
}
pub fn run() {
println!("Main::Begin");
let num_of_loops = 5;
let num_of_threads = 4;
let mut array_of_threads = vec![];
let pair = Arc ::new((Mutex::new(true), Condvar::new()));
for _ in 0..num_of_threads {
let pair_clone1 = pair.clone();
let pair_clone2 = pair.clone();
array_of_threads.push(std::thread::spawn( move || producer(&pair_clone1, num_of_loops)));
array_of_threads.push(std::thread::spawn( move || consumer(&pair_clone2, num_of_loops)));
}
for i in array_of_threads {
i.join().unwrap();
}
println!("Main::End");
}
Demo
Note that I haven't given any attention to the code quality. just fixed the compile errors.

How should I read the contents of a file respecting endianess?

I can see that in Rust I can read a file to a byte array with:
File::open(&Path::new("fid")).read_to_end();
I can also read just one u32 in either big endian or little endian format with:
File::open(&Path::new("fid")).read_be_u32();
File::open(&Path::new("fid")).read_le_u32();
but as far as I can see i'm going to have to do something like this (simplified):
let path = Path::new("fid");
let mut file = File::open(&path);
let mut v = vec![];
for n in range(1u64, path.stat().unwrap().size/4u64){
v.push(if big {
file.read_be_u32()
} else {
file.read_le_u32()
});
}
But that's ugly as hell and I'm just wondering if there's a nicer way to do this.
Ok so the if in the loop was a big part of what was ugly so I hoisted that as suggested, the new version is as follows:
let path = Path::new("fid");
let mut file = File::open(&path);
let mut v = vec![];
let fun = if big {
||->IoResult<u32>{file.read_be_u32()}
} else {
||->IoResult<u32>{file.read_le_u32()}
};
for n in range(1u64, path.stat().unwrap().size/4u64){
v.push(fun());
}
Learned about range_step and using _ as an index, so now I'm left with:
let path = Path::new("fid");
let mut file = File::open(&path);
let mut v = vec![];
let fun = if big {
||->IoResult<u32>{file.read_be_u32()}
} else {
||->IoResult<u32>{file.read_le_u32()}
};
for _ in range_step(0u64, path.stat().unwrap().size,4u64){
v.push(fun().unwrap());
}
Any more advice? This is already looking much better.
This solution reads the whole file into a buffer, then creates a view of the buffer as words, then maps those words into a vector, converting endianness. collect() avoids all the reallocations of growing a mutable vector. You could also mmap the file rather than reading it into a buffer.
use std::io::File;
use std::num::{Int, Num};
fn from_bytes<'a, T: Num>(buf: &'a [u8]) -> &'a [T] {
unsafe {
std::mem::transmute(std::raw::Slice {
data: buf.as_ptr(),
len: buf.len() / std::mem::size_of::<T>()
})
}
}
fn main() {
let buf = File::open(&Path::new("fid")).read_to_end().unwrap();
let words: &[u32] = from_bytes(buf.as_slice());
let big = true;
let v: Vec<u32> = words.iter().map(if big {
|&n| { Int::from_be(n) }
} else {
|&n| { Int::from_le(n) }
}).collect();
println!("{}", v);
}

Resources