Skip to content

Instantly share code, notes, and snippets.

@Restioson

Restioson/csv.rs Secret

Last active October 9, 2017 15:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Restioson/a362b26f64c28e078f3a3b16297c701d to your computer and use it in GitHub Desktop.
Save Restioson/a362b26f64c28e078f3a3b16297c701d to your computer and use it in GitHub Desktop.
/* config.rs */
pub const SERIAL_DATA_LABELS: &[&'static str] = &[
"latitude",
"longitude",
"altitude",
"course",
"heading",
"speed",
"year",
"month",
"day",
"hour",
"minute",
"second",
"temperature",
"humidity",
"pitch",
"roll",
"object_distance_front",
"object_distance_back",
];
pub const SERIAL_SEPARATOR: char = ' ';
pub const SERIAL_TERMINATOR: char = '\n';
/* protocol.rs */
#[derive(Debug, Deserialize, PartialEq)]
pub struct Data {
latitude: f64,
longitude: f64,
altitude: f64,
course: f32,
heading: f32,
speed: f32,
year: u16,
month: u8,
day: u8,
hour: u8,
minute: u8,
second: u8,
temperature: f32,
humidity: f32,
pitch: f32,
roll: f32,
object_distance_front: u16,
object_distance_back: f32,
}
pub struct SerialParser {
data_records: csv::DeserializeRecordsIntoIter<Cursor<Vec<u8>>, Data>,
}
impl SerialParser {
pub fn new() -> Self {
let mut csv_reader = csv::ReaderBuilder::new()
.delimiter(config::SERIAL_SEPARATOR as u8)
.terminator(csv::Terminator::Any(config::SERIAL_TERMINATOR as u8))
.from_reader(Cursor::new(Vec::new()));
// Add the headers
let mut headers: String = config::SERIAL_DATA_LABELS
.iter()
.map(|it| it.to_string())
.collect::<Vec<_>>()
.join(config::SERIAL_SEPARATOR.encode_utf8(&mut [0u8; 2]));
headers.push(config::SERIAL_TERMINATOR);
// Write headers to csv reader
let mut position = csv_reader.position().clone();
position.set_byte(0);
{
let cursor = csv_reader.get_mut();
cursor.set_position(position.byte());
cursor.write_all(headers.as_bytes()).unwrap();
// TODO
eprintln!("Cursor contents: {:?}", cursor.get_ref());
}
csv_reader
.seek_raw(std::io::SeekFrom::Start(position.byte()), position.clone())
.unwrap();
// TODO cleanup all these get_mut's
csv_reader.get_mut().set_position(position.byte());
csv_reader.get_mut().write_all(headers.as_bytes()).expect(
"Error writing into Vec, meaning it's full (shouldn't be) -- this is a bug!",
);
csv_reader.get_mut().set_position(0);
// Read headers
csv_reader.records().next();
// Clear cursor of headers
csv_reader.get_mut().get_mut().clear();
SerialParser { data_records: csv_reader.into_deserialize() }
}
pub fn parse<'a>(&mut self, packet: &'a str) -> Result<Option<Message>, ParseError<'a>> {
let tag = match packet.split(config::SERIAL_SEPARATOR).next() {
Some(tag) => tag,
None => return Err(ParseError::NoTag),
};
trace!("{}", tag); // TODO
trace!("\"{}\"", packet); // TODO
if packet.len() < tag.len() + 1 {
return Err(ParseError::PacketTooShort);
}
// Remove the tag and delimiter, and trim leading/trailing spaces
let data = packet[tag.len() + 1..].trim();
// TODO remove
trace!("\"{}\"", data);
trace!("{}", data.len());
// TODO
eprintln!("\"{}\"", data);
eprintln!("{}", data.len());
// Thanks to daschl
// https://github.com/BurntSushi/rust-csv/issues/91
let mut position = self.data_records.reader().position().clone();
position.set_byte(0);
{
let cursor = self.data_records.reader_mut().get_mut();
cursor.set_position(position.byte());
cursor.write_all(data.as_bytes()).unwrap();
// TODO
eprintln!("Cursor contents: {:?}", cursor.get_ref());
}
{
let reader = self.data_records.reader_mut();
reader
.seek_raw(std::io::SeekFrom::Start(position.byte()), position.clone())
.unwrap();
reader.get_mut().set_position(position.byte());
}
let value = match tag {
"DATA" => {
let value = match self.data_records.next() {
Some(Ok(data)) => Ok(Some(Message::Data(data))),
Some(Err(error)) => Err(ParseError::CsvError(error)),
None => Ok(None),
};
// TODO needed
// Clear cursor to prevent overflow
self.data_records.reader_mut().get_mut().get_mut().clear();
value
}
"CMD" => {
match data {
// TODO capitalised?
"SHUTDOWN" => Ok(Some(Message::Command(Command::Shutdown))),
command => Err(ParseError::InvalidCommand(command)),
}
}
_ => Err(ParseError::InvalidTag(tag)), // Unknown tag
};
value
}
}
// (test to make it runnable)
#[cfg(test)]
mod test {
use super::*;
/* Error in this func */
#[test]
fn csv_dynamic() {
let data = "-100.00 100.00 100.00 77.39 195.9 1.111 2017 9 29 13 14 48 0 0 2.1 -1.3 82 67.3\n";
/* Set up reader */
let mut csv_reader = csv::ReaderBuilder::new()
.delimiter(config::SERIAL_SEPARATOR as u8)
.terminator(csv::Terminator::Any(config::SERIAL_TERMINATOR as u8))
.from_reader(Cursor::new(Vec::new()));
// Add the headers
let mut headers: String = config::SERIAL_DATA_LABELS
.iter()
.map(|it| it.to_string())
.collect::<Vec<_>>()
.join(config::SERIAL_SEPARATOR.encode_utf8(&mut [0u8; 2]));
eprintln!("Headers: {}", headers);
headers.push(config::SERIAL_TERMINATOR);
// Write headers to csv reader
let mut position = csv_reader.position().clone();
position.set_byte(0);
{
let cursor = csv_reader.get_mut();
cursor.set_position(position.byte());
cursor.write_all(headers.as_bytes()).unwrap();
// TODO
eprintln!("Cursor contents: {:?}", cursor.get_ref());
}
csv_reader
.seek_raw(std::io::SeekFrom::Start(position.byte()), position.clone())
.unwrap();
// TODO cleanup all these get_mut's
csv_reader.get_mut().set_position(position.byte());
csv_reader.get_mut().write_all(headers.as_bytes()).expect(
"Error writing into Vec, meaning it's full (shouldn't be) -- this is a bug!",
);
csv_reader.get_mut().set_position(0);
// Read headers
csv_reader.records().next();
// Clear cursor of headers
csv_reader.get_mut().get_mut().clear();
/* Feed data */
let mut position = csv_reader.position().clone();
position.set_byte(0);
{
let cursor = csv_reader.get_mut();
cursor.set_position(position.byte());
cursor.write_all(data.as_bytes()).unwrap();
// TODO
eprintln!("Cursor contents: {:?}", cursor.get_ref());
}
{
let reader = &mut csv_reader;
reader
.seek_raw(std::io::SeekFrom::Start(position.byte()), position.clone())
.unwrap();
reader.get_mut().set_position(position.byte());
}
/* Parse */
println!("{:?}", csv_reader.deserialize::<Data>().next().unwrap().unwrap());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment