2019-04-20 01:24:19 +02:00
use crate ::model ::* ;
2019-05-05 19:16:52 +02:00
use std ::collections ::* ;
2019-04-30 19:08:40 +02:00
use std ::fs ;
2019-04-20 01:24:19 +02:00
use std ::io ;
use std ::path ::{ Path , PathBuf } ;
use std ::sync ::Arc ;
pub use self ::search ::Query ;
mod image_convert ;
2019-05-05 19:16:52 +02:00
mod metadata_file ;
2019-04-24 17:01:43 +02:00
mod search ;
2019-04-20 01:24:19 +02:00
2019-04-24 17:01:43 +02:00
pub type TextureFileResult = Result < Arc < Vec < u8 > > , TextureFileError > ;
2019-04-20 01:24:19 +02:00
pub enum TextureFileError {
NotFound ,
IoError ( io ::Error ) ,
ImageError ( ::image ::ImageError ) ,
}
2019-05-05 19:16:52 +02:00
impl From < io ::Error > for TextureFileError {
fn from ( err : io ::Error ) -> Self {
TextureFileError ::IoError ( err )
}
2019-04-20 01:24:19 +02:00
}
2019-05-05 19:16:52 +02:00
impl From < ::image ::ImageError > for TextureFileError {
fn from ( err : ::image ::ImageError ) -> Self {
TextureFileError ::ImageError ( err )
2019-05-04 18:35:49 +02:00
}
2019-05-05 19:16:52 +02:00
}
pub struct DataStore {
//data_path: PathBuf,
base_dir : PathBuf ,
textures : HashSet < Texture > ,
id_index : HashMap < String , Texture > ,
name_index : HashMap < String , Texture > ,
preview_cache : HashMap < ( TextureFormat , Sha256 ) , Arc < Vec < u8 > > > ,
2019-05-04 18:35:49 +02:00
}
2019-04-20 01:24:19 +02:00
impl DataStore {
2019-05-05 19:16:52 +02:00
fn texture_file_path ( & self , sha : & Sha256 ) -> PathBuf {
let mut path = self . base_dir . clone ( ) ;
path . push ( " textures " ) ;
path . push ( sha . as_hex_string ( ) ) ;
path
}
2019-04-30 19:08:40 +02:00
2019-05-05 19:16:52 +02:00
fn index_file_path ( & self ) -> PathBuf {
let mut path = self . base_dir . clone ( ) ;
path . push ( " collection.json " ) ;
path
2019-04-20 01:24:19 +02:00
}
2019-05-05 19:16:52 +02:00
pub fn new ( base_dir : & Path ) -> io ::Result < DataStore > {
let mut store = DataStore {
base_dir : base_dir . into ( ) ,
textures : Default ::default ( ) ,
id_index : Default ::default ( ) ,
name_index : Default ::default ( ) ,
preview_cache : Default ::default ( ) ,
} ;
let metadata_file = metadata_file ::MetadataFile ::load ( base_dir ) ? ;
for texture in metadata_file . textures . iter ( ) {
match store . insert ( texture . clone ( ) ) ? {
true = > ( ) ,
false = > {
println! ( " inserting {:#?} failed !!! " , texture ) ; // TODO: What should be done?
}
}
}
Ok ( store )
2019-04-20 01:24:19 +02:00
}
2019-05-05 19:16:52 +02:00
pub fn texture_by_id ( & self , id : & str ) -> Option < Texture > {
self . id_index . get ( id ) . cloned ( )
2019-04-20 01:24:19 +02:00
}
2019-05-05 19:16:52 +02:00
pub fn texture_by_name ( & self , id : & str ) -> Option < Texture > {
self . name_index . get ( id ) . cloned ( )
}
pub fn insert ( & mut self , texture : Texture ) -> io ::Result < bool > {
if self . id_index . contains_key ( & texture . id ) {
return Ok ( false ) ;
}
if self . name_index . contains_key ( & texture . name ) {
return Ok ( false ) ;
2019-04-30 19:08:40 +02:00
}
2019-05-05 19:16:52 +02:00
if ! self . is_texture_file_on_disk ( & texture . texture_hash ) ? {
return Ok ( false ) ;
}
self . id_index . insert ( texture . id . clone ( ) , texture . clone ( ) ) ;
self . name_index
. insert ( texture . name . clone ( ) , texture . clone ( ) ) ;
self . textures . insert ( texture . clone ( ) ) ;
Ok ( true )
2019-04-20 01:24:19 +02:00
}
2019-05-05 19:16:52 +02:00
/// returns true if successful
pub fn delete ( & mut self , tex : & Texture ) -> bool {
if self . textures . remove ( tex ) {
// remove
assert! ( self . id_index . remove ( & tex . id ) . is_some ( ) ) ;
assert! ( self . name_index . remove ( & tex . name ) . is_some ( ) ) ;
// don't delete cache, since it could be used
// by other texture.
true
2019-05-03 11:19:34 +02:00
} else {
2019-05-05 19:16:52 +02:00
false
2019-04-30 19:08:40 +02:00
}
2019-04-20 01:24:19 +02:00
}
2019-05-05 19:16:52 +02:00
/// Check if the texture, given by hash, physically exists on the file system.
pub fn is_texture_file_on_disk ( & self , hash : & Sha256 ) -> io ::Result < bool > {
let file_path = self . texture_file_path ( & hash ) ;
2019-04-20 01:24:19 +02:00
2019-05-05 19:16:52 +02:00
Ok ( file_path . is_file ( ) )
2019-04-20 01:24:19 +02:00
}
2019-05-05 19:23:10 +02:00
// Todo: this return type looks wrong : ImageError can't happen
2019-05-05 19:16:52 +02:00
pub fn read_texture_file_by_hash ( & mut self , hash : & Sha256 ) -> TextureFileResult {
use std ::fs ::* ;
use std ::io ::* ;
if ! ( self . is_texture_file_on_disk ( & hash ) ? ) {
return Err ( TextureFileError ::NotFound ) ;
2019-05-03 11:19:34 +02:00
}
2019-04-20 01:24:19 +02:00
2019-05-05 19:16:52 +02:00
let file_path = self . texture_file_path ( & hash ) ;
2019-04-30 19:08:40 +02:00
2019-05-05 19:16:52 +02:00
let mut file = File ::open ( file_path ) ? ;
2019-04-30 19:08:40 +02:00
let mut buffer = Vec ::new ( ) ;
2019-05-05 19:16:52 +02:00
file . read_to_end ( & mut buffer ) ? ;
2019-04-30 19:08:40 +02:00
Ok ( Arc ::new ( buffer ) )
2019-04-20 01:24:19 +02:00
}
2019-05-05 19:16:52 +02:00
pub fn store_texture_file ( & mut self , data : & [ u8 ] ) -> io ::Result < ( ) > {
use std ::fs ;
use std ::io ::Write ;
let hash = crate ::model ::Sha256 ::from_data ( data ) ;
let file_path = self . texture_file_path ( & hash ) ;
fs ::create_dir_all ( & file_path ) ? ;
let mut file = fs ::File ::create ( & file_path ) ? ;
file . write_all ( data )
}
fn flush_metadata ( & self ) -> io ::Result < ( ) > {
let f = metadata_file ::MetadataFile ::from_iterator ( self . textures . iter ( ) ) ;
f . store ( self . index_file_path ( ) . as_path ( ) )
}
2019-05-05 19:23:10 +02:00
pub fn get_texture_preview ( & mut self , hash : & Sha256 , desired_format : TextureFormat ) -> TextureFileResult {
2019-04-20 01:24:19 +02:00
unimplemented! ( ) ;
}
2019-05-04 18:35:49 +02:00
2019-05-05 19:16:52 +02:00
pub fn garbage_collect ( & mut self ) -> io ::Result < ( ) > {
unimplemented! ( )
}
pub fn query ( & mut self , query : & self ::search ::Query ) -> Vec < Texture > {
unimplemented! ( ) ;
// calls self::search::search(... )
2019-05-04 18:35:49 +02:00
}
2019-04-20 01:24:19 +02:00
}