BurntSushi / BurntSushi/rust-csv

Support deserialization into Positioned<T>, or pulling a Position into a struct

Open
#179 1 comment 0 reactions 0 assignees View on GitHub
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.