use crate::error::OpsviewConfigError;
use serde::de::{self, MapAccess, Visitor};
use serde::ser::SerializeStruct;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use strum::IntoEnumIterator;
use strum_macros::{AsRefStr, Display, EnumIter, EnumString, VariantNames};
#[allow(missing_docs)]
#[non_exhaustive] #[derive(Clone, Debug, PartialEq, Eq, EnumString, VariantNames, AsRefStr, EnumIter, Display)]
#[strum(serialize_all = "kebab-case")]
pub enum FontAwesomeIcon {
#[strum(serialize = "500px")]
FiveHundredPx,
Adjust,
Adn,
AlignCenter,
AlignJustify,
AlignLeft,
AlignRight,
Amazon,
Ambulance,
Anchor,
Android,
Angellist,
AngleDoubleDown,
AngleDoubleLeft,
AngleDoubleRight,
AngleDoubleUp,
AngleDown,
AngleLeft,
AngleRight,
AngleUp,
Apple,
Archive,
AreaChart,
ArrowCircleDown,
ArrowCircleLeft,
ArrowCircleODown,
ArrowCircleOLeft,
ArrowCircleORight,
ArrowCircleOUp,
ArrowCircleRight,
ArrowCircleUp,
ArrowDown,
ArrowLeft,
ArrowRight,
ArrowUp,
Arrows,
ArrowsAlt,
ArrowsH,
ArrowsV,
Asterisk,
At,
Automobile,
Backward,
BalanceScale,
Ban,
Bank,
BarChart,
BarChartO,
Barcode,
Bars,
Battery0,
Battery1,
Battery2,
Battery3,
Battery4,
BatteryEmpty,
BatteryFull,
BatteryHalf,
BatteryQuarter,
BatteryThreeQuarters,
Bed,
Beer,
Behance,
BehanceSquare,
Bell,
BellO,
BellSlash,
BellSlashO,
Bicycle,
Binoculars,
BirthdayCake,
Bitbucket,
BitbucketSquare,
Bitcoin,
BlackTie,
Bluetooth,
BluetoothB,
Bold,
Bolt,
Bomb,
Book,
Bookmark,
BookmarkO,
Briefcase,
Btc,
Bug,
Building,
BuildingO,
Bullhorn,
Bullseye,
Bus,
Buysellads,
Cab,
Calculator,
Calendar,
CalendarCheckO,
CalendarMinusO,
CalendarO,
CalendarPlusO,
CalendarTimesO,
Camera,
CameraRetro,
Car,
CaretDown,
CaretLeft,
CaretRight,
CaretSquareODown,
CaretSquareOLeft,
CaretSquareORight,
CaretSquareOUp,
CaretUp,
CartArrowDown,
CartPlus,
Cc,
CcAmex,
CcDinersClub,
CcDiscover,
CcJcb,
CcMastercard,
CcPaypal,
CcStripe,
CcVisa,
Certificate,
Chain,
ChainBroken,
Check,
CheckCircle,
CheckCircleO,
CheckSquare,
CheckSquareO,
ChevronCircleDown,
ChevronCircleLeft,
ChevronCircleRight,
ChevronCircleUp,
ChevronDown,
ChevronLeft,
ChevronRight,
ChevronUp,
Child,
Chrome,
Circle,
CircleO,
CircleONotch,
CircleThin,
Clipboard,
ClockO,
Clone,
Close,
Cloud,
CloudDownload,
CloudUpload,
Cny,
Code,
CodeFork,
Codepen,
Codiepie,
Coffee,
Cog,
Cogs,
Columns,
Comment,
CommentO,
Commenting,
CommentingO,
Comments,
CommentsO,
Compass,
Compress,
Connectdevelop,
Contao,
Copy,
Copyright,
CreativeCommons,
CreditCard,
CreditCardAlt,
Crop,
Crosshairs,
Css3,
Cube,
Cubes,
Cut,
Cutlery,
Dashboard,
Dashcube,
Database,
Dedent,
Delicious,
Desktop,
Deviantart,
Diamond,
Digg,
Dollar,
DotCircleO,
Download,
Dribbble,
Dropbox,
Drupal,
Edge,
Edit,
Eject,
EllipsisH,
EllipsisV,
Empire,
Envelope,
EnvelopeO,
EnvelopeSquare,
Eraser,
Eur,
Euro,
Exchange,
Exclamation,
ExclamationCircle,
ExclamationTriangle,
Expand,
Expeditedssl,
ExternalLink,
ExternalLinkSquare,
Eye,
EyeSlash,
Eyedropper,
Facebook,
FacebookF,
FacebookOfficial,
FacebookSquare,
FastBackward,
FastForward,
Fax,
Feed,
Female,
FighterJet,
File,
FileArchiveO,
FileAudioO,
FileCodeO,
FileExcelO,
FileImageO,
FileMovieO,
FileO,
FilePdfO,
FilePhotoO,
FilePictureO,
FilePowerpointO,
FileSoundO,
FileText,
FileTextO,
FileVideoO,
FileWordO,
FileZipO,
FilesO,
Film,
Filter,
Fire,
FireExtinguisher,
Firefox,
Flag,
FlagCheckered,
FlagO,
Flash,
Flask,
Flickr,
FloppyO,
Folder,
FolderO,
FolderOpen,
FolderOpenO,
Font,
Fonticons,
FortAwesome,
Forumbee,
Forward,
Foursquare,
FrownO,
FutbolO,
Gamepad,
Gavel,
Gbp,
Ge,
Gear,
Gears,
Genderless,
GetPocket,
Gg,
GgCircle,
Gift,
Git,
GitSquare,
Github,
GithubAlt,
GithubSquare,
Gittip,
Glass,
Globe,
Google,
GooglePlus,
GooglePlusSquare,
GoogleWallet,
GraduationCap,
Gratipay,
Group,
HSquare,
HackerNews,
HandGrabO,
HandLizardO,
HandODown,
HandOLeft,
HandORight,
HandOUp,
HandPaperO,
HandPeaceO,
HandPointerO,
HandRockO,
HandScissorsO,
HandSpockO,
HandStopO,
Hashtag,
HddO,
Header,
Headphones,
Heart,
HeartO,
Heartbeat,
History,
Home,
HospitalO,
Hotel,
Hourglass,
Hourglass1,
Hourglass2,
Hourglass3,
HourglassEnd,
HourglassHalf,
HourglassO,
HourglassStart,
Houzz,
Html5,
ICursor,
Ils,
Image,
Inbox,
Indent,
Industry,
Info,
InfoCircle,
Inr,
Instagram,
Institution,
InternetExplorer,
Intersex,
Ioxhost,
Italic,
Joomla,
Jpy,
Jsfiddle,
Key,
KeyboardO,
Krw,
Language,
Laptop,
Lastfm,
LastfmSquare,
Leaf,
Leanpub,
Legal,
LemonO,
LevelDown,
LevelUp,
LifeBouy,
LifeBuoy,
LifeRing,
LifeSaver,
LightbulbO,
LineChart,
Link,
Linkedin,
LinkedinSquare,
Linux,
List,
ListAlt,
ListOl,
ListUl,
LocationArrow,
Lock,
LongArrowDown,
LongArrowLeft,
LongArrowRight,
LongArrowUp,
Magic,
Magnet,
MailForward,
MailReply,
MailReplyAll,
Male,
Map,
MapMarker,
MapO,
MapPin,
MapSigns,
Mars,
MarsDouble,
MarsStroke,
MarsStrokeH,
MarsStrokeV,
Maxcdn,
Meanpath,
Medium,
Medkit,
MehO,
Mercury,
Microphone,
MicrophoneSlash,
Minus,
MinusCircle,
MinusSquare,
MinusSquareO,
Mixcloud,
Mobile,
MobilePhone,
Modx,
Money,
MoonO,
MortarBoard,
Motorcycle,
MousePointer,
Music,
Navicon,
Neuter,
NewspaperO,
ObjectGroup,
ObjectUngroup,
Odnoklassniki,
OdnoklassnikiSquare,
Opencart,
Openid,
Opera,
OptinMonster,
Outdent,
Pagelines,
PaintBrush,
PaperPlane,
PaperPlaneO,
Paperclip,
Paragraph,
Paste,
Pause,
PauseCircle,
PauseCircleO,
Paw,
Paypal,
Pencil,
PencilSquare,
PencilSquareO,
Percent,
Phone,
PhoneSquare,
Photo,
PictureO,
PieChart,
PiedPiper,
PiedPiperAlt,
Pinterest,
PinterestP,
PinterestSquare,
Plane,
Play,
PlayCircle,
PlayCircleO,
Plug,
Plus,
PlusCircle,
PlusSquare,
PlusSquareO,
PowerOff,
Print,
ProductHunt,
PuzzlePiece,
Qq,
Qrcode,
Question,
QuestionCircle,
QuoteLeft,
QuoteRight,
Ra,
Random,
Rebel,
Recycle,
Reddit,
RedditAlien,
RedditSquare,
Refresh,
Registered,
Remove,
Renren,
Reorder,
Repeat,
Reply,
ReplyAll,
Retweet,
Rmb,
Road,
Rocket,
RotateLeft,
RotateRight,
Rouble,
Rss,
RssSquare,
Rub,
Ruble,
Rupee,
Safari,
Save,
Scissors,
Scribd,
Search,
SearchMinus,
SearchPlus,
Sellsy,
Send,
SendO,
Server,
Share,
ShareAlt,
ShareAltSquare,
ShareSquare,
ShareSquareO,
Shekel,
Sheqel,
Shield,
Ship,
Shirtsinbulk,
ShoppingBag,
ShoppingBasket,
ShoppingCart,
SignIn,
SignOut,
Signal,
Simplybuilt,
Sitemap,
Skyatlas,
Skype,
Slack,
Sliders,
Slideshare,
SmileO,
SoccerBallO,
Sort,
SortAlphaAsc,
SortAlphaDesc,
SortAmountAsc,
SortAmountDesc,
SortAsc,
SortDesc,
SortDown,
SortNumericAsc,
SortNumericDesc,
SortUp,
Soundcloud,
SpaceShuttle,
Spinner,
Spoon,
Spotify,
Square,
SquareO,
StackExchange,
StackOverflow,
Star,
StarHalf,
StarHalfEmpty,
StarHalfFull,
StarHalfO,
StarO,
Steam,
SteamSquare,
StepBackward,
StepForward,
Stethoscope,
StickyNote,
StickyNoteO,
Stop,
StopCircle,
StopCircleO,
StreetView,
Strikethrough,
Stumbleupon,
StumbleuponCircle,
Subscript,
Subway,
Suitcase,
SunO,
Superscript,
Support,
Table,
Tablet,
Tachometer,
Tag,
Tags,
Tasks,
Taxi,
Television,
TencentWeibo,
Terminal,
TextHeight,
TextWidth,
Th,
ThLarge,
ThList,
ThumbTack,
ThumbsDown,
ThumbsODown,
ThumbsOUp,
ThumbsUp,
Ticket,
Times,
TimesCircle,
TimesCircleO,
Tint,
ToggleDown,
ToggleLeft,
ToggleOff,
ToggleOn,
ToggleRight,
ToggleUp,
Trademark,
Train,
Transgender,
TransgenderAlt,
Trash,
TrashO,
Tree,
Trello,
Tripadvisor,
Trophy,
Truck,
Try,
Tty,
Tumblr,
TumblrSquare,
TurkishLira,
Tv,
Twitch,
Twitter,
TwitterSquare,
Umbrella,
Underline,
Undo,
University,
Unlink,
Unlock,
UnlockAlt,
Unsorted,
Upload,
Usb,
Usd,
User,
UserMd,
UserPlus,
UserSecret,
UserTimes,
Users,
Venus,
VenusDouble,
VenusMars,
Viacoin,
VideoCamera,
Vimeo,
VimeoSquare,
Vine,
Vk,
VolumeDown,
VolumeOff,
VolumeUp,
Warning,
Wechat,
Weibo,
Weixin,
Whatsapp,
Wheelchair,
Wifi,
WikipediaW,
Windows,
Won,
Wordpress,
Wrench,
Xing,
XingSquare,
YCombinator,
YCombinatorSquare,
Yahoo,
Yc,
YcSquare,
Yelp,
Yen,
Youtube,
YoutubePlay,
YoutubeSquare,
}
struct FontAwesomeIconApi {
name: String,
ref_: String,
}
impl FontAwesomeIcon {
fn to_api(&self) -> FontAwesomeIconApi {
FontAwesomeIconApi {
name: self.to_string(),
ref_: format!("/rest/config/fontawesomeicon/{}", self.variant_index() + 1),
}
}
fn from_kebab_case(name: &str) -> Result<Self, OpsviewConfigError> {
FontAwesomeIcon::iter()
.find(|variant| variant.as_ref() == name)
.ok_or(OpsviewConfigError::UnknownFontAwesomeIcon(name.to_string()))
}
fn variant_index(&self) -> usize {
FontAwesomeIcon::iter()
.position(|variant| variant == *self)
.unwrap()
}
}
impl Serialize for FontAwesomeIcon {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let icon_api = self.to_api();
let mut state = serializer.serialize_struct("FontAwesomeIconApi", 2)?;
state.serialize_field("name", &icon_api.name)?;
state.serialize_field("ref", &icon_api.ref_)?;
state.end()
}
}
impl<'de> Deserialize<'de> for FontAwesomeIcon {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(field_identifier, rename_all = "lowercase")]
enum Field {
Name,
Ref,
}
struct FontAwesomeIconVisitor;
impl<'de> Visitor<'de> for FontAwesomeIconVisitor {
type Value = FontAwesomeIcon;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct FontAwesomeIconApi")
}
fn visit_map<V>(self, mut map: V) -> Result<FontAwesomeIcon, V::Error>
where
V: MapAccess<'de>,
{
let mut name = None;
let mut ref_ = None;
while let Some(key) = map.next_key()? {
match key {
Field::Name => {
if name.is_some() {
return Err(de::Error::duplicate_field("name"));
}
name = Some(map.next_value()?);
}
Field::Ref => {
if ref_.is_some() {
return Err(de::Error::duplicate_field("ref"));
}
ref_ = Some(map.next_value()?);
}
}
}
let name: String = name.ok_or_else(|| de::Error::missing_field("name"))?;
let _ref: String = ref_.ok_or_else(|| de::Error::missing_field("ref"))?;
FontAwesomeIcon::from_kebab_case(&name)
.map_err(|_| de::Error::custom("Unknown FontAwesomeIcon name"))
}
}
const FIELDS: &[&str] = &["name", "ref"];
deserializer.deserialize_struct("FontAwesomeIconApi", FIELDS, FontAwesomeIconVisitor)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_to_api() {
let api = FontAwesomeIcon::Adjust.to_api();
assert_eq!(api.name, "adjust");
assert_eq!(api.ref_, "/rest/config/fontawesomeicon/2");
}
#[test]
fn test_from_kebab_case() {
let icon = FontAwesomeIcon::from_kebab_case("adjust").unwrap();
assert!(matches!(icon, FontAwesomeIcon::Adjust));
let unknown_icon = FontAwesomeIcon::from_kebab_case("unknown");
assert!(unknown_icon.is_err());
}
#[test]
fn test_display() {
assert_eq!(FontAwesomeIcon::Adjust.to_string(), "adjust");
assert_eq!(FontAwesomeIcon::YoutubeSquare.to_string(), "youtube-square");
assert_eq!(FontAwesomeIcon::FiveHundredPx.to_string(), "500px");
}
#[test]
fn test_deserialize_and_serialize() {
let test_icons = [
r#"{"name":"500px","ref":"/rest/config/fontawesomeicon/1"}"#,
r#"{"name":"adjust","ref":"/rest/config/fontawesomeicon/2"}"#,
r#"{"name":"youtube-square","ref":"/rest/config/fontawesomeicon/694"}"#,
];
for json in test_icons {
let deserialized_icon: FontAwesomeIcon = serde_json::from_str(json).unwrap();
println!("deserialized_icon: {:?}", deserialized_icon);
let serialized_icon = serde_json::to_string(&deserialized_icon).unwrap();
println!("serialized_icon: {:?}", serialized_icon);
assert_eq!(&serialized_icon, json);
}
}
}