#[cfg(any(feature = "alloc", feature = "std"))]
use crate::model::capabilities::DisplayCapabilities;
use crate::model::capabilities::StaticContext;
#[cfg(any(feature = "alloc", feature = "std"))]
use crate::model::diagnostics::ParseWarning;
#[cfg(any(feature = "alloc", feature = "std"))]
use crate::model::prelude::{Box, String, Vec};
#[cfg(any(feature = "alloc", feature = "std"))]
pub trait ExtensionHandler: core::fmt::Debug {
fn process(
&self,
blocks: &[&[u8; 128]],
caps: &mut DisplayCapabilities,
warnings: &mut Vec<ParseWarning>,
);
}
pub trait StaticExtensionHandler: Sync {
fn tag(&self) -> u8;
fn process(&self, blocks: &[&[u8; 128]], ctx: &mut StaticContext<'_>);
}
#[cfg(any(feature = "alloc", feature = "std"))]
pub struct ExtensionMetadata {
pub tag: u8,
pub display_name: String,
pub handler: Option<Box<dyn ExtensionHandler>>,
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl core::fmt::Debug for ExtensionMetadata {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ExtensionMetadata")
.field("tag", &self.tag)
.field("display_name", &self.display_name)
.field("has_handler", &self.handler.is_some())
.finish()
}
}
#[cfg(not(any(feature = "alloc", feature = "std")))]
#[derive(Debug, Clone, PartialEq)]
pub struct ExtensionMetadata {
pub tag: u8,
}
pub trait KnownExtensions {
fn is_known(&self, tag: u8) -> bool;
}
#[cfg(any(feature = "alloc", feature = "std"))]
pub struct ExtensionTagRegistry {
pub known_tags: Vec<u8>,
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl Default for ExtensionTagRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl ExtensionTagRegistry {
pub const fn new() -> Self {
Self {
known_tags: Vec::new(),
}
}
pub fn register(&mut self, tag: u8) -> bool {
if !self.known_tags.contains(&tag) {
self.known_tags.push(tag);
}
true
}
pub fn is_known(&self, tag: u8) -> bool {
self.known_tags.contains(&tag)
}
}
#[cfg(not(any(feature = "alloc", feature = "std")))]
pub struct ExtensionTagRegistry {
tags: [u8; 16],
len: usize,
}
#[cfg(not(any(feature = "alloc", feature = "std")))]
impl Default for ExtensionTagRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(not(any(feature = "alloc", feature = "std")))]
impl ExtensionTagRegistry {
pub fn new() -> Self {
Self {
tags: [0u8; 16],
len: 0,
}
}
pub fn register(&mut self, tag: u8) -> bool {
if self.is_known(tag) {
return true; }
debug_assert!(
self.len < 16,
"ExtensionTagRegistry is full (capacity 16); tag {tag:#04x} was not registered"
);
if self.len < 16 {
self.tags[self.len] = tag;
self.len += 1;
true
} else {
false
}
}
pub fn is_known(&self, tag: u8) -> bool {
self.tags[..self.len].contains(&tag)
}
}
impl KnownExtensions for ExtensionTagRegistry {
fn is_known(&self, tag: u8) -> bool {
Self::is_known(self, tag)
}
}
impl KnownExtensions for [&dyn StaticExtensionHandler] {
fn is_known(&self, tag: u8) -> bool {
self.iter().any(|h| h.tag() == tag)
}
}
pub struct ExtensionLibrary {
#[cfg(any(feature = "alloc", feature = "std"))]
pub base_handlers: Vec<Box<dyn ExtensionHandler>>,
#[cfg(any(feature = "alloc", feature = "std"))]
pub extensions: Vec<ExtensionMetadata>,
}
impl Default for ExtensionLibrary {
fn default() -> Self {
Self::new()
}
}
impl ExtensionLibrary {
pub fn new() -> Self {
Self {
#[cfg(any(feature = "alloc", feature = "std"))]
base_handlers: Vec::new(),
#[cfg(any(feature = "alloc", feature = "std"))]
extensions: Vec::new(),
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn add_base_handler<H: ExtensionHandler + 'static>(&mut self, handler: H) {
self.base_handlers.push(Box::new(handler));
}
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn with_standard_extensions() -> Self {
let mut lib = Self::new();
lib.register(ExtensionMetadata {
tag: 0x02,
display_name: String::from("CEA-861"),
handler: None, });
lib.register(ExtensionMetadata {
tag: 0x70,
display_name: String::from("DisplayID"),
handler: None,
});
lib.register(ExtensionMetadata {
tag: 0xF0,
display_name: String::from("Block Map"),
handler: None, });
lib
}
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn register(&mut self, metadata: ExtensionMetadata) {
if !self.extensions.iter().any(|ext| ext.tag == metadata.tag) {
self.extensions.push(metadata);
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn export_tags(&self) -> ExtensionTagRegistry {
let mut known_tags = Vec::new();
for ext in &self.extensions {
known_tags.push(ext.tag);
}
ExtensionTagRegistry { known_tags }
}
#[cfg(not(any(feature = "alloc", feature = "std")))]
pub fn export_tags(&self) -> ExtensionTagRegistry {
ExtensionTagRegistry::new()
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl KnownExtensions for ExtensionLibrary {
fn is_known(&self, tag: u8) -> bool {
self.extensions.iter().any(|e| e.tag == tag)
}
}