Implement optional JPEG2000 codec adapter (#40)
This commit is contained in:
@@ -4,7 +4,9 @@
|
||||
//! surfaces. Their behavior is implemented only when the owning API slice is
|
||||
//! ported.
|
||||
|
||||
use std::any::Any;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
use std::future::Future;
|
||||
use std::hash::Hash;
|
||||
use std::marker::PhantomData;
|
||||
@@ -20,6 +22,54 @@ pub trait ReadWrite: std::io::Read + std::io::Write + std::io::Seek {}
|
||||
|
||||
impl<T: std::io::Read + std::io::Write + std::io::Seek> ReadWrite for T {}
|
||||
|
||||
trait OpaqueValue: Any + fmt::Debug + Send + Sync {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
fn into_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
|
||||
}
|
||||
|
||||
impl<T: Any + fmt::Debug + Send + Sync> OpaqueValue for T {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn into_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// A type-erased reference value used when a mapped `System.Object` carries a
|
||||
/// project type rather than one of the protocol scalar variants.
|
||||
///
|
||||
/// Equality and hashing use reference identity, matching the default behavior
|
||||
/// of arbitrary CLR reference objects. The contained value can be recovered
|
||||
/// with [`Object::downcast_ref`].
|
||||
#[derive(Clone)]
|
||||
pub struct OpaqueObject(Arc<dyn OpaqueValue>);
|
||||
|
||||
impl fmt::Debug for OpaqueObject {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
formatter
|
||||
.debug_tuple("OpaqueObject")
|
||||
.field(&self.0)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for OpaqueObject {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.0, &other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for OpaqueObject {}
|
||||
|
||||
impl Hash for OpaqueObject {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
let pointer = Arc::as_ptr(&self.0).cast::<()>();
|
||||
pointer.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Object {
|
||||
Undefined,
|
||||
@@ -43,6 +93,34 @@ pub enum Object {
|
||||
Vector3(crate::Vector3),
|
||||
Vector3d(crate::Vector3d),
|
||||
Vector4(crate::Vector4),
|
||||
/// A project-owned value passed through a mapped `System.Object` boundary.
|
||||
Opaque(OpaqueObject),
|
||||
}
|
||||
|
||||
impl Object {
|
||||
/// Boxes a project-owned value for a mapped `System.Object` parameter.
|
||||
#[must_use]
|
||||
pub fn opaque<T: Any + fmt::Debug + Send + Sync>(value: T) -> Self {
|
||||
Self::Opaque(OpaqueObject(Arc::new(value)))
|
||||
}
|
||||
|
||||
/// Borrows an opaque value when its concrete type is `T`.
|
||||
#[must_use]
|
||||
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
|
||||
match self {
|
||||
Self::Opaque(value) => value.0.as_ref().as_any().downcast_ref(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Clones the opaque reference and recovers its concrete shared value.
|
||||
#[must_use]
|
||||
pub fn downcast_arc<T: Any + Send + Sync>(&self) -> Option<Arc<T>> {
|
||||
match self {
|
||||
Self::Opaque(value) => value.0.clone().into_any().downcast().ok(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Object {
|
||||
@@ -69,6 +147,7 @@ impl PartialEq for Object {
|
||||
(Self::Vector3(lhs), Self::Vector3(rhs)) => crate::Vector3::eq(*lhs, *rhs),
|
||||
(Self::Vector3d(lhs), Self::Vector3d(rhs)) => crate::Vector3d::eq(*lhs, *rhs),
|
||||
(Self::Vector4(lhs), Self::Vector4(rhs)) => crate::Vector4::eq(*lhs, *rhs),
|
||||
(Self::Opaque(lhs), Self::Opaque(rhs)) => lhs == rhs,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@@ -105,6 +184,7 @@ impl std::hash::Hash for Object {
|
||||
Self::Vector3(value) => value.get_hash_code().hash(state),
|
||||
Self::Vector3d(value) => value.get_hash_code().hash(state),
|
||||
Self::Vector4(value) => value.get_hash_code().hash(state),
|
||||
Self::Opaque(value) => value.hash(state),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,9 +459,10 @@ pub struct SocketException;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{CancellationToken, HttpMessageHandler, HttpRequest, HttpResponse, Uri};
|
||||
use super::{CancellationToken, HttpMessageHandler, HttpRequest, HttpResponse, Object, Uri};
|
||||
use std::collections::BTreeMap;
|
||||
use std::future::Future;
|
||||
use std::sync::Arc;
|
||||
use std::task::{Context, Poll, Waker};
|
||||
|
||||
#[test]
|
||||
@@ -427,4 +508,22 @@ mod tests {
|
||||
.is_success_status_code()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn opaque_objects_downcast_and_preserve_reference_identity() {
|
||||
let object = Object::opaque(String::from("managed image boundary"));
|
||||
assert_eq!(
|
||||
object.downcast_ref::<String>().map(String::as_str),
|
||||
Some("managed image boundary")
|
||||
);
|
||||
assert!(object.downcast_ref::<Vec<u8>>().is_none());
|
||||
let first = object.downcast_arc::<String>().expect("shared string");
|
||||
let second = object.downcast_arc::<String>().expect("shared string");
|
||||
assert!(Arc::ptr_eq(&first, &second));
|
||||
assert_eq!(object, object.clone());
|
||||
assert_ne!(
|
||||
object,
|
||||
Object::opaque(String::from("managed image boundary"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user