@@ -1987,6 +1987,301 @@ mod tests {
19871987 } ) ;
19881988 }
19891989
1990+ #[ test]
1991+ fn error_on_immediate_load_of_self_dependency ( ) {
1992+ let ( mut app, dir, _source_events) = create_app_with_source_event_sender ( ) ;
1993+ let asset_server = app. world ( ) . resource :: < AssetServer > ( ) . clone ( ) ;
1994+
1995+ dir. insert_asset_text ( Path :: new ( "abc.cool.ron" ) , "" ) ;
1996+
1997+ struct ImmediateSelfLoader ;
1998+
1999+ impl AssetLoader for ImmediateSelfLoader {
2000+ type Asset = TestAsset ;
2001+ type Error = crate :: loader:: LoadDirectError ;
2002+ type Settings = ( ) ;
2003+
2004+ async fn load (
2005+ & self ,
2006+ _: & mut dyn Reader ,
2007+ _: & Self :: Settings ,
2008+ load_context : & mut LoadContext < ' _ > ,
2009+ ) -> Result < Self :: Asset , Self :: Error > {
2010+ let asset_path = load_context. asset_path ( ) . clone ( ) ;
2011+ let loaded_asset = load_context. loader ( )
2012+ . immediate ( )
2013+ . load :: < TestAsset > ( asset_path)
2014+ . await ?;
2015+ load_context. add_loaded_labeled_asset ( "myself" . to_string ( ) , loaded_asset) ;
2016+ Ok ( TestAsset )
2017+ }
2018+
2019+ fn extensions ( & self ) -> & [ & str ] {
2020+ & [ "ron" ]
2021+ }
2022+ }
2023+
2024+ app. init_asset :: < TestAsset > ( )
2025+ . register_asset_loader ( ImmediateSelfLoader ) ;
2026+
2027+ let handle: Handle < TestAsset > = asset_server. load ( "abc.cool.ron" ) ;
2028+
2029+ run_app_until ( & mut app, |_world| match asset_server. load_state ( & handle) {
2030+ LoadState :: Loading => None ,
2031+ LoadState :: Failed ( err) => {
2032+ assert ! ( format!( "{:?}" , & err) . contains( "AssetDependentOnSelf" ) , "Error did not contain AssetDependentOnSelf: {:?}" , & err) ;
2033+ Some ( ( ) )
2034+ }
2035+ state => panic ! ( "Unexpected asset state: {state:?}" ) ,
2036+ } ) ;
2037+ }
2038+
2039+ #[ test]
2040+ fn error_on_unknown_type_immediate_load_of_self_dependency ( ) {
2041+ let ( mut app, dir, _source_events) = create_app_with_source_event_sender ( ) ;
2042+ let asset_server = app. world ( ) . resource :: < AssetServer > ( ) . clone ( ) ;
2043+
2044+ dir. insert_asset_text ( Path :: new ( "abc.cool.ron" ) , "" ) ;
2045+
2046+ struct ImmediateSelfLoader ;
2047+
2048+ impl AssetLoader for ImmediateSelfLoader {
2049+ type Asset = TestAsset ;
2050+ type Error = crate :: loader:: LoadDirectError ;
2051+ type Settings = ( ) ;
2052+
2053+ async fn load (
2054+ & self ,
2055+ _: & mut dyn Reader ,
2056+ _: & Self :: Settings ,
2057+ load_context : & mut LoadContext < ' _ > ,
2058+ ) -> Result < Self :: Asset , Self :: Error > {
2059+ let asset_path = load_context. asset_path ( ) . clone ( ) ;
2060+ let loaded_asset = load_context. loader ( )
2061+ . immediate ( )
2062+ . with_unknown_type ( )
2063+ . load ( asset_path)
2064+ . await ?;
2065+ let loaded_asset = match loaded_asset. downcast :: < TestAsset > ( ) {
2066+ Ok ( a) => a,
2067+ Err ( _) => panic ! ( "Could not downcast to `TestAsset`" ) ,
2068+ } ;
2069+ load_context. add_loaded_labeled_asset ( "myself" . to_string ( ) , loaded_asset) ;
2070+ Ok ( TestAsset )
2071+ }
2072+
2073+ fn extensions ( & self ) -> & [ & str ] {
2074+ & [ "ron" ]
2075+ }
2076+ }
2077+
2078+ app. init_asset :: < TestAsset > ( )
2079+ . register_asset_loader ( ImmediateSelfLoader ) ;
2080+
2081+ let handle: Handle < TestAsset > = asset_server. load ( "abc.cool.ron" ) ;
2082+
2083+ run_app_until ( & mut app, |_world| match asset_server. load_state ( & handle) {
2084+ LoadState :: Loading => None ,
2085+ LoadState :: Failed ( err) => {
2086+ assert ! ( format!( "{:?}" , & err) . contains( "AssetDependentOnSelf" ) , "Error did not contain AssetDependentOnSelf: {:?}" , & err) ;
2087+ Some ( ( ) )
2088+ }
2089+ state => panic ! ( "Unexpected asset state: {state:?}" ) ,
2090+ } ) ;
2091+ }
2092+
2093+ /// This is not a statement of intent but one of behavior: One may load
2094+ /// their own path deferred without error. It has the correct handle to
2095+ /// itself. And it can reload.
2096+ ///
2097+ /// I would have wanted this to produce an error. Instead it produces a
2098+ /// warning.
2099+ #[ test]
2100+ fn no_error_on_deferred_load_of_self_dependency ( ) {
2101+ let ( mut app, dir, source_events) = create_app_with_source_event_sender ( ) ;
2102+ let asset_server = app. world ( ) . resource :: < AssetServer > ( ) . clone ( ) ;
2103+
2104+ dir. insert_asset_text ( Path :: new ( "abc.cool.ron" ) , "" ) ;
2105+
2106+ #[ derive( Asset , TypePath ) ]
2107+ pub struct TestAsset ( Handle < TestAsset > ) ;
2108+ struct DeferredSelfLoader ;
2109+
2110+ impl AssetLoader for DeferredSelfLoader {
2111+ type Asset = TestAsset ;
2112+ type Error = crate :: loader:: LoadDirectError ;
2113+ type Settings = ( ) ;
2114+
2115+ async fn load (
2116+ & self ,
2117+ _: & mut dyn Reader ,
2118+ _: & Self :: Settings ,
2119+ load_context : & mut LoadContext < ' _ > ,
2120+ ) -> Result < Self :: Asset , Self :: Error > {
2121+ let asset_path = load_context. asset_path ( ) . clone ( ) ;
2122+ let loaded_asset = load_context. load :: < TestAsset > ( asset_path) ;
2123+ Ok ( TestAsset ( loaded_asset) )
2124+ }
2125+
2126+ fn extensions ( & self ) -> & [ & str ] {
2127+ & [ "ron" ]
2128+ }
2129+ }
2130+
2131+ app. init_asset :: < TestAsset > ( )
2132+ . register_asset_loader ( DeferredSelfLoader ) ;
2133+
2134+ let handle: Handle < TestAsset > = asset_server. load ( "abc.cool.ron" ) ;
2135+
2136+ run_app_until ( & mut app, |world| match asset_server. load_state ( & handle) {
2137+ LoadState :: Loading => None ,
2138+ LoadState :: Loaded => {
2139+ let test_assets = world. resource :: < Assets < TestAsset > > ( ) ;
2140+ let asset = test_assets. get ( & handle) . unwrap ( ) ;
2141+ assert_eq ! ( handle, asset. 0 ) ;
2142+ Some ( ( ) )
2143+ }
2144+ state => panic ! ( "Unexpected asset state: {state:?}" ) ,
2145+ } ) ;
2146+
2147+ run_app_until ( & mut app, |world| {
2148+ let messages = collect_asset_events ( world) ;
2149+ if messages. is_empty ( ) {
2150+ return None ;
2151+ }
2152+ assert_eq ! (
2153+ messages,
2154+ [
2155+ AssetEvent :: LoadedWithDependencies { id: handle. id( ) } ,
2156+ AssetEvent :: Added { id: handle. id( ) }
2157+ ]
2158+ ) ;
2159+ Some ( ( ) )
2160+ } ) ;
2161+
2162+ // Sending an asset event should result in the asset being reloaded - resulting in a
2163+ // "Modified" message.
2164+ source_events
2165+ . send ( AssetSourceEvent :: ModifiedAsset ( PathBuf :: from (
2166+ "abc.cool.ron" ,
2167+ ) ) )
2168+ . unwrap ( ) ;
2169+
2170+ run_app_until ( & mut app, |world| {
2171+ let messages = collect_asset_events ( world) ;
2172+ if messages. is_empty ( ) {
2173+ return None ;
2174+ }
2175+ assert_eq ! (
2176+ messages,
2177+ [
2178+ AssetEvent :: LoadedWithDependencies { id: handle. id( ) } ,
2179+ AssetEvent :: Modified { id: handle. id( ) }
2180+ ]
2181+ ) ;
2182+ Some ( ( ) )
2183+ } ) ;
2184+ }
2185+
2186+ /// This is not a statement of intent but one of behavior: One may load
2187+ /// their own path deferred of unknown type without error. It has the
2188+ /// correct handle to itself. And it can reload.
2189+ ///
2190+ /// I would have wanted this to produce an error. Instead it produces a
2191+ /// warning.
2192+ #[ test]
2193+ fn no_error_on_unknown_type_deferred_load_of_self_dependency ( ) {
2194+ let ( mut app, dir, source_events) = create_app_with_source_event_sender ( ) ;
2195+ let asset_server = app. world ( ) . resource :: < AssetServer > ( ) . clone ( ) ;
2196+
2197+ dir. insert_asset_text ( Path :: new ( "abc.cool.ron" ) , "" ) ;
2198+
2199+ #[ derive( Asset , TypePath ) ]
2200+ pub struct TestAssetUD ( UntypedHandle ) ;
2201+ struct ImmediateSelfLoader ;
2202+
2203+ impl AssetLoader for ImmediateSelfLoader {
2204+ type Asset = TestAssetUD ;
2205+ type Error = crate :: loader:: LoadDirectError ;
2206+ type Settings = ( ) ;
2207+
2208+ async fn load (
2209+ & self ,
2210+ _: & mut dyn Reader ,
2211+ _: & Self :: Settings ,
2212+ load_context : & mut LoadContext < ' _ > ,
2213+ ) -> Result < Self :: Asset , Self :: Error > {
2214+ let asset_path = load_context. asset_path ( ) . clone ( ) ;
2215+ let untyped_handle: UntypedHandle = load_context
2216+ . loader ( )
2217+ . with_unknown_type ( )
2218+ . load ( asset_path) . into ( ) ;
2219+
2220+ Ok ( TestAssetUD ( untyped_handle) )
2221+ }
2222+
2223+ fn extensions ( & self ) -> & [ & str ] {
2224+ & [ "ron" ]
2225+ }
2226+ }
2227+
2228+ app. init_asset :: < TestAssetUD > ( )
2229+ . register_asset_loader ( ImmediateSelfLoader ) ;
2230+
2231+ let handle: Handle < TestAssetUD > = asset_server. load ( "abc.cool.ron" ) ;
2232+
2233+ run_app_until ( & mut app, |world| match asset_server. load_state ( & handle) {
2234+ LoadState :: Loading => None ,
2235+ LoadState :: Loaded => {
2236+ let test_assets = world. resource :: < Assets < TestAssetUD > > ( ) ;
2237+ let asset = test_assets. get ( & handle) . unwrap ( ) ;
2238+ assert_eq ! ( handle. id( ) , asset. 0 . id( ) . typed_unchecked:: <TestAssetUD >( ) ) ;
2239+ // This one fails.
2240+ // assert_eq!(handle.id(), asset.0.id().typed::<TestAssetUD>());
2241+ Some ( ( ) )
2242+ }
2243+ state => panic ! ( "Unexpected asset state: {state:?}" ) ,
2244+ } ) ;
2245+
2246+ run_app_until ( & mut app, |world| {
2247+ let messages = collect_asset_events ( world) ;
2248+ if messages. is_empty ( ) {
2249+ return None ;
2250+ }
2251+ assert_eq ! (
2252+ messages,
2253+ [
2254+ AssetEvent :: LoadedWithDependencies { id: handle. id( ) } ,
2255+ AssetEvent :: Added { id: handle. id( ) }
2256+ ]
2257+ ) ;
2258+ Some ( ( ) )
2259+ } ) ;
2260+
2261+ // Sending an asset event should result in the asset being reloaded - resulting in a
2262+ // "Modified" message.
2263+ source_events
2264+ . send ( AssetSourceEvent :: ModifiedAsset ( PathBuf :: from (
2265+ "abc.cool.ron" ,
2266+ ) ) )
2267+ . unwrap ( ) ;
2268+
2269+ run_app_until ( & mut app, |world| {
2270+ let messages = collect_asset_events ( world) ;
2271+ if messages. is_empty ( ) {
2272+ return None ;
2273+ }
2274+ assert_eq ! (
2275+ messages,
2276+ [
2277+ AssetEvent :: LoadedWithDependencies { id: handle. id( ) } ,
2278+ AssetEvent :: Modified { id: handle. id( ) }
2279+ ]
2280+ ) ;
2281+ Some ( ( ) )
2282+ } ) ;
2283+ }
2284+
19902285 // validate the Asset derive macro for various asset types
19912286 #[ derive( Asset , TypePath ) ]
19922287 pub struct TestAsset ;
0 commit comments