use std::borrow::Cow;
use nom::{
branch::alt,
bytes::complete::tag,
character::complete::{anychar, char},
combinator::{map, verify},
sequence::tuple,
IResult,
};
use crate::{parse::Parse, QualifiedName};
pub trait ParseNamespace<'a>: Parse<'a> + Sized {
fn parse_namespace_attribute_name(input: &'a str) -> IResult<&'a str, Cow<'a, str>> {
let (input, name) = alt((
Self::parse_prefixed_attribute_name,
map(tag("xmlns"), Cow::Borrowed),
))(input)?;
Ok((input, name))
}
fn parse_prefixed_attribute_name(input: &'a str) -> IResult<&'a str, Cow<'a, str>> {
let (input, _) = tag("xmlns:")(input)?;
let (input, name) = Self::parse_non_colonized_name(input)?;
Ok((input, name))
}
fn parse_non_colonized_name(input: &'a str) -> IResult<&'a str, Cow<'a, str>> {
let (input, start_char) = Self::parse_name_start_char(input)?;
let (input, rest_chars) = map(
nom::bytes::complete::take_while1(|c: char| Self::is_name_char(c) && c != ':'),
Cow::Borrowed,
)(input)?;
let mut name = start_char.to_string();
name.push_str(&rest_chars);
Ok((input, Cow::Owned(name)))
}
fn parse_non_colonized_name_char(input: &'a str) -> IResult<&'a str, char> {
let (input, valid_char) = verify(Self::parse_name_char, |c| *c != ':')(input)?;
Ok((input, valid_char))
}
fn parse_non_colonized_name_start_char(input: &'a str) -> IResult<&'a str, char> {
let (input, valid_char) = verify(anychar, |c| *c != ':')(input)?;
Ok((input, valid_char))
}
fn parse_qualified_name(input: &'a str) -> IResult<&'a str, QualifiedName> {
alt((
Self::parse_prefixed_name,
map(Self::parse_non_colonized_name, |local_part| QualifiedName {
prefix: None,
local_part,
}),
))(input)
}
fn parse_prefixed_name(input: &'a str) -> IResult<&'a str, QualifiedName> {
let (input, x) = map(
tuple((
Self::parse_non_colonized_name,
char(':'),
Self::parse_non_colonized_name,
)),
|(prefix, _, local_part)| QualifiedName {
prefix: Some(prefix),
local_part,
},
)(input)?;
Ok((input, x))
}
}