mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 06:44:14 +00:00
use ManuallyDrop
for remaining resources
This commit is contained in:
parent
b0cc0d2ebc
commit
c1bc0864c5
@ -26,6 +26,7 @@ use serde::Serialize;
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
mem::ManuallyDrop,
|
||||
ops::Range,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
@ -498,7 +499,7 @@ impl<A: HalApi> std::fmt::Display for ExclusivePipeline<A> {
|
||||
/// Bind group layout.
|
||||
#[derive(Debug)]
|
||||
pub struct BindGroupLayout<A: HalApi> {
|
||||
pub(crate) raw: Option<A::BindGroupLayout>,
|
||||
pub(crate) raw: ManuallyDrop<A::BindGroupLayout>,
|
||||
pub(crate) device: Arc<Device<A>>,
|
||||
pub(crate) entries: bgl::EntryMap,
|
||||
/// It is very important that we know if the bind group comes from the BGL pool.
|
||||
@ -517,15 +518,15 @@ pub struct BindGroupLayout<A: HalApi> {
|
||||
|
||||
impl<A: HalApi> Drop for BindGroupLayout<A> {
|
||||
fn drop(&mut self) {
|
||||
resource_log!("Destroy raw {}", self.error_ident());
|
||||
if matches!(self.origin, bgl::Origin::Pool) {
|
||||
self.device.bgl_pool.remove(&self.entries);
|
||||
}
|
||||
if let Some(raw) = self.raw.take() {
|
||||
resource_log!("Destroy raw {}", self.error_ident());
|
||||
unsafe {
|
||||
use hal::Device;
|
||||
self.device.raw().destroy_bind_group_layout(raw);
|
||||
}
|
||||
// SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
|
||||
let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
|
||||
unsafe {
|
||||
use hal::Device;
|
||||
self.device.raw().destroy_bind_group_layout(raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -537,7 +538,7 @@ crate::impl_storage_item!(BindGroupLayout);
|
||||
|
||||
impl<A: HalApi> BindGroupLayout<A> {
|
||||
pub(crate) fn raw(&self) -> &A::BindGroupLayout {
|
||||
self.raw.as_ref().unwrap()
|
||||
&self.raw
|
||||
}
|
||||
}
|
||||
|
||||
@ -651,7 +652,7 @@ pub struct ResolvedPipelineLayoutDescriptor<'a, A: HalApi> {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PipelineLayout<A: HalApi> {
|
||||
pub(crate) raw: Option<A::PipelineLayout>,
|
||||
pub(crate) raw: ManuallyDrop<A::PipelineLayout>,
|
||||
pub(crate) device: Arc<Device<A>>,
|
||||
/// The `label` from the descriptor used to create the resource.
|
||||
pub(crate) label: String,
|
||||
@ -661,19 +662,19 @@ pub struct PipelineLayout<A: HalApi> {
|
||||
|
||||
impl<A: HalApi> Drop for PipelineLayout<A> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(raw) = self.raw.take() {
|
||||
resource_log!("Destroy raw {}", self.error_ident());
|
||||
unsafe {
|
||||
use hal::Device;
|
||||
self.device.raw().destroy_pipeline_layout(raw);
|
||||
}
|
||||
resource_log!("Destroy raw {}", self.error_ident());
|
||||
// SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
|
||||
let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
|
||||
unsafe {
|
||||
use hal::Device;
|
||||
self.device.raw().destroy_pipeline_layout(raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: HalApi> PipelineLayout<A> {
|
||||
pub(crate) fn raw(&self) -> &A::PipelineLayout {
|
||||
self.raw.as_ref().unwrap()
|
||||
&self.raw
|
||||
}
|
||||
|
||||
pub(crate) fn get_binding_maps(&self) -> ArrayVec<&bgl::EntryMap, { hal::MAX_BIND_GROUPS }> {
|
||||
|
@ -2191,23 +2191,21 @@ impl Global {
|
||||
if !cache.device.is_valid() {
|
||||
return None;
|
||||
}
|
||||
if let Some(raw_cache) = cache.raw.as_ref() {
|
||||
let mut vec = unsafe { cache.device.raw().pipeline_cache_get_data(raw_cache) }?;
|
||||
let validation_key = cache.device.raw().pipeline_cache_validation_key()?;
|
||||
let mut vec = unsafe { cache.device.raw().pipeline_cache_get_data(cache.raw()) }?;
|
||||
let validation_key = cache.device.raw().pipeline_cache_validation_key()?;
|
||||
|
||||
let mut header_contents = [0; pipeline_cache::HEADER_LENGTH];
|
||||
pipeline_cache::add_cache_header(
|
||||
&mut header_contents,
|
||||
&vec,
|
||||
&cache.device.adapter.raw.info,
|
||||
validation_key,
|
||||
);
|
||||
let mut header_contents = [0; pipeline_cache::HEADER_LENGTH];
|
||||
pipeline_cache::add_cache_header(
|
||||
&mut header_contents,
|
||||
&vec,
|
||||
&cache.device.adapter.raw.info,
|
||||
validation_key,
|
||||
);
|
||||
|
||||
let deleted = vec.splice(..0, header_contents).collect::<Vec<_>>();
|
||||
debug_assert!(deleted.is_empty());
|
||||
let deleted = vec.splice(..0, header_contents).collect::<Vec<_>>();
|
||||
debug_assert!(deleted.is_empty());
|
||||
|
||||
return Some(vec);
|
||||
}
|
||||
return Some(vec);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ use super::{
|
||||
/// When locking pending_writes please check that trackers is not locked
|
||||
/// trackers should be locked only when needed for the shortest time possible
|
||||
pub struct Device<A: HalApi> {
|
||||
raw: Option<A::Device>,
|
||||
raw: ManuallyDrop<A::Device>,
|
||||
pub(crate) adapter: Arc<Adapter<A>>,
|
||||
pub(crate) queue: OnceCell<Weak<Queue<A>>>,
|
||||
queue_to_drop: OnceCell<A::Queue>,
|
||||
@ -169,7 +169,8 @@ impl<A: HalApi> std::fmt::Debug for Device<A> {
|
||||
impl<A: HalApi> Drop for Device<A> {
|
||||
fn drop(&mut self) {
|
||||
resource_log!("Drop {}", self.error_ident());
|
||||
let raw = self.raw.take().unwrap();
|
||||
// SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
|
||||
let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
|
||||
// SAFETY: We are in the Drop impl and we don't use self.pending_writes anymore after this point.
|
||||
let pending_writes = unsafe { ManuallyDrop::take(&mut self.pending_writes.lock()) };
|
||||
pending_writes.dispose(&raw);
|
||||
@ -193,7 +194,7 @@ pub enum CreateDeviceError {
|
||||
|
||||
impl<A: HalApi> Device<A> {
|
||||
pub(crate) fn raw(&self) -> &A::Device {
|
||||
self.raw.as_ref().unwrap()
|
||||
&self.raw
|
||||
}
|
||||
pub(crate) fn require_features(&self, feature: wgt::Features) -> Result<(), MissingFeatures> {
|
||||
if self.features.contains(feature) {
|
||||
@ -271,7 +272,7 @@ impl<A: HalApi> Device<A> {
|
||||
let downlevel = adapter.raw.capabilities.downlevel.clone();
|
||||
|
||||
Ok(Self {
|
||||
raw: Some(raw_device),
|
||||
raw: ManuallyDrop::new(raw_device),
|
||||
adapter: adapter.clone(),
|
||||
queue: OnceCell::new(),
|
||||
queue_to_drop: OnceCell::new(),
|
||||
@ -1418,7 +1419,7 @@ impl<A: HalApi> Device<A> {
|
||||
};
|
||||
|
||||
let sampler = Sampler {
|
||||
raw: Some(raw),
|
||||
raw: ManuallyDrop::new(raw),
|
||||
device: self.clone(),
|
||||
label: desc.label.to_string(),
|
||||
tracking_data: TrackingData::new(self.tracker_indices.samplers.clone()),
|
||||
@ -1550,7 +1551,7 @@ impl<A: HalApi> Device<A> {
|
||||
};
|
||||
|
||||
let module = pipeline::ShaderModule {
|
||||
raw: Some(raw),
|
||||
raw: ManuallyDrop::new(raw),
|
||||
device: self.clone(),
|
||||
interface: Some(interface),
|
||||
label: desc.label.to_string(),
|
||||
@ -1591,7 +1592,7 @@ impl<A: HalApi> Device<A> {
|
||||
};
|
||||
|
||||
let module = pipeline::ShaderModule {
|
||||
raw: Some(raw),
|
||||
raw: ManuallyDrop::new(raw),
|
||||
device: self.clone(),
|
||||
interface: None,
|
||||
label: desc.label.to_string(),
|
||||
@ -1861,7 +1862,7 @@ impl<A: HalApi> Device<A> {
|
||||
.map_err(binding_model::CreateBindGroupLayoutError::TooManyBindings)?;
|
||||
|
||||
let bgl = BindGroupLayout {
|
||||
raw: Some(raw),
|
||||
raw: ManuallyDrop::new(raw),
|
||||
device: self.clone(),
|
||||
entries: entry_map,
|
||||
origin,
|
||||
@ -2576,7 +2577,7 @@ impl<A: HalApi> Device<A> {
|
||||
drop(raw_bind_group_layouts);
|
||||
|
||||
let layout = binding_model::PipelineLayout {
|
||||
raw: Some(raw),
|
||||
raw: ManuallyDrop::new(raw),
|
||||
device: self.clone(),
|
||||
label: desc.label.to_string(),
|
||||
bind_group_layouts,
|
||||
@ -2718,7 +2719,7 @@ impl<A: HalApi> Device<A> {
|
||||
constants: desc.stage.constants.as_ref(),
|
||||
zero_initialize_workgroup_memory: desc.stage.zero_initialize_workgroup_memory,
|
||||
},
|
||||
cache: cache.as_ref().and_then(|it| it.raw.as_ref()),
|
||||
cache: cache.as_ref().map(|it| it.raw()),
|
||||
};
|
||||
|
||||
let raw =
|
||||
@ -2742,7 +2743,7 @@ impl<A: HalApi> Device<A> {
|
||||
)?;
|
||||
|
||||
let pipeline = pipeline::ComputePipeline {
|
||||
raw: Some(raw),
|
||||
raw: ManuallyDrop::new(raw),
|
||||
layout: pipeline_layout,
|
||||
device: self.clone(),
|
||||
_shader_module: shader_module,
|
||||
@ -3299,7 +3300,7 @@ impl<A: HalApi> Device<A> {
|
||||
fragment_stage,
|
||||
color_targets,
|
||||
multiview: desc.multiview,
|
||||
cache: cache.as_ref().and_then(|it| it.raw.as_ref()),
|
||||
cache: cache.as_ref().map(|it| it.raw()),
|
||||
};
|
||||
let raw =
|
||||
unsafe { self.raw().create_render_pipeline(&pipeline_desc) }.map_err(
|
||||
@ -3363,7 +3364,7 @@ impl<A: HalApi> Device<A> {
|
||||
};
|
||||
|
||||
let pipeline = pipeline::RenderPipeline {
|
||||
raw: Some(raw),
|
||||
raw: ManuallyDrop::new(raw),
|
||||
layout: pipeline_layout,
|
||||
device: self.clone(),
|
||||
pass_context,
|
||||
@ -3434,7 +3435,7 @@ impl<A: HalApi> Device<A> {
|
||||
device: self.clone(),
|
||||
label: desc.label.to_string(),
|
||||
// This would be none in the error condition, which we don't implement yet
|
||||
raw: Some(raw),
|
||||
raw: ManuallyDrop::new(raw),
|
||||
};
|
||||
|
||||
let cache = Arc::new(cache);
|
||||
@ -3535,8 +3536,10 @@ impl<A: HalApi> Device<A> {
|
||||
|
||||
let hal_desc = desc.map_label(|label| label.to_hal(self.instance_flags));
|
||||
|
||||
let raw = unsafe { self.raw().create_query_set(&hal_desc).unwrap() };
|
||||
|
||||
let query_set = QuerySet {
|
||||
raw: Some(unsafe { self.raw().create_query_set(&hal_desc).unwrap() }),
|
||||
raw: ManuallyDrop::new(raw),
|
||||
device: self.clone(),
|
||||
label: desc.label.to_string(),
|
||||
tracking_data: TrackingData::new(self.tracker_indices.query_sets.clone()),
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
};
|
||||
use arrayvec::ArrayVec;
|
||||
use naga::error::ShaderError;
|
||||
use std::{borrow::Cow, marker::PhantomData, num::NonZeroU32, sync::Arc};
|
||||
use std::{borrow::Cow, marker::PhantomData, mem::ManuallyDrop, num::NonZeroU32, sync::Arc};
|
||||
use thiserror::Error;
|
||||
|
||||
/// Information about buffer bindings, which
|
||||
@ -47,7 +47,7 @@ pub struct ShaderModuleDescriptor<'a> {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ShaderModule<A: HalApi> {
|
||||
pub(crate) raw: Option<A::ShaderModule>,
|
||||
pub(crate) raw: ManuallyDrop<A::ShaderModule>,
|
||||
pub(crate) device: Arc<Device<A>>,
|
||||
pub(crate) interface: Option<validation::Interface>,
|
||||
/// The `label` from the descriptor used to create the resource.
|
||||
@ -56,12 +56,12 @@ pub struct ShaderModule<A: HalApi> {
|
||||
|
||||
impl<A: HalApi> Drop for ShaderModule<A> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(raw) = self.raw.take() {
|
||||
resource_log!("Destroy raw {}", self.error_ident());
|
||||
unsafe {
|
||||
use hal::Device;
|
||||
self.device.raw().destroy_shader_module(raw);
|
||||
}
|
||||
resource_log!("Destroy raw {}", self.error_ident());
|
||||
// SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
|
||||
let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
|
||||
unsafe {
|
||||
use hal::Device;
|
||||
self.device.raw().destroy_shader_module(raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -73,7 +73,7 @@ crate::impl_storage_item!(ShaderModule);
|
||||
|
||||
impl<A: HalApi> ShaderModule<A> {
|
||||
pub(crate) fn raw(&self) -> &A::ShaderModule {
|
||||
self.raw.as_ref().unwrap()
|
||||
&self.raw
|
||||
}
|
||||
|
||||
pub(crate) fn finalize_entry_point_name(
|
||||
@ -242,7 +242,7 @@ pub enum CreateComputePipelineError {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ComputePipeline<A: HalApi> {
|
||||
pub(crate) raw: Option<A::ComputePipeline>,
|
||||
pub(crate) raw: ManuallyDrop<A::ComputePipeline>,
|
||||
pub(crate) layout: Arc<PipelineLayout<A>>,
|
||||
pub(crate) device: Arc<Device<A>>,
|
||||
pub(crate) _shader_module: Arc<ShaderModule<A>>,
|
||||
@ -254,12 +254,12 @@ pub struct ComputePipeline<A: HalApi> {
|
||||
|
||||
impl<A: HalApi> Drop for ComputePipeline<A> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(raw) = self.raw.take() {
|
||||
resource_log!("Destroy raw {}", self.error_ident());
|
||||
unsafe {
|
||||
use hal::Device;
|
||||
self.device.raw().destroy_compute_pipeline(raw);
|
||||
}
|
||||
resource_log!("Destroy raw {}", self.error_ident());
|
||||
// SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
|
||||
let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
|
||||
unsafe {
|
||||
use hal::Device;
|
||||
self.device.raw().destroy_compute_pipeline(raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -272,7 +272,7 @@ crate::impl_trackable!(ComputePipeline);
|
||||
|
||||
impl<A: HalApi> ComputePipeline<A> {
|
||||
pub(crate) fn raw(&self) -> &A::ComputePipeline {
|
||||
self.raw.as_ref().unwrap()
|
||||
&self.raw
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,7 +301,7 @@ impl From<hal::PipelineCacheError> for CreatePipelineCacheError {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PipelineCache<A: HalApi> {
|
||||
pub(crate) raw: Option<A::PipelineCache>,
|
||||
pub(crate) raw: ManuallyDrop<A::PipelineCache>,
|
||||
pub(crate) device: Arc<Device<A>>,
|
||||
/// The `label` from the descriptor used to create the resource.
|
||||
pub(crate) label: String,
|
||||
@ -309,12 +309,12 @@ pub struct PipelineCache<A: HalApi> {
|
||||
|
||||
impl<A: HalApi> Drop for PipelineCache<A> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(raw) = self.raw.take() {
|
||||
resource_log!("Destroy raw {}", self.error_ident());
|
||||
unsafe {
|
||||
use hal::Device;
|
||||
self.device.raw().destroy_pipeline_cache(raw);
|
||||
}
|
||||
resource_log!("Destroy raw {}", self.error_ident());
|
||||
// SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
|
||||
let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
|
||||
unsafe {
|
||||
use hal::Device;
|
||||
self.device.raw().destroy_pipeline_cache(raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -324,6 +324,12 @@ crate::impl_labeled!(PipelineCache);
|
||||
crate::impl_parent_device!(PipelineCache);
|
||||
crate::impl_storage_item!(PipelineCache);
|
||||
|
||||
impl<A: HalApi> PipelineCache<A> {
|
||||
pub(crate) fn raw(&self) -> &A::PipelineCache {
|
||||
&self.raw
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes how the vertex buffer is interpreted.
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
@ -586,7 +592,7 @@ impl Default for VertexStep {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RenderPipeline<A: HalApi> {
|
||||
pub(crate) raw: Option<A::RenderPipeline>,
|
||||
pub(crate) raw: ManuallyDrop<A::RenderPipeline>,
|
||||
pub(crate) device: Arc<Device<A>>,
|
||||
pub(crate) layout: Arc<PipelineLayout<A>>,
|
||||
pub(crate) _shader_modules:
|
||||
@ -603,12 +609,12 @@ pub struct RenderPipeline<A: HalApi> {
|
||||
|
||||
impl<A: HalApi> Drop for RenderPipeline<A> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(raw) = self.raw.take() {
|
||||
resource_log!("Destroy raw {}", self.error_ident());
|
||||
unsafe {
|
||||
use hal::Device;
|
||||
self.device.raw().destroy_render_pipeline(raw);
|
||||
}
|
||||
resource_log!("Destroy raw {}", self.error_ident());
|
||||
// SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
|
||||
let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
|
||||
unsafe {
|
||||
use hal::Device;
|
||||
self.device.raw().destroy_render_pipeline(raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -621,6 +627,6 @@ crate::impl_trackable!(RenderPipeline);
|
||||
|
||||
impl<A: HalApi> RenderPipeline<A> {
|
||||
pub(crate) fn raw(&self) -> &A::RenderPipeline {
|
||||
self.raw.as_ref().unwrap()
|
||||
&self.raw
|
||||
}
|
||||
}
|
||||
|
@ -1697,7 +1697,7 @@ pub struct SamplerDescriptor<'a> {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Sampler<A: HalApi> {
|
||||
pub(crate) raw: Option<A::Sampler>,
|
||||
pub(crate) raw: ManuallyDrop<A::Sampler>,
|
||||
pub(crate) device: Arc<Device<A>>,
|
||||
/// The `label` from the descriptor used to create the resource.
|
||||
pub(crate) label: String,
|
||||
@ -1710,19 +1710,19 @@ pub struct Sampler<A: HalApi> {
|
||||
|
||||
impl<A: HalApi> Drop for Sampler<A> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(raw) = self.raw.take() {
|
||||
resource_log!("Destroy raw {}", self.error_ident());
|
||||
unsafe {
|
||||
use hal::Device;
|
||||
self.device.raw().destroy_sampler(raw);
|
||||
}
|
||||
resource_log!("Destroy raw {}", self.error_ident());
|
||||
// SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
|
||||
let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
|
||||
unsafe {
|
||||
use hal::Device;
|
||||
self.device.raw().destroy_sampler(raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: HalApi> Sampler<A> {
|
||||
pub(crate) fn raw(&self) -> &A::Sampler {
|
||||
self.raw.as_ref().unwrap()
|
||||
&self.raw
|
||||
}
|
||||
}
|
||||
|
||||
@ -1793,7 +1793,7 @@ pub type QuerySetDescriptor<'a> = wgt::QuerySetDescriptor<Label<'a>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct QuerySet<A: HalApi> {
|
||||
pub(crate) raw: Option<A::QuerySet>,
|
||||
pub(crate) raw: ManuallyDrop<A::QuerySet>,
|
||||
pub(crate) device: Arc<Device<A>>,
|
||||
/// The `label` from the descriptor used to create the resource.
|
||||
pub(crate) label: String,
|
||||
@ -1803,12 +1803,12 @@ pub struct QuerySet<A: HalApi> {
|
||||
|
||||
impl<A: HalApi> Drop for QuerySet<A> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(raw) = self.raw.take() {
|
||||
resource_log!("Destroy raw {}", self.error_ident());
|
||||
unsafe {
|
||||
use hal::Device;
|
||||
self.device.raw().destroy_query_set(raw);
|
||||
}
|
||||
resource_log!("Destroy raw {}", self.error_ident());
|
||||
// SAFETY: We are in the Drop impl and we don't use self.raw anymore after this point.
|
||||
let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
|
||||
unsafe {
|
||||
use hal::Device;
|
||||
self.device.raw().destroy_query_set(raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1821,7 +1821,7 @@ crate::impl_trackable!(QuerySet);
|
||||
|
||||
impl<A: HalApi> QuerySet<A> {
|
||||
pub(crate) fn raw(&self) -> &A::QuerySet {
|
||||
self.raw.as_ref().unwrap()
|
||||
&self.raw
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user