BurntSushi / BurntSushi/rust-csv
Support deserialization into Positioned<T>, or pulling a Position into a struct
- Dominant language
- Rust
- Stars
- 2k
- Forks
- 257
- PR merge metrics
- No merged PRs in 30d
Description
#### What version of the `csv` crate are you using?
1.1.1
#### Briefly describe the question, bug or feature request.
When writing a program that does validations on deserialized data, I would like to be able to access position information after deserialization.
#### Include a complete program demonstrating a problem.
```rust
struct Positioned {
pub position: csv::Position,
pub value: T,
}
impl Positioned {
pub fn map(self, f: impl (FnOnce(T) -> U)) -> Positioned {
Positioned {
position: self.position,
value: f(self.value),
}
}
}
#[derive(StructOpt)]
struct Options {
/// TSV files of simple rules, with one rule per line
#[structopt(name = "FILES", parse(from_os_str))]
files: Vec,
}
fn main() -> anyhow::Result<()> {
let opts: Options = Options::from_args();
let mut rules = vec![];
for path in &opts.files {
let mut reader = csv::ReaderBuilder::new().delimiter(b'\t').from_path(path)?;
let headers = reader.headers()?.clone();
for record in reader.records() {
let record = record?;
let position = record.position().expect("Lost CSV position").clone();
let value = record.deserialize::(Some(&headers))?;
rules.push(Positioned { value, position });
}
}
// I WOULD LIKE TO DO VALIDATIONS HERE, AND SURFACE POSITIONS ON THE ERRORS
let compiled = rules
.into_iter()
.map(|v| v.map(rule::CompiledRule::from))
.collect::>();
let mut writer = csv::WriterBuilder::default()
.has_headers(true)
.from_writer(std::io::stdout());
for rule in compiled {
writer.serialize(rule.value)?;
}
Ok(())
}
```
#### What is the observed behavior of the code above?
Not relevant in this case.
#### What is the expected or desired behavior of the code above?
In the validation code, I'd like to write something that runs validations and returns a `Vec`, where each `Diagnostic` has a message and a `position` property. (A span-like thing would also work well).
#### Other Notes
I created something similar for `darling` [here](https://github.com/TedDriggs/darling/blob/master/core/src/util/spanned_value.rs). However, in that case I controlled the traits, so I'm not sure how much of that is relevant here. I also saw that dtolnay did something like this for toml, but after reading his example I struggled to understand how I'd apply it to CSV.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the example's Reader::records loop, Record::position, and Record::deserialize calls to understand where position information is available. Review the requested Positioned or equivalent deserialization design and define how validated values retain positions; done means deserialized values can expose their CSV positions for diagnostics.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- data
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100