2016-01-26 23:21:57 +00:00
|
|
|
use eventual::Async;
|
2016-02-05 21:11:55 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
use std::ffi::CStr;
|
|
|
|
use std::cell::UnsafeCell;
|
2016-01-26 23:21:57 +00:00
|
|
|
|
|
|
|
use librespot::metadata::{MetadataTrait, MetadataRef};
|
|
|
|
|
2016-02-05 21:11:55 +00:00
|
|
|
use cstring_cache::CStringCache;
|
|
|
|
|
|
|
|
use session::SpSession;
|
|
|
|
|
|
|
|
pub struct UnsafeSyncCell<T> {
|
|
|
|
cell: UnsafeCell<T>
|
|
|
|
}
|
|
|
|
|
|
|
|
impl <T> UnsafeSyncCell<T> {
|
|
|
|
fn new(value: T) -> UnsafeSyncCell<T> {
|
|
|
|
UnsafeSyncCell { cell: UnsafeCell::new(value) }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get(&self) -> *mut T {
|
|
|
|
self.cell.get()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl<T> Sync for UnsafeSyncCell<T> {}
|
|
|
|
|
|
|
|
pub enum SpMetadataState<T: MetadataTrait> {
|
2016-01-26 23:21:57 +00:00
|
|
|
Loading,
|
|
|
|
Error,
|
|
|
|
Loaded(T),
|
|
|
|
}
|
|
|
|
|
2016-02-05 21:11:55 +00:00
|
|
|
pub struct SpMetadata<T: MetadataTrait> {
|
|
|
|
state: Arc<UnsafeSyncCell<SpMetadataState<T>>>,
|
|
|
|
cache: CStringCache,
|
|
|
|
}
|
2016-01-26 23:21:57 +00:00
|
|
|
|
|
|
|
impl <T: MetadataTrait> SpMetadata<T> {
|
|
|
|
pub fn from_future(future: MetadataRef<T>) -> SpMetadata<T> {
|
2016-02-05 21:11:55 +00:00
|
|
|
let state = Arc::new(UnsafeSyncCell::new(SpMetadataState::Loading));
|
2016-01-26 23:21:57 +00:00
|
|
|
|
|
|
|
{
|
2016-02-05 21:11:55 +00:00
|
|
|
let state = state.clone();
|
|
|
|
SpSession::receive(future, move |session, result| {
|
|
|
|
let state = unsafe {
|
|
|
|
&mut *state.get()
|
|
|
|
};
|
|
|
|
|
|
|
|
*state = match result {
|
|
|
|
Ok(data) => SpMetadataState::Loaded(data),
|
|
|
|
Err(_) => SpMetadataState::Error,
|
2016-01-26 23:21:57 +00:00
|
|
|
};
|
2016-02-05 21:11:55 +00:00
|
|
|
|
|
|
|
unsafe {
|
|
|
|
if let Some(f) = session.callbacks.metadata_updated {
|
|
|
|
f(session as *mut _)
|
|
|
|
}
|
|
|
|
}
|
2016-01-26 23:21:57 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-02-05 21:11:55 +00:00
|
|
|
SpMetadata {
|
|
|
|
state: state,
|
|
|
|
cache: CStringCache::new(),
|
|
|
|
}
|
2016-01-26 23:21:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_loaded(&self) -> bool {
|
2016-02-05 21:11:55 +00:00
|
|
|
unsafe {
|
|
|
|
self.get().is_some()
|
|
|
|
}
|
2016-01-26 23:21:57 +00:00
|
|
|
}
|
|
|
|
|
2016-02-05 21:11:55 +00:00
|
|
|
pub unsafe fn get(&self) -> Option<&'static T> {
|
|
|
|
let state = &*self.state.get();
|
2016-01-26 23:21:57 +00:00
|
|
|
|
2016-02-05 21:11:55 +00:00
|
|
|
match *state {
|
|
|
|
SpMetadataState::Loaded(ref metadata) => Some(metadata),
|
2016-01-26 23:21:57 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
2016-02-05 21:11:55 +00:00
|
|
|
|
|
|
|
pub fn intern(&mut self, string: &str) -> &CStr {
|
|
|
|
self.cache.intern(string)
|
|
|
|
}
|
2016-01-26 23:21:57 +00:00
|
|
|
}
|