use std::io;
use std::path::{ Path, PathBuf };
use std::sync::OnceLock;
static RESOURCE_DIR: OnceLock<PathBuf> = OnceLock::new();
pub fn set_resource_dir( dir: impl Into<PathBuf> )
{
let _ = RESOURCE_DIR.set( dir.into() );
}
pub fn resource_dir() -> Option<&'static Path>
{
RESOURCE_DIR.get().map( PathBuf::as_path ).or_else( beside_executable )
}
#[ cfg( windows ) ]
fn beside_executable() -> Option<&'static Path>
{
static DIR: OnceLock<Option<PathBuf>> = OnceLock::new();
DIR.get_or_init( ||
{
let dir = std::env::current_exe().ok()?.parent()?.join( "ltk" );
dir.is_dir().then_some( dir )
} ).as_deref()
}
#[ cfg( not( windows ) ) ]
fn beside_executable() -> Option<&'static Path>
{
None
}
pub( crate ) fn read_font( path: &Path ) -> io::Result<Vec<u8>>
{
read_font_in( path, resource_dir() )
}
fn read_font_in( path: &Path, bundle: Option<&Path> ) -> io::Result<Vec<u8>>
{
match crate::vfs::read( path )
{
Err( e ) if e.kind() == io::ErrorKind::NotFound =>
{
let Some( ( dir, name ) ) = bundle.zip( path.file_name() ) else { return Err( e ) };
crate::vfs::read( dir.join( "fonts" ).join( name ) )
}
read => read,
}
}
#[ cfg( test ) ]
mod tests
{
use super::read_font_in;
use std::path::Path;
#[ test ]
fn a_missing_font_is_found_in_the_bundle_by_name()
{
let bundle = std::env::temp_dir().join( format!( "ltk-resources-{}", std::process::id() ) );
std::fs::create_dir_all( bundle.join( "fonts" ) ).unwrap();
std::fs::write( bundle.join( "fonts/Face-Regular.otf" ), b"face" ).unwrap();
let read = read_font_in( Path::new( "/nonexistent/fonts/Face-Regular.otf" ), Some( &bundle ) );
std::fs::remove_dir_all( &bundle ).unwrap();
assert_eq!( read.unwrap(), b"face" );
}
#[ test ]
fn without_a_bundle_a_missing_font_stays_missing()
{
assert!( read_font_in( Path::new( "/nonexistent/fonts/Face-Regular.otf" ), None ).is_err() );
}
}