1#![cfg_attr(target_os = "windows", allow(dead_code))]
8
9mod parser;
10
11use crate::ev::{self, Axis, AxisOrBtn, Button};
12use gilrs_core::native_ev_codes as nec;
13use gilrs_core::EvCode;
14
15use std::collections::HashMap;
16use std::env;
17use std::error::Error;
18use std::fmt::{Display, Formatter, Result as FmtResult, Write as _};
19
20use fnv::FnvHashMap;
21use uuid::Uuid;
22use vec_map::VecMap;
23
24use self::parser::{Error as ParserError, ErrorKind as ParserErrorKind, Parser, Token};
25
26#[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd"))]
28const SDL_PLATFORM_NAME: &str = "Linux";
29#[cfg(target_os = "macos")]
30const SDL_PLATFORM_NAME: &str = "Mac OS X";
31#[cfg(target_os = "windows")]
32const SDL_PLATFORM_NAME: &str = "Windows";
33#[cfg(all(
34 not(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd")),
35 not(target_os = "macos"),
36 not(target_os = "windows")
37))]
38const SDL_PLATFORM_NAME: &str = "Unknown";
39
40#[derive(Debug)]
41#[cfg_attr(test, derive(PartialEq))]
42pub struct Mapping {
46 mappings: FnvHashMap<EvCode, AxisOrBtn>,
47 name: String,
48 default: bool,
49 hats_mapped: u8,
50}
51
52impl Mapping {
53 pub fn new() -> Self {
54 Mapping {
55 mappings: FnvHashMap::default(),
56 name: String::new(),
57 default: false,
58 hats_mapped: 0,
59 }
60 }
61
62 pub fn default(gamepad: &gilrs_core::Gamepad) -> Self {
63 use self::Axis as Ax;
64 use self::AxisOrBtn::*;
65
66 macro_rules! fnv_map {
67 ( $( $key:expr => $elem:expr ),* ) => {
68 {
69 let mut map = FnvHashMap::default();
70 $(
71 map.insert($key, $elem);
72 )*
73
74 map
75 }
76 };
77 }
78
79 let mut mappings = fnv_map![
80 nec::BTN_SOUTH => Btn(Button::South),
81 nec::BTN_EAST => Btn(Button::East),
82 nec::BTN_C => Btn(Button::C),
83 nec::BTN_NORTH => Btn(Button::North),
84 nec::BTN_WEST => Btn(Button::West),
85 nec::BTN_Z => Btn(Button::Z),
86 nec::BTN_LT => Btn(Button::LeftTrigger),
87 nec::BTN_RT => Btn(Button::RightTrigger),
88 nec::BTN_LT2 => Btn(Button::LeftTrigger2),
89 nec::BTN_RT2 => Btn(Button::RightTrigger2),
90 nec::BTN_SELECT => Btn(Button::Select),
91 nec::BTN_START => Btn(Button::Start),
92 nec::BTN_MODE => Btn(Button::Mode),
93 nec::BTN_LTHUMB => Btn(Button::LeftThumb),
94 nec::BTN_RTHUMB => Btn(Button::RightThumb),
95 nec::BTN_DPAD_UP => Btn(Button::DPadUp),
96 nec::BTN_DPAD_DOWN => Btn(Button::DPadDown),
97 nec::BTN_DPAD_LEFT => Btn(Button::DPadLeft),
98 nec::BTN_DPAD_RIGHT => Btn(Button::DPadRight),
99
100 nec::AXIS_LT => Btn(Button::LeftTrigger),
101 nec::AXIS_RT => Btn(Button::RightTrigger),
102 nec::AXIS_LT2 => Btn(Button::LeftTrigger2),
103 nec::AXIS_RT2 => Btn(Button::RightTrigger2),
104
105 nec::AXIS_LSTICKX => Axis(Ax::LeftStickX),
106 nec::AXIS_LSTICKY => Axis(Ax::LeftStickY),
107 nec::AXIS_LEFTZ => Axis(Ax::LeftZ),
108 nec::AXIS_RSTICKX => Axis(Ax::RightStickX),
109 nec::AXIS_RSTICKY => Axis(Ax::RightStickY),
110 nec::AXIS_RIGHTZ => Axis(Ax::RightZ),
111 nec::AXIS_DPADX => Axis(Ax::DPadX),
112 nec::AXIS_DPADY => Axis(Ax::DPadY)
113 ];
114
115 let axes = [
117 nec::AXIS_DPADX,
118 nec::AXIS_DPADY,
119 nec::AXIS_LEFTZ,
120 nec::AXIS_LSTICKX,
121 nec::AXIS_LSTICKY,
122 nec::AXIS_RSTICKX,
123 nec::AXIS_RSTICKY,
124 nec::AXIS_LT,
125 nec::AXIS_LT2,
126 nec::AXIS_RT,
127 nec::AXIS_RT2,
128 nec::AXIS_RIGHTZ,
129 ];
130 let btns = [
131 nec::BTN_SOUTH,
132 nec::BTN_NORTH,
133 nec::BTN_WEST,
134 nec::BTN_WEST,
135 nec::BTN_C,
136 nec::BTN_Z,
137 nec::BTN_LT,
138 nec::BTN_LT2,
139 nec::BTN_RT,
140 nec::BTN_RT2,
141 nec::BTN_SELECT,
142 nec::BTN_START,
143 nec::BTN_MODE,
144 nec::BTN_LTHUMB,
145 nec::BTN_RTHUMB,
146 nec::BTN_DPAD_DOWN,
147 nec::BTN_DPAD_LEFT,
148 nec::BTN_DPAD_RIGHT,
149 nec::BTN_DPAD_UP,
150 ];
151
152 for axis in &axes {
153 if !gamepad.axes().contains(axis) {
154 mappings.remove(axis);
155 }
156 }
157
158 for btn in &btns {
159 if !gamepad.buttons().contains(btn) {
160 mappings.remove(btn);
161 }
162 }
163
164 Mapping {
165 mappings,
166 name: String::new(),
167 default: true,
168 hats_mapped: 0,
169 }
170 }
171
172 pub fn name(&self) -> &str {
173 &self.name
174 }
175
176 pub fn from_data(
177 data: &MappingData,
178 buttons: &[EvCode],
179 axes: &[EvCode],
180 name: &str,
181 uuid: Uuid,
182 ) -> Result<(Self, String), MappingError> {
183 use crate::constants::*;
184
185 if !Self::is_name_valid(name) {
186 return Err(MappingError::InvalidName);
187 }
188
189 let mut mappings = FnvHashMap::default();
190 let mut sdl_mappings = format!("{},{},", uuid.as_simple(), name);
191
192 {
193 let mut add_button = |ident, ev_code, mapped_btn| {
194 Self::add_button(
195 ident,
196 ev_code,
197 mapped_btn,
198 buttons,
199 &mut sdl_mappings,
200 &mut mappings,
201 )
202 };
203
204 for (button, &ev_code) in &data.buttons {
205 match button as u16 {
206 BTN_SOUTH => add_button("a", ev_code, Button::South)?,
207 BTN_EAST => add_button("b", ev_code, Button::East)?,
208 BTN_WEST => add_button("x", ev_code, Button::West)?,
209 BTN_NORTH => add_button("y", ev_code, Button::North)?,
210 BTN_LT => add_button("leftshoulder", ev_code, Button::LeftTrigger)?,
211 BTN_RT => add_button("rightshoulder", ev_code, Button::RightTrigger)?,
212 BTN_LT2 => add_button("lefttrigger", ev_code, Button::LeftTrigger2)?,
213 BTN_RT2 => add_button("righttrigger", ev_code, Button::RightTrigger2)?,
214 BTN_SELECT => add_button("back", ev_code, Button::Select)?,
215 BTN_START => add_button("start", ev_code, Button::Start)?,
216 BTN_MODE => add_button("guide", ev_code, Button::Mode)?,
217 BTN_LTHUMB => add_button("leftstick", ev_code, Button::LeftThumb)?,
218 BTN_RTHUMB => add_button("rightstick", ev_code, Button::RightThumb)?,
219 BTN_DPAD_UP => add_button("dpup", ev_code, Button::DPadUp)?,
220 BTN_DPAD_DOWN => add_button("dpdown", ev_code, Button::DPadDown)?,
221 BTN_DPAD_LEFT => add_button("dpleft", ev_code, Button::DPadLeft)?,
222 BTN_DPAD_RIGHT => add_button("dpright", ev_code, Button::DPadRight)?,
223 BTN_C => add_button("c", ev_code, Button::C)?,
224 BTN_Z => add_button("z", ev_code, Button::Z)?,
225 BTN_UNKNOWN => return Err(MappingError::UnknownElement),
226 _ => unreachable!(),
227 }
228 }
229 }
230
231 {
232 let mut add_axis = |ident, ev_code, mapped_axis| {
233 Self::add_axis(
234 ident,
235 ev_code,
236 mapped_axis,
237 axes,
238 &mut sdl_mappings,
239 &mut mappings,
240 )
241 };
242
243 for (axis, &ev_code) in &data.axes {
244 match axis as u16 {
245 AXIS_LSTICKX => add_axis("leftx", ev_code, Axis::LeftStickX)?,
246 AXIS_LSTICKY => add_axis("lefty", ev_code, Axis::LeftStickY)?,
247 AXIS_RSTICKX => add_axis("rightx", ev_code, Axis::RightStickX)?,
248 AXIS_RSTICKY => add_axis("righty", ev_code, Axis::RightStickY)?,
249 AXIS_LEFTZ => add_axis("leftz", ev_code, Axis::LeftZ)?,
250 AXIS_RIGHTZ => add_axis("rightz", ev_code, Axis::RightZ)?,
251 AXIS_UNKNOWN => return Err(MappingError::UnknownElement),
252 _ => unreachable!(),
253 }
254 }
255 }
256
257 let mapping = Mapping {
258 mappings,
259 name: name.to_owned(),
260 default: false,
261 hats_mapped: 0,
262 };
263
264 Ok((mapping, sdl_mappings))
265 }
266
267 pub fn parse_sdl_mapping(
268 line: &str,
269 buttons: &[EvCode],
270 axes: &[EvCode],
271 ) -> Result<Self, ParseSdlMappingError> {
272 let mut mapping = Mapping::new();
273 let mut parser = Parser::new(line);
274
275 let mut uuid: Option<Uuid> = None;
276 while let Some(token) = parser.next_token() {
277 if let Err(ref e) = token {
278 if e.kind() == &ParserErrorKind::EmptyValue {
279 continue;
280 }
281 }
282
283 let token = token?;
284
285 match token {
286 Token::Platform(platform) => {
287 if platform != SDL_PLATFORM_NAME {
288 warn!("Mappings for different platform – {}", platform);
289 }
290 }
291 Token::Uuid(v) => uuid = Some(v),
292
293 Token::Name(name) => mapping.name = name.to_owned(),
294 Token::AxisMapping { from, to, .. } => {
295 let axis = axes.get(from as usize).cloned();
296 if let Some(axis) = axis {
297 mapping.mappings.insert(axis, to);
298 } else {
299 warn!(
300 "SDL-mapping {} {}: Unknown axis a{}",
301 uuid.unwrap(),
302 mapping.name,
303 from
304 )
305 }
306 }
307 Token::ButtonMapping { from, to, .. } => {
308 let btn = buttons.get(from as usize).cloned();
309
310 if let Some(btn) = btn {
311 mapping.mappings.insert(btn, to);
312 } else {
313 warn!(
314 "SDL-mapping {} {}: Unknown button b{}",
315 uuid.unwrap(),
316 mapping.name,
317 from
318 )
319 }
320 }
321 Token::HatMapping {
322 hat, direction, to, ..
323 } => {
324 if hat != 0 {
325 warn!(
326 "Hat mappings are only supported for dpads (requested to map hat \
327 {}.{} to {:?}",
328 hat, direction, to
329 );
330 } else {
331 let (from_axis, from_btn) = match direction {
337 1 => (nec::AXIS_DPADY, nec::BTN_DPAD_UP),
338 4 => (nec::AXIS_DPADY, nec::BTN_DPAD_DOWN),
339 2 => (nec::AXIS_DPADX, nec::BTN_DPAD_RIGHT),
340 8 => (nec::AXIS_DPADX, nec::BTN_DPAD_LEFT),
341 0 => continue, _ => return Err(ParseSdlMappingError::UnknownHatDirection),
343 };
344
345 if to.is_button() {
346 match to {
347 AxisOrBtn::Btn(Button::DPadLeft | Button::DPadRight) => {
348 mapping
349 .mappings
350 .insert(from_axis, AxisOrBtn::Axis(Axis::DPadX));
351 }
352 AxisOrBtn::Btn(Button::DPadUp | Button::DPadDown) => {
353 mapping
354 .mappings
355 .insert(from_axis, AxisOrBtn::Axis(Axis::DPadY));
356 }
357 _ => (),
358 }
359 mapping.mappings.insert(from_btn, to);
360 } else {
361 mapping.mappings.insert(from_axis, to);
362 }
363
364 mapping.hats_mapped |= direction as u8;
365 }
366 }
367 }
368 }
369
370 Ok(mapping)
371 }
372
373 fn add_button(
374 ident: &str,
375 ev_code: EvCode,
376 mapped_btn: Button,
377 buttons: &[EvCode],
378 sdl_mappings: &mut String,
379 mappings: &mut FnvHashMap<EvCode, AxisOrBtn>,
380 ) -> Result<(), MappingError> {
381 let n_btn = buttons
382 .iter()
383 .position(|&x| x == ev_code)
384 .ok_or(MappingError::InvalidCode(ev::Code(ev_code)))?;
385 let _ = write!(sdl_mappings, "{}:b{},", ident, n_btn);
386 mappings.insert(ev_code, AxisOrBtn::Btn(mapped_btn));
387 Ok(())
388 }
389
390 fn add_axis(
391 ident: &str,
392 ev_code: EvCode,
393 mapped_axis: Axis,
394 axes: &[EvCode],
395 sdl_mappings: &mut String,
396 mappings: &mut FnvHashMap<EvCode, AxisOrBtn>,
397 ) -> Result<(), MappingError> {
398 let n_axis = axes
399 .iter()
400 .position(|&x| x == ev_code)
401 .ok_or(MappingError::InvalidCode(ev::Code(ev_code)))?;
402 let _ = write!(sdl_mappings, "{}:a{},", ident, n_axis);
403 mappings.insert(ev_code, AxisOrBtn::Axis(mapped_axis));
404 Ok(())
405 }
406
407 fn is_name_valid(name: &str) -> bool {
408 !name.chars().any(|x| x == ',')
409 }
410
411 pub fn map(&self, code: &EvCode) -> Option<AxisOrBtn> {
412 self.mappings.get(code).cloned()
413 }
414
415 pub fn map_rev(&self, el: &AxisOrBtn) -> Option<EvCode> {
416 self.mappings.iter().find(|x| x.1 == el).map(|x| *x.0)
417 }
418
419 pub fn is_default(&self) -> bool {
420 self.default
421 }
422
423 pub fn hats_mapped(&self) -> u8 {
426 self.hats_mapped
427 }
428}
429
430#[derive(Clone, PartialEq, Eq, Debug)]
431pub enum ParseSdlMappingError {
432 UnknownHatDirection,
433 ParseError(ParserError),
434}
435
436impl From<ParserError> for ParseSdlMappingError {
437 fn from(f: ParserError) -> Self {
438 ParseSdlMappingError::ParseError(f)
439 }
440}
441
442impl Error for ParseSdlMappingError {
443 fn source(&self) -> Option<&(dyn Error + 'static)> {
444 if let ParseSdlMappingError::ParseError(ref err) = self {
445 Some(err)
446 } else {
447 None
448 }
449 }
450}
451
452impl Display for ParseSdlMappingError {
453 fn fmt(&self, fmt: &mut Formatter<'_>) -> FmtResult {
454 match self {
455 ParseSdlMappingError::UnknownHatDirection => {
456 fmt.write_str("hat direction wasn't 1, 2, 4 or 8")
457 }
458 ParseSdlMappingError::ParseError(_) => fmt.write_str("parsing error"),
459 }
460 }
461}
462
463#[derive(Debug)]
464pub struct MappingDb {
465 mappings: HashMap<Uuid, String>,
466}
467
468impl MappingDb {
469 pub fn new() -> Self {
470 MappingDb {
471 mappings: HashMap::new(),
472 }
473 }
474
475 pub fn add_included_mappings(&mut self) {
476 self.insert(include_str!(concat!(
477 env!("OUT_DIR"),
478 "/gamecontrollerdb.txt"
479 )));
480 }
481
482 pub fn add_env_mappings(&mut self) {
483 if let Ok(mapping) = env::var("SDL_GAMECONTROLLERCONFIG") {
484 self.insert(&mapping);
485 }
486 }
487
488 pub fn insert(&mut self, s: &str) {
489 for mapping in s.lines() {
490 let pat = "platform:";
491 if let Some(offset) = mapping.find(pat).map(|o| o + pat.len()) {
492 let s = &mapping[offset..];
493 let end = s.find(',').unwrap_or(s.len());
494
495 if &s[..end] != SDL_PLATFORM_NAME {
496 continue;
497 }
498 }
499
500 mapping
501 .split(',')
502 .next()
503 .and_then(|s| Uuid::parse_str(s).ok())
504 .and_then(|uuid| self.mappings.insert(uuid, mapping.to_owned()));
505 }
506 }
507
508 pub fn get(&self, uuid: Uuid) -> Option<&str> {
509 self.mappings.get(&uuid).map(String::as_ref)
510 }
511
512 pub fn len(&self) -> usize {
513 self.mappings.len()
514 }
515}
516
517#[derive(Debug, Clone, Default)]
525pub struct MappingData {
527 buttons: VecMap<EvCode>,
528 axes: VecMap<EvCode>,
529}
530
531impl MappingData {
532 pub fn new() -> Self {
534 MappingData {
535 buttons: VecMap::with_capacity(18),
536 axes: VecMap::with_capacity(11),
537 }
538 }
539
540 pub fn button(&self, idx: Button) -> Option<ev::Code> {
542 self.buttons.get(idx as usize).cloned().map(ev::Code)
543 }
544
545 pub fn axis(&self, idx: Axis) -> Option<ev::Code> {
547 self.axes.get(idx as usize).cloned().map(ev::Code)
548 }
549
550 pub fn insert_btn(&mut self, from: ev::Code, to: Button) -> Option<ev::Code> {
552 self.buttons.insert(to as usize, from.0).map(ev::Code)
553 }
554
555 pub fn insert_axis(&mut self, from: ev::Code, to: Axis) -> Option<ev::Code> {
557 self.axes.insert(to as usize, from.0).map(ev::Code)
558 }
559
560 pub fn remove_button(&mut self, idx: Button) -> Option<ev::Code> {
562 self.buttons.remove(idx as usize).map(ev::Code)
563 }
564
565 pub fn remove_axis(&mut self, idx: Axis) -> Option<ev::Code> {
567 self.axes.remove(idx as usize).map(ev::Code)
568 }
569}
570
571#[derive(Copy, Clone, Debug, PartialEq, Eq)]
573#[non_exhaustive]
574pub enum MappingError {
575 InvalidCode(ev::Code),
577 InvalidName,
579 NotImplemented,
581 NotConnected,
583 DuplicatedEntry,
585 UnknownElement,
587 NotSdl2Compatible,
589}
590
591impl Error for MappingError {}
592
593impl Display for MappingError {
594 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
595 let sbuf;
596 let s = match self {
597 MappingError::InvalidCode(code) => {
598 sbuf = format!("gamepad does not have element with {}", code);
599 sbuf.as_ref()
600 }
601 MappingError::InvalidName => "name can not contain comma",
602 MappingError::NotImplemented => {
603 "current platform does not implement setting custom mappings"
604 }
605 MappingError::NotConnected => "gamepad is not connected",
606 MappingError::DuplicatedEntry => {
607 "same gamepad element is referenced by axis and button"
608 }
609 MappingError::UnknownElement => "Button::Unknown and Axis::Unknown are not allowed",
610 MappingError::NotSdl2Compatible => "one of buttons or axes is not compatible with SDL2",
611 };
612
613 f.write_str(s)
614 }
615}
616
617#[cfg(test)]
618mod tests {
619 use super::*;
620 use crate::ev::{Axis, Button};
621 use gilrs_core::native_ev_codes as nec;
622 use gilrs_core::EvCode;
623 use uuid::Uuid;
624 const TEST_STR: &str = "03000000260900008888000000010001,GameCube {WiseGroup USB \
627 box},a:b0,b:b2,y:b3,x:b1,start:b7,rightshoulder:b6,dpup:h0.1,dpleft:\
628 h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,\
629 lefttrigger:a4,righttrigger:a5,";
630
631 const BUTTONS: [EvCode; 15] = [
632 nec::BTN_SOUTH,
633 nec::BTN_EAST,
634 nec::BTN_C,
635 nec::BTN_NORTH,
636 nec::BTN_WEST,
637 nec::BTN_Z,
638 nec::BTN_LT,
639 nec::BTN_RT,
640 nec::BTN_LT2,
641 nec::BTN_RT2,
642 nec::BTN_SELECT,
643 nec::BTN_START,
644 nec::BTN_MODE,
645 nec::BTN_LTHUMB,
646 nec::BTN_RTHUMB,
647 ];
648
649 const AXES: [EvCode; 12] = [
650 nec::AXIS_LSTICKX,
651 nec::AXIS_LSTICKY,
652 nec::AXIS_LEFTZ,
653 nec::AXIS_RSTICKX,
654 nec::AXIS_RSTICKY,
655 nec::AXIS_RIGHTZ,
656 nec::AXIS_DPADX,
657 nec::AXIS_DPADY,
658 nec::AXIS_RT,
659 nec::AXIS_LT,
660 nec::AXIS_RT2,
661 nec::AXIS_LT2,
662 ];
663
664 #[test]
665 fn mapping() {
666 Mapping::parse_sdl_mapping(TEST_STR, &BUTTONS, &AXES).unwrap();
667 }
668
669 #[test]
670 fn from_data() {
671 let uuid = Uuid::nil();
672 let name = "Best Gamepad";
673 let buttons = BUTTONS.iter().cloned().map(ev::Code).collect::<Vec<_>>();
674 let axes = AXES.iter().cloned().map(ev::Code).collect::<Vec<_>>();
675
676 let mut data = MappingData::new();
677 data.insert_axis(axes[0], Axis::LeftStickX);
678 data.insert_axis(axes[1], Axis::LeftStickY);
679 data.insert_axis(axes[2], Axis::LeftZ);
680 data.insert_axis(axes[3], Axis::RightStickX);
681 data.insert_axis(axes[4], Axis::RightStickY);
682 data.insert_axis(axes[5], Axis::RightZ);
683
684 data.insert_btn(buttons[0], Button::South);
685 data.insert_btn(buttons[1], Button::East);
686 data.insert_btn(buttons[3], Button::North);
687 data.insert_btn(buttons[4], Button::West);
688 data.insert_btn(buttons[5], Button::Select);
689 data.insert_btn(buttons[6], Button::Start);
690 data.insert_btn(buttons[7], Button::DPadDown);
691 data.insert_btn(buttons[8], Button::DPadLeft);
692 data.insert_btn(buttons[9], Button::RightThumb);
693
694 let (mappings, sdl_mappings) =
695 Mapping::from_data(&data, &BUTTONS, &AXES, name, uuid).unwrap();
696 let sdl_mappings = Mapping::parse_sdl_mapping(&sdl_mappings, &BUTTONS, &AXES).unwrap();
697 assert_eq!(mappings, sdl_mappings);
698
699 let incorrect_mappings = Mapping::from_data(&data, &BUTTONS, &AXES, "Inval,id name", uuid);
700 assert_eq!(Err(MappingError::InvalidName), incorrect_mappings);
701
702 data.insert_btn(ev::Code(nec::BTN_DPAD_RIGHT), Button::DPadRight);
703 let incorrect_mappings = Mapping::from_data(&data, &BUTTONS, &AXES, name, uuid);
704 assert_eq!(
705 Err(MappingError::InvalidCode(ev::Code(nec::BTN_DPAD_RIGHT))),
706 incorrect_mappings
707 );
708
709 data.insert_btn(ev::Code(BUTTONS[3]), Button::Unknown);
710 let incorrect_mappings = Mapping::from_data(&data, &BUTTONS, &AXES, name, uuid);
711 assert_eq!(Err(MappingError::UnknownElement), incorrect_mappings);
712 }
713
714 #[test]
715 fn with_mappings() {
716 let mappings = format!(
717 "\nShould be ignored\nThis also should,be ignored\n\n{}",
718 TEST_STR
719 );
720 let mut db = MappingDb::new();
721 db.add_included_mappings();
722 db.insert(&mappings);
723
724 assert_eq!(
725 Some(TEST_STR),
726 db.get(Uuid::parse_str("03000000260900008888000000010001").unwrap())
727 );
728 }
729}