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