1#![allow(non_upper_case_globals)]
41#![allow(non_camel_case_types)]
42#![allow(non_snake_case)]
43
44mod error;
45mod sort;
46
47#[cfg(target_os = "windows")]
48extern crate everything_sys_bindgen;
49
50use bitflags::bitflags;
51pub use error::{EverythingError, EverythingResult, EverythingSDKError};
52use everything_sys_bindgen::*;
53pub use sort::EverythingSort;
54use std::time::Duration;
55use widestring::{U16CStr, U16CString};
56
57bitflags! {
58 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
62 pub struct EverythingRequestFlags: u32 {
63 const FileName = EVERYTHING_REQUEST_FILE_NAME;
64 const Path = EVERYTHING_REQUEST_PATH;
65 const FullPathAndFileName = EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME;
66 const Extension = EVERYTHING_REQUEST_EXTENSION;
67 const Size = EVERYTHING_REQUEST_SIZE;
68 const DateCreated = EVERYTHING_REQUEST_DATE_CREATED;
69 const DateModified = EVERYTHING_REQUEST_DATE_MODIFIED;
70 const DateAccessed = EVERYTHING_REQUEST_DATE_ACCESSED;
71 const Attributes = EVERYTHING_REQUEST_ATTRIBUTES;
72 const FileListFileName = EVERYTHING_REQUEST_FILE_LIST_FILE_NAME;
73 const RunCount = EVERYTHING_REQUEST_RUN_COUNT;
74 const DateRun = EVERYTHING_REQUEST_DATE_RUN;
75 const DateRecentlyChanged = EVERYTHING_REQUEST_DATE_RECENTLY_CHANGED;
76 const HighlightedFileName = EVERYTHING_REQUEST_HIGHLIGHTED_FILE_NAME;
77 const HighlightedPath = EVERYTHING_REQUEST_HIGHLIGHTED_PATH;
78 const HighlightedFullPathAndFileName = EVERYTHING_REQUEST_HIGHLIGHTED_FULL_PATH_AND_FILE_NAME;
79 }
80}
81
82trait U64Able {
83 fn as_u64(&self) -> u64;
84}
85
86impl U64Able for FILETIME {
87 fn as_u64(&self) -> u64 {
88 ((self.dwHighDateTime as u64) << 32) | (self.dwLowDateTime as u64)
89 }
90}
91
92fn parse_string_ptr(ptr: *const u16) -> EverythingResult<String> {
98 if ptr.is_null() {
99 let error_code = Everything::get_last_error();
100 panic!("Error code: {:?}", error_code);
101 }
102
103 Ok(unsafe { U16CStr::from_ptr_str(ptr).to_string_lossy() })
104}
105
106#[derive(Debug)]
109pub struct Everything;
110
111impl Everything {
112 pub fn get_last_error() -> EverythingResult<()> {
114 let error_code = unsafe { Everything_GetLastError() };
115 match error_code.try_into().unwrap() {
116 EverythingSDKError::Ok => Ok(()),
117 err => Err(EverythingError::SDKError(err)),
118 }
119 }
120
121 pub fn wait_db_loaded(timeout: Duration) -> EverythingResult<()> {
124 let sleep_duration: u64 = 300;
125 let mut wait_time: u64 = 0;
126
127 unsafe {
128 while Everything_IsDBLoaded() == 0 {
129 if wait_time >= timeout.as_millis() as u64 {
130 return Err(EverythingError::DatabaseTimeout);
131 }
132 Everything::get_last_error()?;
133 std::thread::sleep(std::time::Duration::from_millis(sleep_duration));
134 wait_time += sleep_duration;
135 }
136 }
137
138 Ok(())
139 }
140
141 pub fn set_search(&self, search: &str) {
144 let wide_search = U16CString::from_str(search).expect("Failed to convert search string");
145 unsafe {
146 Everything_SetSearchW(wide_search.as_ptr());
147 }
148 }
149
150 pub fn get_search(&self) -> EverythingResult<String> {
161 let search_ptr = unsafe { Everything_GetSearchW() };
162 parse_string_ptr(search_ptr)
163 }
164
165 pub fn set_sort(&self, sort: EverythingSort) {
168 unsafe {
169 Everything_SetSort(sort.into());
170 }
171 }
172
173 pub fn get_sort(&self) -> Option<EverythingSort> {
176 let sort = unsafe { Everything_GetSort() };
177 if let Ok(eve_sort) = sort.try_into() {
178 Some(eve_sort)
179 } else {
180 None
181 }
182 }
183
184 pub fn is_fast_sort(&self, sort: EverythingSort) -> bool {
187 unsafe { Everything_IsFastSort(sort.into()) != 0 }
188 }
189
190 pub fn is_result_file(&self, index: DWORD) -> bool {
192 unsafe { Everything_IsFileResult(index) != 0 }
193 }
194
195 pub fn is_result_folder(&self, index: DWORD) -> bool {
197 unsafe { Everything_IsFolderResult(index) != 0 }
198 }
199
200 pub fn is_result_volume(&self, index: DWORD) -> bool {
202 unsafe { Everything_IsVolumeResult(index) != 0 }
203 }
204
205 pub fn get_num_results(&self) -> DWORD {
210 unsafe { Everything_GetNumResults() }
211 }
212
213 pub fn get_total_results(&self) -> DWORD {
216 unsafe { Everything_GetTotResults() }
217 }
218
219 pub fn set_max_results(&self, max_results: DWORD) {
222 unsafe {
223 Everything_SetMax(max_results);
224 }
225 }
226
227 pub fn get_max_results(&self) -> DWORD {
230 unsafe { Everything_GetMax() }
231 }
232
233 pub fn set_result_offset(&self, offset_results: DWORD) {
236 unsafe {
237 Everything_SetOffset(offset_results);
238 }
239 }
240
241 pub fn get_result_offset(&self) -> DWORD {
244 unsafe { Everything_GetOffset() }
245 }
246
247 pub fn set_request_flags(&self, request_flags: EverythingRequestFlags) {
250 unsafe {
251 Everything_SetRequestFlags(request_flags.bits());
252 }
253 }
254
255 pub fn get_request_flags(&self) -> EverythingRequestFlags {
258 let request_flags = unsafe { Everything_GetRequestFlags() };
259 EverythingRequestFlags::from_bits_truncate(request_flags)
260 }
261
262 pub fn query(&self) -> EverythingResult<()> {
263 let result = unsafe { Everything_QueryW(1) };
264 if result == 0 {
265 Everything::get_last_error()
266 } else {
267 Ok(())
268 }
269 }
270
271 pub fn reset(&self) {
274 unsafe {
275 Everything_Reset();
276 }
277 }
278
279 pub fn get_result_count(&self) -> u32 {
282 unsafe { Everything_GetNumResults() }
283 }
284
285 pub fn get_result_full_path(&self, index: u32) -> EverythingResult<String> {
288 let path_length =
289 unsafe { Everything_GetResultFullPathNameW(index, std::ptr::null_mut(), 0) };
290 if path_length == 0 {
291 Everything::get_last_error()?;
292 }
293
294 let mut path_buffer = Vec::with_capacity(path_length as usize + 1);
296 unsafe {
297 let count_copied = Everything_GetResultFullPathNameW(
298 index,
299 path_buffer.as_mut_ptr(),
300 path_buffer.len() as u32,
301 );
302 Ok(
303 U16CStr::from_ptr(path_buffer.as_ptr(), count_copied as usize)
304 .unwrap()
305 .to_string_lossy(),
306 )
307 }
308 }
309
310 pub fn full_path_iter(&self) -> impl Iterator<Item = EverythingResult<String>> + '_ {
313 let num_results = self.get_result_count();
314 (0..num_results).map(|index| self.get_result_full_path(index))
315 }
316
317 pub fn get_result_file_name(&self, index: u32) -> EverythingResult<String> {
320 let result_ptr = unsafe { Everything_GetResultFileNameW(index) };
321
322 if result_ptr.is_null() {
323 Everything::get_last_error()?;
324 }
325
326 parse_string_ptr(result_ptr)
327 }
328
329 pub fn name_iter(&self) -> impl Iterator<Item = EverythingResult<String>> + '_ {
332 let num_results = self.get_result_count();
333 (0..num_results).map(|index| self.get_result_file_name(index))
334 }
335
336 pub fn get_result_created_date(&self, index: u32) -> EverythingResult<u64> {
339 let mut file_time: FILETIME = FILETIME {
340 dwLowDateTime: 0,
341 dwHighDateTime: 0,
342 };
343
344 let success = unsafe { Everything_GetResultDateCreated(index, &mut file_time) };
345
346 if success == 0 {
347 Everything::get_last_error()?;
348 }
349
350 Ok(file_time.as_u64())
351 }
352
353 pub fn get_result_count_modified_date(&self, index: u32) -> EverythingResult<u64> {
356 let mut file_time: FILETIME = FILETIME {
357 dwLowDateTime: 0,
358 dwHighDateTime: 0,
359 };
360
361 let success = unsafe { Everything_GetResultDateModified(index, &mut file_time) };
362
363 if success == 0 {
364 Everything::get_last_error()?;
365 }
366
367 Ok(file_time.as_u64())
368 }
369
370 pub fn get_result_size(&self, index: u32) -> EverythingResult<u64> {
373 let mut size: LARGE_INTEGER = LARGE_INTEGER { QuadPart: 0 };
374
375 let success = unsafe { Everything_GetResultSize(index, &mut size) };
376
377 if success == 0 {
378 Everything::get_last_error()?;
379 }
380
381 Ok(unsafe { size.QuadPart as u64 })
382 }
383
384 pub fn get_result_extension(&self, index: u32) -> EverythingResult<String> {
388 let result_ptr = unsafe { Everything_GetResultExtensionW(index) };
389
390 if result_ptr.is_null() {
391 Everything::get_last_error()?;
392 }
393
394 parse_string_ptr(result_ptr)
395 }
396
397 pub fn new() -> Everything {
399 Everything::wait_db_loaded(Duration::from_secs(5)).expect("Everything database not loaded");
400 Everything
401 }
402
403 pub fn version() -> String {
404 unsafe {
405 let major = Everything_GetMajorVersion();
406 let minor = Everything_GetMinorVersion();
407 let revision = Everything_GetRevision();
408 let build = Everything_GetBuildNumber();
409
410 format!("{}.{}.{}.{}", major, minor, revision, build)
411 }
412 }
413}
414
415impl Drop for Everything {
416 fn drop(&mut self) {
417 unsafe {
418 Everything_CleanUp();
419 }
420 }
421}
422
423impl Default for Everything {
424 fn default() -> Self {
425 Everything::new()
426 }
427}
428
429#[cfg(test)]
430mod tests {
431 use super::*;
432 use lazy_static::lazy_static;
433 use std::path::Path;
434 use std::sync::Mutex;
435
436 lazy_static! {
437 static ref TEST_EVERYTHING: Mutex<Everything> = Mutex::new(Everything::new());
438 }
439
440 fn setup() -> std::sync::MutexGuard<'static, Everything> {
441 let everything = TEST_EVERYTHING.lock().unwrap();
442 everything.reset();
443 everything
444 }
445
446 #[test]
447 fn parses_string_ptr() {
448 let test_string = "test\0";
449 let test_string_ptr = test_string.encode_utf16().collect::<Vec<u16>>();
450 let test_string_ptr = test_string_ptr.as_ptr();
451 let parsed_string = parse_string_ptr(test_string_ptr).unwrap();
452 assert_eq!(parsed_string, test_string[0..4]);
453 }
454
455 #[test]
456 fn parses_full_path() {
457 let test_dir_path = Path::canonicalize(Path::new("../test")).unwrap();
458 let test_dir_path = test_dir_path.to_str().unwrap();
459 let test_dir_path = test_dir_path.trim_start_matches(r"\\?\");
460
461 println!("{}", test_dir_path);
462
463 let evthing = setup();
464
465 evthing.set_search(test_dir_path);
466 evthing.set_request_flags(EverythingRequestFlags::FullPathAndFileName);
467
468 evthing.query().unwrap();
469
470 let num_results = evthing.get_result_count();
471
472 assert!(num_results > 0);
473
474 for path in evthing.full_path_iter().flatten() {
475 println!("{}", path);
476 assert!(path.contains(test_dir_path));
477 }
478 }
479
480 #[test]
481 fn searches() {
482 let everything = setup();
483
484 everything.set_search("test");
485 let search = everything.get_search().unwrap();
486 assert_eq!(search, "test");
487
488 everything.set_max_results(10);
489 let max_results = everything.get_max_results();
490 assert_eq!(max_results, 10);
491
492 everything.set_result_offset(10);
493 let offset = everything.get_result_offset();
494 assert_eq!(offset, 10);
495
496 let flag = EverythingRequestFlags::FullPathAndFileName
497 | EverythingRequestFlags::DateCreated
498 | EverythingRequestFlags::DateModified
499 | EverythingRequestFlags::Size
500 | EverythingRequestFlags::Extension;
501 everything.set_request_flags(flag);
502
503 let flags = everything.get_request_flags();
504 assert_eq!(flags, flag);
505
506 everything.set_sort(EverythingSort::DateCreatedDescending);
507
508 everything.query().unwrap();
509
510 let num_results = everything.get_result_count();
511 assert_eq!(num_results, 10);
512
513 let full_path_results: Vec<EverythingResult<String>> =
514 everything.full_path_iter().collect();
515
516 assert_eq!(full_path_results.len(), 10);
517
518 let mut last_date_created = everything.get_result_created_date(0).unwrap();
519 for idx in 0..num_results {
520 let result = everything.get_result_full_path(idx).unwrap();
521 let iter_result = full_path_results[idx as usize].as_ref().unwrap();
522 assert_eq!(result, *iter_result);
523 println!("{}", result);
524
525 let size = everything.get_result_size(idx).unwrap();
526 assert!(size > 0);
527
528 let created_date = everything.get_result_created_date(idx).unwrap();
529 assert!(created_date > 0);
530 assert!(created_date <= last_date_created);
531 last_date_created = created_date;
532
533 let modified_date = everything.get_result_count_modified_date(idx).unwrap();
534 assert!(modified_date > 0);
535 }
536 }
537}