1use std::{collections::HashSet, fmt, sync::Arc};
2
3use nwnrs_lru::prelude::*;
4use nwnrs_resref::prelude::*;
5use tracing::instrument;
6
7use crate::prelude::*;
8
9pub struct ResMan {
15 containers: Vec<Arc<dyn ResContainer>>,
16 cache: Option<WeightedLru<ResRef, Res>>,
17}
18
19impl fmt::Debug for ResMan {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 f.debug_struct("ResMan")
22 .field("container_count", &self.containers.len())
23 .field("has_cache", &self.cache.is_some())
24 .finish()
25 }
26}
27
28impl ResMan {
29 #[must_use]
35 pub fn new(cache_size_mb: usize) -> Self {
36 Self {
37 containers: Vec::new(),
38 cache: (cache_size_mb > 0)
39 .then(|| WeightedLru::new(cache_size_mb * 1024 * 1024, 1)),
40 }
41 }
42
43 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("contains",
"nwnrs_resman::manager", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("src/manager.rs"),
::tracing_core::__macro_support::Option::Some(47u32),
::tracing_core::__macro_support::Option::Some("nwnrs_resman::manager"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("resref")
}> =
::tracing::__macro_support::FieldName::new("resref");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("cache_policy")
}> =
::tracing::__macro_support::FieldName::new("cache_policy");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::display(&rr)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&cache_policy)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: bool = loop {};
return __tracing_attr_fake_return;
}
{
if cache_policy.uses_cache() &&
self.cache.as_mut().is_some_and(|cache|
cache.contains_key(rr)) {
return true;
}
self.containers.iter().any(|container| container.contains(rr))
}
}
}#[instrument(level = "debug", skip_all, fields(resref = %rr, cache_policy = ?cache_policy))]
48 pub fn contains(&mut self, rr: &ResRef, cache_policy: CachePolicy) -> bool {
49 if cache_policy.uses_cache()
50 && self
51 .cache
52 .as_mut()
53 .is_some_and(|cache| cache.contains_key(rr))
54 {
55 return true;
56 }
57
58 self.containers
59 .iter()
60 .any(|container| container.contains(rr))
61 }
62
63 #[allow(clippy :: redundant_closure_call)]
match (move ||
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy
:: needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: ResManResult<Res> = loop {};
return __tracing_attr_fake_return;
}
{
if cache_policy.uses_cache() &&
let Some(cached) =
self.cache.as_mut().and_then(|cache| cache.get(rr).cloned())
{
return Ok(cached);
}
for container in &self.containers {
if container.contains(rr) {
let result = container.demand(rr)?;
if cache_policy.uses_cache() &&
let Some(cache) = self.cache.as_mut() {
let weight =
usize::try_from(result.io_size().max(1)).unwrap_or(usize::MAX);
cache.insert_weighted(rr.clone(), weight, result.clone());
}
return Ok(result);
}
}
Err(ResManError::msg(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("not found: {0}", rr))
})))
}
})()
{
#[allow(clippy :: unit_arg)]
Ok(x) => Ok(x),
Err(e) => {
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event src/manager.rs:72",
"nwnrs_resman::manager", ::tracing::Level::ERROR,
::tracing_core::__macro_support::Option::Some("src/manager.rs"),
::tracing_core::__macro_support::Option::Some(72u32),
::tracing_core::__macro_support::Option::Some("nwnrs_resman::manager"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("error")
}> =
::tracing::__macro_support::FieldName::new("error");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::ERROR <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::ERROR <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::display(&e)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
Err(e)
}
}#[instrument(level = "debug", skip_all, err, fields(resref = %rr, cache_policy = ?cache_policy))]
73 pub fn demand(&mut self, rr: &ResRef, cache_policy: CachePolicy) -> ResManResult<Res> {
74 if cache_policy.uses_cache()
75 && let Some(cached) = self.cache.as_mut().and_then(|cache| cache.get(rr).cloned())
76 {
77 return Ok(cached);
78 }
79
80 for container in &self.containers {
81 if container.contains(rr) {
82 let result = container.demand(rr)?;
83 if cache_policy.uses_cache()
84 && let Some(cache) = self.cache.as_mut()
85 {
86 let weight = usize::try_from(result.io_size().max(1)).unwrap_or(usize::MAX);
87 cache.insert_weighted(rr.clone(), weight, result.clone());
88 }
89 return Ok(result);
90 }
91 }
92
93 Err(ResManError::msg(format!("not found: {rr}")))
94 }
95
96 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("contents",
"nwnrs_resman::manager", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("src/manager.rs"),
::tracing_core::__macro_support::Option::Some(97u32),
::tracing_core::__macro_support::Option::Some("nwnrs_resman::manager"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("self")
}> =
::tracing::__macro_support::FieldName::new("self");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("container_count")
}> =
::tracing::__macro_support::FieldName::new("container_count");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&self.containers.len()
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: HashSet<ResRef> = loop {};
return __tracing_attr_fake_return;
}
{
let mut result = HashSet::new();
for container in &self.containers {
result.extend(container.contents());
}
result
}
}
}#[instrument(level = "debug", fields(container_count = self.containers.len()))]
98 pub fn contents(&self) -> HashSet<ResRef> {
99 let mut result = HashSet::new();
100 for container in &self.containers {
101 result.extend(container.contents());
102 }
103 result
104 }
105
106 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("get_resolved",
"nwnrs_resman::manager", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("src/manager.rs"),
::tracing_core::__macro_support::Option::Some(107u32),
::tracing_core::__macro_support::Option::Some("nwnrs_resman::manager"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("resref")
}> =
::tracing::__macro_support::FieldName::new("resref");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::display(&rr)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: Option<Res> = loop {};
return __tracing_attr_fake_return;
}
{
let base = rr.base().clone();
self.contains(&base,
CachePolicy::Use).then(||
self.demand(&base, CachePolicy::Use).ok()).flatten()
}
}
}#[instrument(level = "debug", skip_all, fields(resref = %rr))]
108 pub fn get_resolved(&mut self, rr: &ResolvedResRef) -> Option<Res> {
109 let base = rr.base().clone();
110 self.contains(&base, CachePolicy::Use)
111 .then(|| self.demand(&base, CachePolicy::Use).ok())
112 .flatten()
113 }
114
115 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("get",
"nwnrs_resman::manager", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("src/manager.rs"),
::tracing_core::__macro_support::Option::Some(116u32),
::tracing_core::__macro_support::Option::Some("nwnrs_resman::manager"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("resref")
}> =
::tracing::__macro_support::FieldName::new("resref");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::display(&rr)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: Option<Res> = loop {};
return __tracing_attr_fake_return;
}
{
self.contains(rr,
CachePolicy::Use).then(||
self.demand(rr, CachePolicy::Use).ok()).flatten()
}
}
}#[instrument(level = "debug", skip_all, fields(resref = %rr))]
117 pub fn get(&mut self, rr: &ResRef) -> Option<Res> {
118 self.contains(rr, CachePolicy::Use)
119 .then(|| self.demand(rr, CachePolicy::Use).ok())
120 .flatten()
121 }
122
123 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("add",
"nwnrs_resman::manager", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("src/manager.rs"),
::tracing_core::__macro_support::Option::Some(126u32),
::tracing_core::__macro_support::Option::Some("nwnrs_resman::manager"),
::tracing_core::field::FieldSet::new(&[],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{ meta.fields().value_set_all(&[]) })
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{ self.containers.insert(0, container); }
}
}#[instrument(level = "debug", skip_all)]
127 pub fn add(&mut self, container: Arc<dyn ResContainer>) {
128 self.containers.insert(0, container);
129 }
130
131 #[must_use]
133 pub fn containers(&self) -> &[Arc<dyn ResContainer>] {
134 &self.containers
135 }
136
137 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("remove",
"nwnrs_resman::manager", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("src/manager.rs"),
::tracing_core::__macro_support::Option::Some(138u32),
::tracing_core::__macro_support::Option::Some("nwnrs_resman::manager"),
::tracing_core::field::FieldSet::new(&[],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{ meta.fields().value_set_all(&[]) })
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: bool = loop {};
return __tracing_attr_fake_return;
}
{
if let Some(index) =
self.containers.iter().position(|candidate|
Arc::ptr_eq(candidate, container)) {
self.containers.remove(index);
true
} else { false }
}
}
}#[instrument(level = "debug", skip_all)]
139 pub fn remove(&mut self, container: &Arc<dyn ResContainer>) -> bool {
140 if let Some(index) = self
141 .containers
142 .iter()
143 .position(|candidate| Arc::ptr_eq(candidate, container))
144 {
145 self.containers.remove(index);
146 true
147 } else {
148 false
149 }
150 }
151
152 #[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("remove_at",
"nwnrs_resman::manager", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("src/manager.rs"),
::tracing_core::__macro_support::Option::Some(153u32),
::tracing_core::__macro_support::Option::Some("nwnrs_resman::manager"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("self")
}> =
::tracing::__macro_support::FieldName::new("self");
NAME.as_str()
},
{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("index")
}> =
::tracing::__macro_support::FieldName::new("index");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self)
as &dyn ::tracing::field::Value)),
(::tracing::__macro_support::Option::Some(&::tracing::field::Empty
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: Option<Arc<dyn ResContainer>> =
loop {};
return __tracing_attr_fake_return;
}
{
(index <
self.containers.len()).then(||
self.containers.remove(index))
}
}
}#[instrument(level = "debug", fields(index))]
154 pub fn remove_at(&mut self, index: usize) -> Option<Arc<dyn ResContainer>> {
155 (index < self.containers.len()).then(|| self.containers.remove(index))
156 }
157
158 pub fn cache(&mut self) -> Option<&mut WeightedLru<ResRef, Res>> {
160 self.cache.as_mut()
161 }
162}
163
164#[allow(clippy::panic)]
165#[cfg(test)]
166mod tests {
167 use std::{collections::HashMap, io::Cursor, sync::Arc, time::SystemTime};
168
169 use nwnrs_checksums::EMPTY_SECURE_HASH;
170 use nwnrs_exo::ExoResFileCompressionType;
171 use nwnrs_resref::{ResRef, ResolvedResRef};
172 use nwnrs_restype::ResType;
173
174 use crate::{
175 CachePolicy, Res, ResContainer, ResMan, ResManError, ResManResult, new_res_origin,
176 shared_stream,
177 };
178
179 #[derive(Clone)]
180 struct TestContainer {
181 label: &'static str,
182 entries: HashMap<nwnrs_resref::ResRef, Res>,
183 }
184
185 impl std::fmt::Display for TestContainer {
186 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187 f.write_str(self.label)
188 }
189 }
190
191 impl ResContainer for TestContainer {
192 fn contains(&self, rr: &nwnrs_resref::ResRef) -> bool {
193 self.entries.contains_key(rr)
194 }
195
196 fn demand(&self, rr: &nwnrs_resref::ResRef) -> ResManResult<Res> {
197 self.entries
198 .get(rr)
199 .cloned()
200 .ok_or_else(|| ResManError::msg(format!("not found: {rr}")))
201 }
202
203 fn count(&self) -> usize {
204 self.entries.len()
205 }
206
207 fn contents(&self) -> Vec<nwnrs_resref::ResRef> {
208 self.entries.keys().cloned().collect()
209 }
210 }
211
212 fn make_res(name: &str, ty: u16, bytes: &[u8], label: &str) -> Res {
213 let rr = ResRef::new(name, ResType(ty)).unwrap_or_else(|error| {
214 panic!("make rr: {error}");
215 });
216 Res::new_with_stream(
217 new_res_origin("TestContainer", label),
218 rr,
219 SystemTime::UNIX_EPOCH,
220 shared_stream(Cursor::new(bytes.to_vec())),
221 bytes.len() as i64,
222 0,
223 ExoResFileCompressionType::None,
224 None,
225 bytes.len(),
226 EMPTY_SECURE_HASH,
227 )
228 }
229
230 #[test]
231 fn resolves_latest_container_first_and_unions_contents() {
232 let shared = ResRef::new("shared", ResType(2027)).unwrap_or_else(|error| {
233 panic!("shared rr: {error}");
234 });
235 let older = TestContainer {
236 label: "older",
237 entries: HashMap::from([
238 (shared.clone(), make_res("shared", 2027, b"older", "older")),
239 (
240 ResRef::new("only_old", ResType(2027)).unwrap_or_else(|error| {
241 panic!("only_old rr: {error}");
242 }),
243 make_res("only_old", 2027, b"old", "older"),
244 ),
245 ]),
246 };
247 let newer = TestContainer {
248 label: "newer",
249 entries: HashMap::from([(shared.clone(), make_res("shared", 2027, b"newer", "newer"))]),
250 };
251
252 let mut manager = ResMan::new(1);
253 manager.add(Arc::new(older));
254 manager.add(Arc::new(newer));
255
256 let res = match manager.demand(&shared, CachePolicy::Bypass) {
257 Ok(value) => value,
258 Err(error) => panic!("demand shared: {error}"),
259 };
260 let bytes = match res.read_all(CachePolicy::Bypass) {
261 Ok(value) => value,
262 Err(error) => panic!("read shared bytes: {error}"),
263 };
264 assert_eq!(bytes, b"newer".to_vec());
265 assert_eq!(manager.contents().len(), 2);
266 }
267
268 #[test]
269 fn resolves_fully_specified_references() {
270 let rr = ResRef::new("alpha", ResType(2027)).unwrap_or_else(|error| {
271 panic!("alpha rr: {error}");
272 });
273 let container = TestContainer {
274 label: "single",
275 entries: HashMap::from([(rr.clone(), make_res("alpha", 2027, b"alpha", "single"))]),
276 };
277 let mut manager = ResMan::new(1);
278 manager.add(Arc::new(container));
279
280 let resolved = ResolvedResRef::from_filename("alpha.utc").unwrap_or_else(|error| {
281 panic!("resolved rr: {error}");
282 });
283 assert!(manager.get_resolved(&resolved).is_some());
284 }
285}