Component and Subcomponent Parsing/Values
Closed this issue · 3 comments
I've implemented the basic structure for parsing out component
and subcomponent
&str
s into vectors:
#[derive(Debug, PartialEq, Clone)]
pub enum Field<'a> {
Generic(&'a str),
Component(Vec<&'a str>),
Subcomponent(Vec<Vec<&'a str>>),
}
impl<'a> Field<'a> {
/// Convert the given line of text into a field.
pub fn parse(input: &'a str, delims: &Separators) -> Result<Field<'a>, Hl7ParseError> {
match input.find(delims.component) {
Some(_x) => {
match input.find(delims.subcomponent) {
Some(_x) => {
let components = input.split(delims.component).collect::<Vec<&str>>();
Ok(Field::Subcomponent(
components
.iter()
.map(|c| c.split(delims.subcomponent).collect::<Vec<&str>>())
.collect::<Vec<Vec<&str>>>()
))
},
None => Ok(Field::Component(input.split(delims.component).collect())),
}
}
None => Ok(Field::Generic(input))
}
}
...
However, getting data out of this construct is... non-trivial?
pub fn value(&self) -> &'a str {
let component = String::from(Separators::default().component);
let subcomponent = String::from(Separators::default().subcomponent);
match &self {
Field::Generic(g) => g,
Field::Component(c) => &c.join(&component),
Field::Subcomponent(s) => {
&s.into_iter().map(|sc|
&sc.join(&subcomponent)
).collect::<Vec<&str>>()
.join(&component).as_str()
}
}
}
because making an &str out of vectors of them or vectors of vectors of them requires some sort of borrowing function that i'm not quite getting.
@wokket - happen to have any insight to how i can implement that without
error[E0515]: cannot return value referencing temporary value
--> src/fields/mod.rs:64:9
|
64 | / match &self {
65 | | Field::Generic(g) => g,
66 | | Field::Component(c) => &c.join(&component),
| | ------------------ temporary value created here
67 | | _ => ""
... |
73 | | // }
74 | | }
| |_________^ returns a value referencing data owned by the current function
or
error[E0277]: a value of type `Vec<&str>` cannot be built from an iterator over elements of type `&String`
--> src/fields/mod.rs:70:19
|
70 | ).collect::<Vec<&str>>()
| ^^^^^^^ value of type `Vec<&str>` cannot be built from `std::iter::Iterator<Item=&String>`
|
= help: the trait `FromIterator<&String>` is not implemented for `Vec<&str>`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.
error: could not compile `rust-hl7`
biting me in the arse?
The alternative approach would be to keep the field data as a string and perform components()
and subcomponents()
calls as functions against that, i think.
Thoughts?
Hey mate,
Repeats/Components/Subcomponents are on the TODO list, but I haven't given much concrete through to it.
My general thinking was to have variants of Field
where Generic was just a string, and Repeat etc had more logic/behaviour associated with them. The hard bit I had to work through in my head was how best to actually expose that data, as a consumer of the HL7 do I really just want a bag of bags of bags of strings?? Or something more like:
enum Field {
Generic(str),
Repeating(Vec<Repeat>)
Componentised(Vec<Component>)
}
enum Repeat {
Generic(str),
Componentised(Vec<Component>)
}
enum Component {
Generic(str),
Subcomponentised(Vec<SubComponent/str>)
Given I really don't want to get into interpresting field types etc I'm envisaging a set of helper methods in the library (to say convert a str to a DateTime etc) is just exposing the strings enough? What value does a value() method even provide on a repeating field?
Thoughts?
For the time being, i implemented this functionally at the Field
level to emulate how value()
works and to return Vec<&str>
and Vec<Vec<&str>>
as appropriate. Looking at this from a consumer's perspective, i need to be able to rapidly access complex fields by index (see #11) which necessitates having an iterable set of dimensions which i can traverse to reach the desired position in each dimension requested by the FIELDNAME.FX.RX.CX
index notation
Closed via #11