metadata.rs 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. use eventual::Async;
  2. use std::sync::Arc;
  3. use std::ffi::CStr;
  4. use std::cell::UnsafeCell;
  5. use librespot::metadata::{MetadataTrait, MetadataRef};
  6. use cstring_cache::CStringCache;
  7. use session::SpSession;
  8. pub struct UnsafeSyncCell<T> {
  9. cell: UnsafeCell<T>
  10. }
  11. impl <T> UnsafeSyncCell<T> {
  12. fn new(value: T) -> UnsafeSyncCell<T> {
  13. UnsafeSyncCell { cell: UnsafeCell::new(value) }
  14. }
  15. fn get(&self) -> *mut T {
  16. self.cell.get()
  17. }
  18. }
  19. unsafe impl<T> Sync for UnsafeSyncCell<T> {}
  20. pub enum SpMetadataState<T: MetadataTrait> {
  21. Loading,
  22. Error,
  23. Loaded(T),
  24. }
  25. pub struct SpMetadata<T: MetadataTrait> {
  26. state: Arc<UnsafeSyncCell<SpMetadataState<T>>>,
  27. cache: CStringCache,
  28. }
  29. impl <T: MetadataTrait> SpMetadata<T> {
  30. pub fn from_future(future: MetadataRef<T>) -> SpMetadata<T> {
  31. let state = Arc::new(UnsafeSyncCell::new(SpMetadataState::Loading));
  32. {
  33. let state = state.clone();
  34. SpSession::receive(future, move |session, result| {
  35. let state = unsafe {
  36. &mut *state.get()
  37. };
  38. *state = match result {
  39. Ok(data) => SpMetadataState::Loaded(data),
  40. Err(_) => SpMetadataState::Error,
  41. };
  42. unsafe {
  43. if let Some(f) = session.callbacks.metadata_updated {
  44. f(session as *mut _)
  45. }
  46. }
  47. });
  48. }
  49. SpMetadata {
  50. state: state,
  51. cache: CStringCache::new(),
  52. }
  53. }
  54. pub fn is_loaded(&self) -> bool {
  55. unsafe {
  56. self.get().is_some()
  57. }
  58. }
  59. pub unsafe fn get(&self) -> Option<&'static T> {
  60. let state = &*self.state.get();
  61. match *state {
  62. SpMetadataState::Loaded(ref metadata) => Some(metadata),
  63. _ => None,
  64. }
  65. }
  66. pub fn intern(&mut self, string: &str) -> &CStr {
  67. self.cache.intern(string)
  68. }
  69. }