1 type Directory<T, U> where T : Discard = 2 let directory_path : String 3 let f : String * Option<T> -> T 4 let ids : mut obs/Multiset<String> 5 val id_assets : obs/Map<String, U> 6 let paths : obs/Multiset<String> 7 let path_files : mut obs/Map<String, T> 8 let id_atoms = Map<String, mut Atom<Option<U>>>.new 9 let path_modified = Map<String, Time>.new 10 let tokens = List<Token>.new 11 12 fun destruct = 13 for i = tokens.size - 1 downto 0 do 14 tokens[i].discard 15 16 let get_path (id : String) = 17 if not id.contains ' ' 18 then id 19 else id.split_first ' ' 20 21 let update<T, U> (directory : Directory<T, U>) (path : String) where T : Discard = 22 let modified = 23 let full_path = "${directory.directory_path}/$path" 24 if fs/exists full_path 25 then fs/modified_time full_path 26 else Time.new 27 28 let stored_modified = directory.path_modified[path] 29 if modified <> stored_modified then 30 directory.path_modified.insert path modified 31 let maybe_prev_file = directory.path_files.try_get path 32 let maybe_file = if modified == Time@zero then 33 None 34 else 35 let full_path = "${directory.directory_path}/$path" 36 let file = directory.f full_path maybe_prev_file 37 Some file 38 39 case maybe_file of 40 None -> 41 if directory.path_files.contains path then 42 directory.path_files.remove path 43 44 Some file -> 45 directory.path_files.add path file 46 47 if maybe_prev_file ? Some prev_file then 48 prev_file.discard 49 50 object Directory<T, U> where T : Discard = 51 def create (directory_path : String 52 f : String * Option<T> -> T 53 g : obs/Map<String, T> -> obs/Map<String, U>) = 54 let path_files = obs/Map<String, T>.new 55 let ids = obs/Multiset<String>.new 56 let path_ids = Obs.to_multimap ids { id -> (get_path id, id) } 57 let id_files = path_ids.join path_files 58 let paths = Obs.map ids { get_path _ } 59 let directory = Directory<T, U> 60 id_assets = g id_files 61 =ids =paths =path_files =f =directory_path 62 63 paths.bind 64 { path -> directory.path_modified.add path Time.new 65 update directory path } 66 67 { path -> directory.path_modified.remove path 68 let file = path_files[path] 69 path_files.remove path 70 file.discard } 71 |> directory.tokens.add 72 73 directory.id_assets.bind 74 { id x -> if directory.id_atoms.contains id then 75 directory.id_atoms[id].set x } 76 77 { id _ x -> if directory.id_atoms.contains id then 78 directory.id_atoms[id].set x } 79 80 { id _ -> if directory.id_atoms.contains id then 81 directory.id_atoms[id].set None } 82 |> directory.tokens.add 83 84 directory 85 86 type Directory<T, U> 87 def get (id : String) = 88 if not ids.contains id then 89 ids.add id 90 91 id_assets[id] 92 93 def atom (id : String) = 94 if not ids.contains id then 95 ids.add id 96 97 if not id_atoms.contains id then 98 let atom = id_assets.try_get id |> Atom<Option<U>> 99 id_atoms.add id atom 100 101 id_atoms[id].as_readonly 102 103 def update_all = 104 for path in paths do 105 update self path 106 107 def try_update (path : String) = 108 if paths.contains path then 109 update self path 110