gonk_database/
query.rs

1use crate::*;
2use rayon::slice::ParallelSliceMut;
3use std::str::from_utf8_unchecked;
4
5pub fn artist(text: &[u8]) -> &str {
6    debug_assert_eq!(text.len(), TEXT_LEN);
7    unsafe {
8        let end = u16::from_le_bytes(text[0..2].try_into().unwrap_unchecked()) as usize + 2;
9        from_utf8_unchecked(&text[2..end])
10    }
11}
12
13pub fn album(text: &[u8]) -> &str {
14    debug_assert_eq!(text.len(), TEXT_LEN);
15    unsafe {
16        let artist_len = u16::from_le_bytes(text[0..2].try_into().unwrap_unchecked()) as usize;
17        let album_len = u16::from_le_bytes(
18            text[2 + artist_len..2 + artist_len + 2]
19                .try_into()
20                .unwrap_unchecked(),
21        ) as usize;
22        let album = 2 + artist_len + 2..artist_len + 2 + album_len + 2;
23        from_utf8_unchecked(&text[album])
24    }
25}
26
27pub fn title(text: &[u8]) -> &str {
28    debug_assert_eq!(text.len(), TEXT_LEN);
29    unsafe {
30        let artist_len = u16::from_le_bytes(text[0..2].try_into().unwrap_unchecked()) as usize;
31        let album_len = u16::from_le_bytes(
32            text[2 + artist_len..2 + artist_len + 2]
33                .try_into()
34                .unwrap_unchecked(),
35        ) as usize;
36
37        let title_len = u16::from_le_bytes(
38            text[2 + artist_len + 2 + album_len..2 + artist_len + 2 + album_len + 2]
39                .try_into()
40                .unwrap_unchecked(),
41        ) as usize;
42
43        let title =
44            2 + artist_len + 2 + album_len + 2..artist_len + 2 + album_len + 2 + title_len + 2;
45
46        from_utf8_unchecked(&text[title])
47    }
48}
49
50pub fn path(text: &[u8]) -> &str {
51    debug_assert_eq!(text.len(), TEXT_LEN);
52    unsafe {
53        let artist_len = u16::from_le_bytes(text[0..2].try_into().unwrap_unchecked()) as usize;
54        let album_len = u16::from_le_bytes(
55            text[2 + artist_len..2 + artist_len + 2]
56                .try_into()
57                .unwrap_unchecked(),
58        ) as usize;
59
60        let title_len = u16::from_le_bytes(
61            text[2 + artist_len + 2 + album_len..2 + artist_len + 2 + album_len + 2]
62                .try_into()
63                .unwrap_unchecked(),
64        ) as usize;
65
66        let path_len = u16::from_le_bytes(
67            text[2 + artist_len + 2 + album_len + 2 + title_len
68                ..2 + artist_len + 2 + album_len + 2 + title_len + 2]
69                .try_into()
70                .unwrap_unchecked(),
71        ) as usize;
72
73        let path = 2 + artist_len + 2 + album_len + 2 + title_len + 2
74            ..artist_len + 2 + album_len + 2 + title_len + 2 + path_len + 2;
75
76        from_utf8_unchecked(&text[path])
77    }
78}
79
80pub fn artist_and_album(text: &[u8]) -> (&str, &str) {
81    debug_assert_eq!(text.len(), TEXT_LEN);
82    unsafe {
83        let artist_len = u16::from_le_bytes(text[0..2].try_into().unwrap_unchecked()) as usize;
84        let artist = 2..artist_len + 2;
85
86        let album_len = u16::from_le_bytes(
87            text[2 + artist_len..2 + artist_len + 2]
88                .try_into()
89                .unwrap_unchecked(),
90        ) as usize;
91        let album = 2 + artist_len + 2..artist_len + 2 + album_len + 2;
92
93        (
94            from_utf8_unchecked(&text[artist]),
95            from_utf8_unchecked(&text[album]),
96        )
97    }
98}
99
100pub fn get(index: usize) -> Option<Song> {
101    if let Some(mmap) = mmap() {
102        let start = SONG_LEN * index;
103        let bytes = mmap.get(start..start + SONG_LEN)?;
104        Some(Song::from(bytes, index))
105    } else {
106        None
107    }
108}
109
110pub fn ids(ids: &[usize]) -> Vec<Song> {
111    if let Some(mmap) = mmap() {
112        let mut songs = Vec::new();
113        for id in ids {
114            let start = SONG_LEN * id;
115            let bytes = &mmap[start..start + SONG_LEN];
116            songs.push(Song::from(bytes, *id));
117        }
118        //TODO: Check if songs need to be sorted here.
119        songs
120    } else {
121        Vec::new()
122    }
123}
124
125pub fn songs_from_album(ar: &str, al: &str) -> Vec<Song> {
126    if let Some(mmap) = mmap() {
127        let mut songs = Vec::new();
128        let mut i = 0;
129        while let Some(text) = mmap.get(i..i + TEXT_LEN) {
130            let (artist, album) = artist_and_album(text);
131            if artist == ar && album == al {
132                songs.push(Song::from(&mmap[i..i + SONG_LEN], i / SONG_LEN));
133            }
134            i += SONG_LEN;
135        }
136        songs.sort_unstable();
137        songs
138    } else {
139        Vec::new()
140    }
141}
142
143pub fn albums_by_artist(ar: &str) -> Vec<String> {
144    if let Some(mmap) = mmap() {
145        let mut albums = Vec::new();
146        let mut i = 0;
147        while let Some(text) = mmap.get(i..i + TEXT_LEN) {
148            let artist = artist(text);
149            if artist == ar {
150                albums.push(album(text).to_string());
151            }
152            i += SONG_LEN;
153        }
154        albums.sort_unstable_by_key(|album| album.to_ascii_lowercase());
155        albums.dedup();
156        albums
157    } else {
158        Vec::new()
159    }
160}
161
162pub fn songs_by_artist(ar: &str) -> Vec<Song> {
163    if let Some(mmap) = mmap() {
164        let mut songs = Vec::new();
165        let mut i = 0;
166        while let Some(text) = mmap.get(i..i + TEXT_LEN) {
167            let artist = artist(text);
168            if artist == ar {
169                let song_bytes = &mmap[i..i + SONG_LEN];
170                songs.push(Song::from(song_bytes, i / SONG_LEN));
171            }
172            i += SONG_LEN;
173        }
174        songs.sort_unstable();
175        songs
176    } else {
177        Vec::new()
178    }
179}
180
181pub fn artists() -> Vec<String> {
182    if let Some(mmap) = mmap() {
183        let mut artists = Vec::new();
184        let mut i = 0;
185        while let Some(text) = mmap.get(i..i + TEXT_LEN) {
186            artists.push(artist(text).to_string());
187            i += SONG_LEN;
188        }
189        artists.sort_unstable_by_key(|artist| artist.to_ascii_lowercase());
190        artists.dedup();
191        artists
192    } else {
193        Vec::new()
194    }
195}
196
197pub fn artists_albums_and_songs() -> (Vec<String>, Vec<(String, String)>, Vec<Song>) {
198    if let Some(mmap) = mmap() {
199        let songs: Vec<Song> = (0..len())
200            .into_par_iter()
201            .map(|i| {
202                let pos = i * SONG_LEN;
203                let bytes = unsafe { &mmap.get_unchecked(pos..pos + SONG_LEN) };
204                Song::from(bytes, i)
205            })
206            .collect();
207
208        let mut albums: Vec<(&str, &str)> = songs
209            .iter()
210            .map(|song| (song.artist.as_str(), song.album.as_str()))
211            .collect();
212        albums.par_sort_unstable_by_key(|(artist, _album)| artist.to_ascii_lowercase());
213        albums.dedup();
214        let albums: Vec<(String, String)> = albums
215            .into_iter()
216            .map(|(artist, album)| (artist.to_owned(), album.to_owned()))
217            .collect();
218
219        let mut artists: Vec<String> = albums
220            .iter()
221            .map(|(artist, _album)| artist.clone())
222            .collect();
223        artists.dedup();
224
225        (artists, albums, songs)
226    } else {
227        (Vec::new(), Vec::new(), Vec::new())
228    }
229}
230
231pub fn len() -> usize {
232    if let Some(mmap) = mmap() {
233        mmap.len() / SONG_LEN
234    } else {
235        0
236    }
237}