Skip to main content

soundevents_dataset/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(feature = "std"), no_std)]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4#![cfg_attr(docsrs, allow(unused_attributes))]
5#![deny(missing_docs)]
6#![forbid(unsafe_code)]
7
8#[cfg(feature = "ontology")]
9#[cfg_attr(docsrs, doc(cfg(feature = "ontology")))]
10pub mod ontology;
11
12#[cfg(feature = "rated")]
13#[cfg_attr(docsrs, doc(cfg(feature = "rated")))]
14pub mod rated;
15
16#[cfg(feature = "ontology")]
17#[cfg_attr(docsrs, doc(cfg(feature = "ontology")))]
18pub use ontology::SoundEvent;
19
20#[cfg(feature = "rated")]
21#[cfg_attr(docsrs, doc(cfg(feature = "rated")))]
22pub use rated::RatedSoundEvent;
23
24/// Errors that can occur when parsing a [`Restriction`] from a string.
25#[derive(Debug, thiserror::Error, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
26#[error("unknown restriction: {0}")]
27pub struct UnknownRestriction<'a>(&'a str);
28
29impl<'a> UnknownRestriction<'a> {
30  /// Get the name associated with the `UnknownRestriction` error
31  #[cfg_attr(not(tarpaulin), inline(always))]
32  pub const fn name(&self) -> &'a str {
33    self.0
34  }
35}
36
37impl<'a> TryFrom<&'a str> for Restriction {
38  type Error = UnknownRestriction<'a>;
39
40  #[cfg_attr(not(tarpaulin), inline(always))]
41  fn try_from(value: &'a str) -> Result<Self, Self::Error> {
42    Ok(match value {
43      "abstract" | "ABSTRACT" | "Abstract" => Restriction::Abstract,
44      "blacklist" | "BLACKLIST" | "BlackList" | "blackList" | "Blacklist" => Restriction::Blacklist,
45      _ => return Err(UnknownRestriction(value)),
46    })
47  }
48}
49
50/// A restriction on a sound entry, which may be an abstract category or a blacklisted entry
51#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
52#[cfg_attr(feature = "serde", derive(serde::Serialize))]
53#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
54#[non_exhaustive]
55pub enum Restriction {
56  /// For a class that is principally a container within the hierarchy, but will not have any explicit examples for itself. "Human voice" is an abstract class. Abstract classes will always have children.
57  Abstract,
58  /// For classes that have been excluded from rating for the time being. These are classes that we found were too difficult for raters to mark reliably, or for which we had too much trouble finding candidates, or which we decided to drop from labeling for some other reason.
59  Blacklist,
60}
61
62impl core::fmt::Display for Restriction {
63  #[cfg_attr(not(tarpaulin), inline(always))]
64  fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
65    write!(f, "{}", self.as_str())
66  }
67}
68
69impl Restriction {
70  /// Get the string representation of the restriction
71  #[cfg_attr(not(tarpaulin), inline(always))]
72  pub const fn as_str(&self) -> &'static str {
73    match self {
74      Self::Abstract => "abstract",
75      Self::Blacklist => "blacklist",
76    }
77  }
78
79  /// Return `true` if the restriction is an abstract category
80  #[cfg_attr(not(tarpaulin), inline(always))]
81  pub const fn is_abstract(&self) -> bool {
82    matches!(self, Self::Abstract)
83  }
84
85  /// Return `true` if the restriction is a blacklisted entry.
86  #[cfg_attr(not(tarpaulin), inline(always))]
87  pub const fn is_blacklist(&self) -> bool {
88    matches!(self, Self::Blacklist)
89  }
90}
91
92/// Defines a sound-event struct (with all its accessors), its companion
93/// `Unknown*Code` error type, and `Display`. Used twice — once in the
94/// `ontology` module and once in the `rated` module — to produce two
95/// independent types with identical shape.
96#[cfg(any(feature = "ontology", feature = "rated"))]
97macro_rules! define_sound_event {
98  (
99    $(#[$struct_meta:meta])*
100    name: $name:ident,
101    $(#[$err_meta:meta])*
102    error: $err_name:ident,
103    error_message: $err_msg:literal
104    $(,
105      extra_fields: {
106        $($extra_field:tt)*
107      }
108    )?
109    $(,
110      extra_impl: {
111        $($extra_impl:tt)*
112      }
113    )?
114    $(,)?
115  ) => {
116    $(#[$struct_meta])*
117    #[derive(Debug, Clone, PartialEq, Eq, Hash)]
118    #[cfg_attr(feature = "serde", derive(serde::Serialize))]
119    pub struct $name {
120      #[cfg_attr(feature = "serde", serde(skip))]
121      pub(crate) code: u64,
122      pub(crate) id: &'static str,
123      pub(crate) name: &'static str,
124      #[cfg_attr(feature = "serde", serde(skip_serializing_if = "<[_]>::is_empty"))]
125      pub(crate) aliases: &'static [&'static str],
126      pub(crate) description: &'static str,
127      #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
128      pub(crate) citation_uri: ::core::option::Option<&'static str>,
129      #[cfg_attr(feature = "serde", serde(skip_serializing_if = "<[_]>::is_empty"))]
130      pub(crate) children: &'static [&'static $name],
131      #[cfg_attr(feature = "serde", serde(skip_serializing_if = "<[_]>::is_empty"))]
132      pub(crate) restrictions: &'static [$crate::Restriction],
133      $($($extra_field)*)?
134    }
135
136    impl ::core::fmt::Display for $name {
137      #[cfg_attr(not(tarpaulin), inline(always))]
138      fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
139        f.write_str(self.name)
140      }
141    }
142
143    impl $name {
144      /// Get the unique code for the sound entry, which is a hash of its name.
145      #[cfg_attr(not(tarpaulin), inline(always))]
146      pub const fn encode(&self) -> u64 {
147        self.code
148      }
149
150      /// Get the sound entry's id
151      #[cfg_attr(not(tarpaulin), inline(always))]
152      pub const fn id(&self) -> &'static str {
153        self.id
154      }
155
156      /// Get the sound entry's name
157      #[cfg_attr(not(tarpaulin), inline(always))]
158      pub const fn name(&self) -> &'static str {
159        self.name
160      }
161
162      /// Get the sound entry's description
163      #[cfg_attr(not(tarpaulin), inline(always))]
164      pub const fn description(&self) -> &'static str {
165        self.description
166      }
167
168      /// Get the sound entry's aliases
169      #[cfg_attr(not(tarpaulin), inline(always))]
170      pub const fn aliases(&self) -> &'static [&'static str] {
171        self.aliases
172      }
173
174      /// Get the sound entry's citation url, if any
175      #[cfg_attr(not(tarpaulin), inline(always))]
176      pub const fn citation_uri(&self) -> ::core::option::Option<&'static str> {
177        self.citation_uri
178      }
179
180      /// Get the sound entry's children sound entries
181      #[cfg_attr(not(tarpaulin), inline(always))]
182      pub const fn children(&self) -> &'static [&'static Self] {
183        self.children
184      }
185
186      /// Get the sound entry's restrictions
187      #[cfg_attr(not(tarpaulin), inline(always))]
188      pub const fn restrictions(&self) -> &'static [$crate::Restriction] {
189        self.restrictions
190      }
191
192      $($($extra_impl)*)?
193    }
194
195    $(#[$err_meta])*
196    #[derive(Debug, ::thiserror::Error, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
197    #[error($err_msg)]
198    pub struct $err_name(pub(crate) u64);
199
200    impl $err_name {
201      /// Get the code associated with this error.
202      #[cfg_attr(not(tarpaulin), inline(always))]
203      pub const fn code(&self) -> u64 {
204        self.0
205      }
206    }
207  };
208}
209
210#[cfg(any(feature = "ontology", feature = "rated"))]
211pub(crate) use define_sound_event;