data_forms: Split field parsing into its own TryFrom impl.

Emmanuel Gil Peyrot created

Change summary

src/data_forms.rs | 138 ++++++++++++++++++++++++++----------------------
1 file changed, 74 insertions(+), 64 deletions(-)

Detailed changes

src/data_forms.rs 🔗

@@ -57,6 +57,78 @@ pub struct Field {
     pub media: Vec<MediaElement>,
 }
 
+impl Field {
+    fn is_list(&self) -> bool {
+        self.type_ == FieldType::ListSingle ||
+        self.type_ == FieldType::ListMulti
+    }
+}
+
+impl TryFrom<Element> for Field {
+    type Err = Error;
+
+    fn try_from(elem: Element) -> Result<Field, Error> {
+        let mut field = Field {
+            var: get_attr!(elem, "var", required),
+            type_: get_attr!(elem, "type", default),
+            label: get_attr!(elem, "label", optional),
+            required: false,
+            options: vec!(),
+            values: vec!(),
+            media: vec!(),
+        };
+        for element in elem.children() {
+            if element.is("value", ns::DATA_FORMS) {
+                for _ in element.children() {
+                    return Err(Error::ParseError("Value element must not have any child."));
+                }
+                for _ in element.attrs() {
+                    return Err(Error::ParseError("Value element must not have any attribute."));
+                }
+                field.values.push(element.text());
+            } else if element.is("required", ns::DATA_FORMS) {
+                if field.required {
+                    return Err(Error::ParseError("More than one required element."));
+                }
+                for _ in element.children() {
+                    return Err(Error::ParseError("Required element must not have any child."));
+                }
+                for _ in element.attrs() {
+                    return Err(Error::ParseError("Required element must not have any attribute."));
+                }
+                field.required = true;
+            } else if element.is("option", ns::DATA_FORMS) {
+                if !field.is_list() {
+                    return Err(Error::ParseError("Option element found in non-list field."));
+                }
+                let label = get_attr!(element, "label", optional);
+                let mut value = None;
+                for child2 in element.children() {
+                    if child2.is("value", ns::DATA_FORMS) {
+                        if value.is_some() {
+                            return Err(Error::ParseError("More than one value element in option element"));
+                        }
+                        value = Some(child2.text());
+                    } else {
+                        return Err(Error::ParseError("Non-value element in option element"));
+                    }
+                }
+                let value = value.ok_or(Error::ParseError("No value element in option element"))?;
+                field.options.push(Option_ {
+                    label: label,
+                    value: value,
+                });
+            } else if element.is("media", ns::MEDIA_ELEMENT) {
+                let media_element = MediaElement::try_from(element.clone())?;
+                field.media.push(media_element);
+            } else {
+                return Err(Error::ParseError("Field child isn’t a value or media element."));
+            }
+        }
+        Ok(field)
+    }
+}
+
 impl From<Field> for Element {
     fn from(field: Field) -> Element {
         Element::builder("field")
@@ -129,70 +201,8 @@ impl TryFrom<Element> for DataForm {
                 }
                 form.instructions = Some(child.text());
             } else if child.is("field", ns::DATA_FORMS) {
-                let var: String = get_attr!(child, "var", required);
-                let field_type = get_attr!(child, "type", default);
-                let label = get_attr!(child, "label", optional);
-
-                let is_form_type = var == "FORM_TYPE" && field_type == FieldType::Hidden;
-                let is_list = field_type == FieldType::ListSingle || field_type == FieldType::ListMulti;
-                let mut field = Field {
-                    var: var,
-                    type_: field_type,
-                    label: label,
-                    required: false,
-                    options: vec!(),
-                    values: vec!(),
-                    media: vec!(),
-                };
-                for element in child.children() {
-                    if element.is("value", ns::DATA_FORMS) {
-                        for _ in element.children() {
-                            return Err(Error::ParseError("Value element must not have any child."));
-                        }
-                        for _ in element.attrs() {
-                            return Err(Error::ParseError("Value element must not have any attribute."));
-                        }
-                        field.values.push(element.text());
-                    } else if element.is("required", ns::DATA_FORMS) {
-                        if field.required {
-                            return Err(Error::ParseError("More than one required element."));
-                        }
-                        for _ in element.children() {
-                            return Err(Error::ParseError("Required element must not have any child."));
-                        }
-                        for _ in element.attrs() {
-                            return Err(Error::ParseError("Required element must not have any attribute."));
-                        }
-                        field.required = true;
-                    } else if element.is("option", ns::DATA_FORMS) {
-                        if !is_list {
-                            return Err(Error::ParseError("Option element found in non-list field."));
-                        }
-                        let label = get_attr!(element, "label", optional);
-                        let mut value = None;
-                        for child2 in element.children() {
-                            if child2.is("value", ns::DATA_FORMS) {
-                                if value.is_some() {
-                                    return Err(Error::ParseError("More than one value element in option element"));
-                                }
-                                value = Some(child2.text());
-                            } else {
-                                return Err(Error::ParseError("Non-value element in option element"));
-                            }
-                        }
-                        let value = value.ok_or(Error::ParseError("No value element in option element"))?;
-                        field.options.push(Option_ {
-                            label: label,
-                            value: value,
-                        });
-                    } else if element.is("media", ns::MEDIA_ELEMENT) {
-                        let media_element = MediaElement::try_from(element.clone())?;
-                        field.media.push(media_element);
-                    } else {
-                        return Err(Error::ParseError("Field child isn’t a value or media element."));
-                    }
-                }
-                if is_form_type {
+                let field = Field::try_from(child.clone())?;
+                if field.var == "FORM_TYPE" && field.type_ == FieldType::Hidden {
                     if form.form_type.is_some() {
                         return Err(Error::ParseError("More than one FORM_TYPE in a data form."));
                     }