Repository: Orange-OpenSource/hurl
File: packages/hurl_core/src/parser/parsers.rs (Rust)

Code before:
        space0,
        method,
        space1,
        url,
        line_terminator0,
        headers,
        sections,
        body,
        source_info,
    })
}

fn response(reader: &mut Reader) -> ParseResult<Response> {
    let start = reader.cursor();
    let line_terminators = optional_line_terminators(reader)?;
    let space0 = zero_or_more_spaces(reader)?;
    let version = version(reader)?;
    let space1 = one_or_more_spaces(reader)?;
    let status = status(reader)?;
    let line_terminator0 = line_terminator(reader)?;
    let headers = zero_or_more(key_value, reader)?;
    let sections = response_sections(reader)?;
    let body = optional(body, reader)?;
    let source_info = SourceInfo::new(start.pos, reader.cursor().pos);

    // Check duplicated section
    let mut section_names = vec![];
    for section in &sections {
        if section_names.contains(&section.identifier()) {
            return Err(ParseError::new(
                section.source_info.start,
                false,
                ParseErrorKind::DuplicateSection,
            ));
        } else {
            section_names.push(section.identifier());
        }
    }

    Ok(Response {
        line_terminators,
        space0,
        version,
        space1,
        status,
        line_terminator0,
        headers,
        sections,
        body,
        source_info,
    })

Review comment (refactor):
Maybe we should make a function to reuse it in `request` and `response` functions:

```rust
fn response(reader: &mut Reader) -> ParseResult<Response> {
    let start = reader.cursor();
    // ...
    check_duplicated_sections(&sections)?;

    Ok(Response {
        line_terminators,
        space0,
       // ...
```

With this function:

```rust
// TODO: write a nice function doc
fn check_duplicated_sections(sections: &[Section]) -> Result<(), ParseError> {
    let mut section_names = vec![];
    for section in sections {
        if section_names.contains(&section.identifier()) {
            return Err(ParseError::new(
                section.source_info.start,
                false,
                ParseErrorKind::DuplicateSection,
            ));
        } else {
            section_names.push(section.identifier());
        }
    }
    Ok(())
}

```




Code after:
fn response(reader: &mut Reader) -> ParseResult<Response> {
    let start = reader.cursor();
    let line_terminators = optional_line_terminators(reader)?;
    let space0 = zero_or_more_spaces(reader)?;
    let version = version(reader)?;
    let space1 = one_or_more_spaces(reader)?;
    let status = status(reader)?;
    let line_terminator0 = line_terminator(reader)?;
    let headers = zero_or_more(key_value, reader)?;
    let sections = response_sections(reader)?;
    let body = optional(body, reader)?;
    let source_info = SourceInfo::new(start.pos, reader.cursor().pos);

    check_duplicated_sections(&sections)?;

    Ok(Response {
        line_terminators,
        space0,
        version,
        space1,
        status,
        line_terminator0,
        headers,
        sections,
        body,
        source_info,
    })
}

fn check_duplicated_sections(sections: &[Section]) -> Result<(), ParseError> {
    let mut section_names = vec![];
    for section in sections {
        if section_names.contains(&section.identifier()) {
            return Err(ParseError::new(
                section.source_info.start,
                false,
                ParseErrorKind::DuplicateSection,
            ));
        } else {
            section_names.push(section.identifier());
        }
    }
    Ok(())
}

fn method(reader: &mut Reader) -> ParseResult<Method> {
    if reader.is_eof() {
        let kind = ParseErrorKind::Method {
            name: "<EOF>".to_string(),
        };
        return Err(ParseError::new(reader.cursor().pos, true, kind));