I am trying to iterate through a BufReader with Lines to capture certain data to a struct. It skips through the file until a certain String is found, then loops through the data to capture three String fields (nomen, id, data_type) to a struct if a line starts with a certain String. Then, the struct is pushed to a vec. It finally breaks out of the loop when either certain conditions are met.
I cannot figure out why I am having two weird issues:
-
The loop captures the first iteration perfectly. After the second iteration, it only captures a portion of the "nomen" field. It drops everything after String.starts_with(). The other fields capture correctly.
-
After all the fields are captured to the struct, it test the break out condition by a read line.next(). It then matches against Option. If it is None, it breaks out of the loop. If the Some matches to an Ok(String) and the String.starts_with(), it supposed to break out without capturing or pushing to the vec. But, the condition is met and it still reads the incorrect data and pushes.
Here's the code:
pub fn extract_triggers(self) -> Vec<GameObject> {
let path = PathBuf::from(&self.filename);
let file = File::open(path).unwrap();
let mut lines = BufReader::new(file).lines();
let mut trigger_vec = Vec::<GameObject>::new();
//Move the CMF file pointer until TRIGGERS array & loop through
lines.find(|trigger| trigger.as_ref().unwrap() == "\t\"triggers\": [");
loop {
// capture element ID
let mut nomen = {
match lines.find(|has_name| {
has_name.as_ref().unwrap().starts_with("\t\t\t\t\"name\": ")
}) {
Some(nomen) => match nomen {
Ok(nomen) => {
println!("Found {}", nomen);
nomen
}
Err(e) => e.to_string(),
},
None => "missing data".to_string(),
}
};
let mut id = {
match lines
.find(|has_id| has_id.as_ref().unwrap().starts_with("\t\t\t\"id\": "))
{
Some(id) => match id {
Ok(id) => {
println!("Found {}", id);
id
}
Err(e) => e.to_string(),
},
None => "missing data".to_string(),
}
};
let mut data_type = {
match lines.find(|has_type| {
has_type
.as_ref()
.unwrap()
.starts_with("\t\t\t\"dataType\": ")
}) {
Some(data_type) => match data_type {
Ok(data_type) => data_type,
Err(e) => e.to_string(),
},
None => "missing data".to_string(),
}
};
trigger_vec.push(GameObject {
id,
nomen,
data_type,
});
match lines.next() {
None => break,
Some(line_data) => match line_data {
Err(err) => continue,
Ok(line) => {
if line.starts_with("\t]") {
break;
} else if line.starts_with("\t\t}") {
continue;
}
}
},
}
}
println!("Trigger = {:#?}", trigger_vec);
trigger_vec
}
And, here's a sample of the results:
Trigger = [
GameObject {
id: "\t\t\t\"id\": 6,",
nomen: "\t\t\t\t\"name\": \"L Eng Sel Mach CHA\"",
data_type: "\t\t\t\"dataType\": \"BOOL_TRGR_DATA_TYPE_UINT32\",",
},
GameObject {
id: "\t\t\t\"id\": 7,",
nomen: "\t\t\t\t\"name\": \"\"",
data_type: "\t\t\t\"dataType\": \"BOOL_TRGR_DATA_TYPE_UINT32\",",
},
GameObject {
id: "\t\t\t\"id\": 8,",
nomen: "\t\t\t\t\"name\": \"\"",
data_type: "\t\t\t\"dataType\": \"BOOL_TRGR_DATA_TYPE_UINT32\",",
},
...
GameObject {
id: "\t\t\t\"id\": 0,",
nomen: "\t\t\t\t\"name\": \"\"",
data_type: "missing data",
},
]