aboutsummaryrefslogtreecommitdiff
path: root/src/api_interface_definition.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/api_interface_definition.rs')
-rw-r--r--src/api_interface_definition.rs398
1 files changed, 198 insertions, 200 deletions
diff --git a/src/api_interface_definition.rs b/src/api_interface_definition.rs
index 784b7d0..8208dbe 100644
--- a/src/api_interface_definition.rs
+++ b/src/api_interface_definition.rs
@@ -1,8 +1,12 @@
//! GL API interface definition.
-use quick_xml::events::BytesStart;
+use std::borrow::Cow;
-use crate::deserialization::{Deserialize, Deserializer, DeserializerError};
+use xml_stinks::deserializer::Deserializer;
+use xml_stinks::tagged::{TagStart, TagStartError};
+use xml_stinks::{impl_from_deserializer_error, DeserializeTagged};
+
+use crate::util::impl_from_deserializer_err_wrapped;
use crate::DeserializationError;
/// GL API interface definition.
@@ -73,48 +77,39 @@ impl APIInterfaceDefinition
}
}
-impl Deserialize for APIInterfaceDefinition
+impl DeserializeTagged for APIInterfaceDefinition
{
type Error = Error;
fn deserialize<TDeserializer: Deserializer>(
- start: &BytesStart,
+ start: &TagStart,
deserializer: &mut TDeserializer,
) -> Result<Self, Self::Error>
{
- let api_name = String::from_utf8(
- start
- .try_get_attribute(b"api")
- .map_err(DeserializerError::ReadFailed)?
- .ok_or_else(|| Error::MissingAPIName)?
- .value
- .into_owned(),
- )
- .map_err(|_| Error::APINameNotUTF8)?;
-
- let name = String::from_utf8(
- start
- .try_get_attribute(b"name")
- .map_err(DeserializerError::ReadFailed)?
- .ok_or_else(|| Error::MissingName)?
- .value
- .into_owned(),
- )
- .map_err(|_| Error::NameNotUTF8)?;
-
- let version = String::from_utf8(
- start
- .try_get_attribute(b"number")
- .map_err(DeserializerError::ReadFailed)?
- .ok_or_else(|| Error::MissingVersionNumber)?
- .value
- .into_owned(),
- )
- .map_err(|_| Error::VersionNotUTF8)?;
-
- let requirements = deserializer.de_tag_list::<Requirement>("require")?;
-
- let removals = deserializer.de_tag_list::<Removal>("remove")?;
+ let api_name = start
+ .get_attribute("api")?
+ .ok_or_else(|| Error::MissingAPIName)?
+ .value()
+ .map_err(|_| Error::APINameNotUTF8)?
+ .into_owned();
+
+ let name = start
+ .get_attribute("name")?
+ .ok_or_else(|| Error::MissingName)?
+ .value()
+ .map_err(|_| Error::NameNotUTF8)?
+ .into_owned();
+
+ let version = start
+ .get_attribute("number")?
+ .ok_or_else(|| Error::MissingVersionNumber)?
+ .value()
+ .map_err(|_| Error::VersionNotUTF8)?
+ .into_owned();
+
+ let requirements = deserializer.de_tag_list::<Requirement, _>(Some("require"))?;
+
+ let removals = deserializer.de_tag_list::<Removal, _>(Some("remove"))?;
Ok(Self {
api_name,
@@ -154,19 +149,26 @@ pub enum Error
#[error("Version is not valid UTF-8")]
VersionNotUTF8,
+ /// Invalid requirement.
+ #[error("Invalid requirement")]
+ InvalidRequirement(#[from] RequirementError),
+
+ /// Invalid removal.
+ #[error("Invalid removal")]
+ InvalidRemoval(#[from] RemovalError),
+
/// Deserialization failed.
#[error("Deserialization failed")]
DeserializationFailed(#[from] DeserializationError),
-}
-impl From<DeserializerError> for Error
-{
- fn from(err: DeserializerError) -> Self
- {
- DeserializationError(err).into()
- }
+ /// Invalid tag start.
+ #[error("Invalid tag start")]
+ InvalidTagStart(#[from] TagStartError),
}
+impl_from_deserializer_err_wrapped!(Error);
+impl_from_deserializer_error!(Error);
+
/// GL API feature requirement.
#[derive(Debug, PartialEq, Eq)]
pub struct Requirement
@@ -215,38 +217,36 @@ impl Requirement
}
}
-impl Deserialize for Requirement
+impl DeserializeTagged for Requirement
{
type Error = RequirementError;
fn deserialize<TDeserializer: Deserializer>(
- start: &BytesStart,
+ start: &TagStart,
deserializer: &mut TDeserializer,
) -> Result<Self, Self::Error>
{
- let profile = match start
- .try_get_attribute(b"profile")
- .map_err(DeserializerError::ReadFailed)?
- {
+ let profile = match start.get_attribute("profile")? {
Some(comment_attr) => Some(
- String::from_utf8(comment_attr.value.into_owned())
- .map_err(|_| RequirementError::ProfileNotUTF8)?,
+ comment_attr
+ .value()
+ .map_err(|_| RequirementError::ProfileNotUTF8)?
+ .into_owned(),
),
None => None,
};
- let comment = match start
- .try_get_attribute(b"comment")
- .map_err(DeserializerError::ReadFailed)?
- {
+ let comment = match start.get_attribute("comment")? {
Some(comment_attr) => Some(
- String::from_utf8(comment_attr.value.into_owned())
- .map_err(|_| RequirementError::CommentNotUTF8)?,
+ comment_attr
+ .value()
+ .map_err(|_| RequirementError::CommentNotUTF8)?
+ .into_owned(),
),
None => None,
};
- let features = deserializer.de_list::<Feature>()?;
+ let features = deserializer.de_tag_list::<Feature, _>(None::<&str>)?;
Ok(Self {
profile,
@@ -268,19 +268,22 @@ pub enum RequirementError
#[error("Comment is not valid UTF-8")]
CommentNotUTF8,
+ /// Invalid feature.
+ #[error("Invalid feature")]
+ InvalidFeature(#[from] FeatureError),
+
/// Deserialization failed.
#[error("Deserialization failed")]
DeserializationFailed(#[from] DeserializationError),
-}
-impl From<DeserializerError> for RequirementError
-{
- fn from(err: DeserializerError) -> Self
- {
- DeserializationError(err).into()
- }
+ /// Invalid tag start.
+ #[error("Invalid tag start")]
+ InvalidTagStart(#[from] TagStartError),
}
+impl_from_deserializer_err_wrapped!(RequirementError);
+impl_from_deserializer_error!(RequirementError);
+
/// GL API feature removal.
#[derive(Debug, PartialEq, Eq)]
pub struct Removal
@@ -329,36 +332,30 @@ impl Removal
}
}
-impl Deserialize for Removal
+impl DeserializeTagged for Removal
{
type Error = RemovalError;
fn deserialize<TDeserializer: Deserializer>(
- start: &BytesStart,
+ start: &TagStart,
deserializer: &mut TDeserializer,
) -> Result<Self, Self::Error>
{
- let profile = String::from_utf8(
- start
- .try_get_attribute(b"profile")
- .map_err(DeserializerError::ReadFailed)?
- .ok_or_else(|| RemovalError::MissingProfile)?
- .value
- .into_owned(),
- )
- .map_err(|_| RemovalError::ProfileNotUTF8)?;
-
- let comment = String::from_utf8(
- start
- .try_get_attribute(b"comment")
- .map_err(DeserializerError::ReadFailed)?
- .ok_or_else(|| RemovalError::MissingComment)?
- .value
- .into_owned(),
- )
- .map_err(|_| RemovalError::CommentNotUTF8)?;
-
- let features = deserializer.de_list::<Feature>()?;
+ let profile = start
+ .get_attribute("profile")?
+ .ok_or_else(|| RemovalError::MissingProfile)?
+ .value()
+ .map_err(|_| RemovalError::ProfileNotUTF8)?
+ .into_owned();
+
+ let comment = start
+ .get_attribute("comment")?
+ .ok_or_else(|| RemovalError::MissingComment)?
+ .value()
+ .map_err(|_| RemovalError::CommentNotUTF8)?
+ .into_owned();
+
+ let features = deserializer.de_tag_list::<Feature, _>(None::<&str>)?;
Ok(Self {
profile,
@@ -388,19 +385,22 @@ pub enum RemovalError
#[error("Comment is not valid UTF-8")]
CommentNotUTF8,
+ /// Invalid feature.
+ #[error("Invalid feature")]
+ InvalidFeature(#[from] FeatureError),
+
/// Deserialization failed.
#[error("Deserialization failed")]
DeserializationFailed(#[from] DeserializationError),
-}
-impl From<DeserializerError> for RemovalError
-{
- fn from(err: DeserializerError) -> Self
- {
- DeserializationError(err).into()
- }
+ /// Invalid tag start.
+ #[error("Invalid tag start")]
+ InvalidTagStart(#[from] TagStartError),
}
+impl_from_deserializer_err_wrapped!(RemovalError);
+impl_from_deserializer_error!(RemovalError);
+
/// GL API feature.
#[derive(Debug, PartialEq, Eq)]
pub struct Feature
@@ -449,16 +449,16 @@ impl Feature
}
}
-impl Deserialize for Feature
+impl DeserializeTagged for Feature
{
type Error = FeatureError;
fn deserialize<TDeserializer: Deserializer>(
- start: &BytesStart,
+ start: &TagStart,
_deserializer: &mut TDeserializer,
) -> Result<Self, Self::Error>
{
- let kind = match start.name().as_ref() {
+ let kind = match start.name_bytes() {
b"enum" => Ok(FeatureKind::Enum),
b"command" => Ok(FeatureKind::Command),
b"type" => Ok(FeatureKind::Type),
@@ -467,26 +467,22 @@ impl Deserialize for Feature
)),
}?;
- let name = String::from_utf8(
- start
- .try_get_attribute(b"name")
- .map_err(DeserializerError::ReadFailed)?
- .ok_or_else(|| FeatureError::MissingName)?
- .value
- .into_owned(),
- )
- .map_err(|_| FeatureError::NameNotUTF8)?;
-
- let comment = match start
- .try_get_attribute(b"comment")
- .map_err(DeserializerError::ReadFailed)?
- {
- Some(comment_attr) => Some(
- String::from_utf8(comment_attr.value.into_owned())
- .map_err(|_| FeatureError::CommentNotUTF8)?,
- ),
- None => None,
- };
+ let name = start
+ .get_attribute("name")?
+ .ok_or_else(|| FeatureError::MissingName)?
+ .value()
+ .map_err(|_| FeatureError::NameNotUTF8)?
+ .into_owned();
+
+ let comment = start
+ .get_attribute("comment")?
+ .map(|comment_attr| {
+ comment_attr
+ .value()
+ .map(Cow::into_owned)
+ .map_err(|_| FeatureError::CommentNotUTF8)
+ })
+ .transpose()?;
Ok(Self {
kind,
@@ -519,16 +515,15 @@ pub enum FeatureError
/// Deserialization failed.
#[error("Deserialization failed")]
DeserializationFailed(#[from] DeserializationError),
-}
-impl From<DeserializerError> for FeatureError
-{
- fn from(err: DeserializerError) -> Self
- {
- DeserializationError(err).into()
- }
+ /// Invalid tag start.
+ #[error("Invalid tag start")]
+ InvalidTagStart(#[from] TagStartError),
}
+impl_from_deserializer_err_wrapped!(FeatureError);
+impl_from_deserializer_error!(FeatureError);
+
/// GL API feature kind.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FeatureKind
@@ -547,9 +542,10 @@ pub enum FeatureKind
mod tests
{
use pretty_assertions::{assert_eq, assert_str_eq};
+ use xml_stinks::attribute::Attribute;
use super::*;
- use crate::deserialization::MockDeserializer;
+ use crate::test_utils::MockDeserializer;
#[test]
fn deserialize_feature_works()
@@ -557,7 +553,8 @@ mod tests
let mut mock_deserializer = MockDeserializer::new();
let commentless_enum_feature = Feature::deserialize(
- &BytesStart::new("enum").with_attributes([("name", "GL_BLEND")]),
+ &TagStart::new("enum")
+ .with_attributes([Attribute::new("name", "GL_BLEND".as_bytes())]),
&mut mock_deserializer,
)
.expect("Expected Ok");
@@ -567,9 +564,12 @@ mod tests
assert!(commentless_enum_feature.comment.is_none());
let enum_feature = Feature::deserialize(
- &BytesStart::new("enum").with_attributes([
- ("name", "GL_VERTEX_BINDING_BUFFER"),
- ("comment", "Added in 2013/10/22 update to the spec"),
+ &TagStart::new("enum").with_attributes([
+ Attribute::new("name", "GL_VERTEX_BINDING_BUFFER".as_bytes()),
+ Attribute::new(
+ "comment",
+ "Added in 2013/10/22 update to the spec".as_bytes(),
+ ),
]),
&mut mock_deserializer,
)
@@ -584,7 +584,8 @@ mod tests
);
let command_feature = Feature::deserialize(
- &BytesStart::new("command").with_attributes([("name", "glCreateBuffers")]),
+ &TagStart::new("command")
+ .with_attributes([Attribute::new("name", "glCreateBuffers".as_bytes())]),
&mut mock_deserializer,
)
.expect("Expected Ok");
@@ -594,7 +595,8 @@ mod tests
assert!(command_feature.comment.is_none());
let type_feature = Feature::deserialize(
- &BytesStart::new("type").with_attributes([("name", "GLbyte")]),
+ &TagStart::new("type")
+ .with_attributes([Attribute::new("name", "GLbyte".as_bytes())]),
&mut mock_deserializer,
)
.expect("Expected Ok");
@@ -604,7 +606,7 @@ mod tests
assert!(type_feature.comment.is_none());
assert!(matches!(
- Feature::deserialize(&BytesStart::new("foo"), &mut mock_deserializer),
+ Feature::deserialize(&TagStart::new("foo"), &mut mock_deserializer),
Err(FeatureError::UnknownFeatureKind(_))
));
}
@@ -614,22 +616,22 @@ mod tests
{
let mut mock_deserializer = MockDeserializer::new();
- // SAFETY: No argument lifetime is mistreated
- unsafe {
- mock_deserializer.expect_de_list().times(1).returning(|_| {
+ mock_deserializer
+ .expect_de_tag_list::<_, &str>()
+ .times(1)
+ .returning(|_| {
Ok(vec![
Feature::new(FeatureKind::Command, "glNewList", None),
Feature::new(FeatureKind::Command, "glEndList", None),
])
});
- }
let removal = Removal::deserialize(
- &BytesStart::new("remove").with_attributes([
- ("profile", "core"),
- (
+ &TagStart::new("remove").with_attributes([
+ Attribute::new("profile", "core".as_bytes()),
+ Attribute::new(
"comment",
- "Compatibility-only GL 1.0 features removed from GL 3.2",
+ "Compatibility-only GL 1.0 features removed from GL 3.2".as_bytes(),
),
]),
&mut mock_deserializer,
@@ -651,39 +653,39 @@ mod tests
{
let mut mock_deserializer = MockDeserializer::new();
- // SAFETY: No argument lifetime is mistreated
- unsafe {
- mock_deserializer.expect_de_list().times(1).returning(|_| {
+ mock_deserializer
+ .expect_de_tag_list::<_, &str>()
+ .times(1)
+ .returning(|_| {
Ok(vec![
Feature::new(FeatureKind::Command, "glNewList", None),
Feature::new(FeatureKind::Command, "glEndList", None),
])
});
- }
- // SAFETY: No argument lifetime is mistreated
- unsafe {
- mock_deserializer.expect_de_list().times(1).returning(|_| {
+ mock_deserializer
+ .expect_de_tag_list::<_, &str>()
+ .times(1)
+ .returning(|_| {
Ok(vec![
Feature::new(FeatureKind::Enum, "GL_COLOR_TABLE", None),
Feature::new(FeatureKind::Enum, "GL_MINMAX", None),
Feature::new(FeatureKind::Enum, "GL_HISTOGRAM", None),
])
});
- }
- // SAFETY: No argument lifetime is mistreated
- unsafe {
- mock_deserializer.expect_de_list().times(1).returning(|_| {
+ mock_deserializer
+ .expect_de_tag_list::<_, &str>()
+ .times(1)
+ .returning(|_| {
Ok(vec![
Feature::new(FeatureKind::Enum, "GL_STACK_UNDERFLOW", None),
Feature::new(FeatureKind::Enum, "GL_STACK_OVERFLOW", None),
])
});
- }
let requirement =
- Requirement::deserialize(&BytesStart::new("require"), &mut mock_deserializer)
+ Requirement::deserialize(&TagStart::new("require"), &mut mock_deserializer)
.expect("Expected Ok");
assert!(requirement.profile.is_none());
@@ -692,7 +694,8 @@ mod tests
assert_eq!(requirement.features.len(), 2);
let requirement = Requirement::deserialize(
- &BytesStart::new("require").with_attributes([("profile", "compatibility")]),
+ &TagStart::new("require")
+ .with_attributes([Attribute::new("profile", "compatibility".as_bytes())]),
&mut mock_deserializer,
)
.expect("Expected Ok");
@@ -703,14 +706,15 @@ mod tests
assert_eq!(requirement.features.len(), 3);
let requirement = Requirement::deserialize(
- &BytesStart::new("require").with_attributes([
- ("profile", "core"),
- (
+ &TagStart::new("require").with_attributes([
+ Attribute::new("profile", "core".as_bytes()),
+ Attribute::new(
"comment",
concat!(
"Restore functionality removed in GL 3.2 core ",
"to GL 4.3. Needed for debug interface."
- ),
+ )
+ .as_bytes(),
),
]),
&mut mock_deserializer,
@@ -734,49 +738,43 @@ mod tests
{
let mut mock_deserializer = MockDeserializer::new();
- // SAFETY: No argument lifetime is mistreated
- unsafe {
- mock_deserializer
- .expect_de_tag_list()
- .times(1)
- .returning(|_, _| {
- Ok(vec![
- Requirement::new(
- None,
- None,
- vec![
- Feature::new(FeatureKind::Command, "glFenceSync", None),
- Feature::new(FeatureKind::Enum, "GL_WAIT_FAILED", None),
- ],
- ),
- Requirement::new(
- None,
- Some("Reuse ARB_sync".to_string()),
- [Feature::new(FeatureKind::Enum, "GL_OBJECT_TYPE", None)],
- ),
- ])
- });
- }
+ mock_deserializer
+ .expect_de_tag_list::<_, &str>()
+ .times(1)
+ .returning(|_| {
+ Ok(vec![
+ Requirement::new(
+ None,
+ None,
+ vec![
+ Feature::new(FeatureKind::Command, "glFenceSync", None),
+ Feature::new(FeatureKind::Enum, "GL_WAIT_FAILED", None),
+ ],
+ ),
+ Requirement::new(
+ None,
+ Some("Reuse ARB_sync".to_string()),
+ [Feature::new(FeatureKind::Enum, "GL_OBJECT_TYPE", None)],
+ ),
+ ])
+ });
- // SAFETY: No argument lifetime is mistreated
- unsafe {
- mock_deserializer
- .expect_de_tag_list()
- .times(1)
- .returning(|_, _| {
- Ok(vec![Removal::new(
- "core",
- "Compatibility-only GL 1.0 features removed from GL 3.2",
- vec![Feature::new(FeatureKind::Command, "glBegin", None)],
- )])
- });
- }
+ mock_deserializer
+ .expect_de_tag_list::<_, &str>()
+ .times(1)
+ .returning(|_| {
+ Ok(vec![Removal::new(
+ "core",
+ "Compatibility-only GL 1.0 features removed from GL 3.2",
+ vec![Feature::new(FeatureKind::Command, "glBegin", None)],
+ )])
+ });
let api_interface_definition = APIInterfaceDefinition::deserialize(
- &BytesStart::new("feature").with_attributes([
- ("api", "gl"),
- ("name", "GL_VERSION_3_2"),
- ("number", "3.2"),
+ &TagStart::new("feature").with_attributes([
+ Attribute::new("api", "gl".as_bytes()),
+ Attribute::new("name", "GL_VERSION_3_2".as_bytes()),
+ Attribute::new("number", "3.2".as_bytes()),
]),
&mut mock_deserializer,
)