Make strum_macros update with strum.

Accordingly, update strum_macros to 0.27.1 to match strum.

Test: treehugger
Change-Id: Ieeaf99c93e10d4b084b9c8f253e6efc9cdfc8a5c
diff --git a/crates/strum/.android-checksum.json b/crates/strum/.android-checksum.json
index d1db01e..578f383 100644
--- a/crates/strum/.android-checksum.json
+++ b/crates/strum/.android-checksum.json
@@ -1 +1 @@
-{"package":null,"files":{".cargo-checksum.json":"01c8cea6f4f78999eef4c846985f21fad83b7209ff32ccfd2c931d04fdc1edf5","Android.bp":"9cca58ae0552b26d30ab260887aa8921ac8f03448cce29e7ebdb2a0ae776d4af","Cargo.toml":"2f79195a448fa01a3c78dff2c62ac68ea5be6347cdfc20c6c8b6c50dae03024e","LICENSE":"1884079d8260fd6643f913346f742df6dabc32a0d1d1a973f6c70b2ae20383fe","METADATA":"4b7fef6289da6bbdd50c2c24fea739346deaad6b21c73e183a3dabfe0e7c4d02","MODULE_LICENSE_MIT":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","README.md":"bc5a072044da2a52d2a656564d830e2960cfb8f242a68812cb03290cb7b247b2","cargo_embargo.json":"aa45a963da01d3f018be316cd5b7646a5b413ce2611c5218f2914d2e8a9efd0e","src/additional_attributes.rs":"fc2e26c26de442bf925fc69a1ce5091d49639e08bd7611318abd28c815affcf1","src/lib.rs":"8a635261891a311a737235ba8f92d006f4d8c3af879c9cffd2841a86cdb0ff07"}}
\ No newline at end of file
+{"package":null,"files":{".cargo-checksum.json":"01c8cea6f4f78999eef4c846985f21fad83b7209ff32ccfd2c931d04fdc1edf5","Android.bp":"9cca58ae0552b26d30ab260887aa8921ac8f03448cce29e7ebdb2a0ae776d4af","Cargo.toml":"2f79195a448fa01a3c78dff2c62ac68ea5be6347cdfc20c6c8b6c50dae03024e","LICENSE":"1884079d8260fd6643f913346f742df6dabc32a0d1d1a973f6c70b2ae20383fe","METADATA":"4b7fef6289da6bbdd50c2c24fea739346deaad6b21c73e183a3dabfe0e7c4d02","MODULE_LICENSE_MIT":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","README.md":"bc5a072044da2a52d2a656564d830e2960cfb8f242a68812cb03290cb7b247b2","android_config.toml":"9653479b2e5807b447bc6d909d4de097906bb43f6bb6a9ff3c97bab55df52f7b","cargo_embargo.json":"aa45a963da01d3f018be316cd5b7646a5b413ce2611c5218f2914d2e8a9efd0e","src/additional_attributes.rs":"fc2e26c26de442bf925fc69a1ce5091d49639e08bd7611318abd28c815affcf1","src/lib.rs":"8a635261891a311a737235ba8f92d006f4d8c3af879c9cffd2841a86cdb0ff07"}}
\ No newline at end of file
diff --git a/crates/strum/android_config.toml b/crates/strum/android_config.toml
new file mode 100644
index 0000000..7dbab26
--- /dev/null
+++ b/crates/strum/android_config.toml
@@ -0,0 +1 @@
+update_with = ["strum_macros"]
diff --git a/crates/strum_macros/.android-checksum.json b/crates/strum_macros/.android-checksum.json
index a948d6c..d594c80 100644
--- a/crates/strum_macros/.android-checksum.json
+++ b/crates/strum_macros/.android-checksum.json
@@ -1 +1 @@
-{"package":null,"files":{".cargo-checksum.json":"2a77879144dd02a4809a1cfd0b85ac8b220c32e21f7b0fc5bcfebeb40891b876","Android.bp":"7f36d73f0ae45a174d2e526edcfda3e9dba9013cf8862dba787c538f02a89851","Cargo.toml":"137ea4cd60ce441852ce8b9fa8f28991a772a52b018ef8732b5407c628166abb","LICENSE":"1884079d8260fd6643f913346f742df6dabc32a0d1d1a973f6c70b2ae20383fe","METADATA":"19f6922bf713cebe4639d26b8eec0aef31a5828908302c1833a9eee30fbc29d7","MODULE_LICENSE_MIT":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","README.md":"97422babc5ef03a7347fd1efe7c6866a231925d7e436e7f9f38caaaa0ed464a9","TEST_MAPPING":"130934553eb809f532f064b6d924421ef21dc989325f59a50bd6f726f2cba884","cargo_embargo.json":"fa702ccdadce959e0baa3621834e37c34b5b20d1d2993055e3efbb9ad62a03b8","src/helpers/case_style.rs":"a401e30dc1198a382681dfbc7edabe641df80e6717b6b57ad3d8f9d3457c24ca","src/helpers/inner_variant_props.rs":"fb25aac1a36405f4912d239241ed50d304946b3bdff79bd90466b41fa99785cc","src/helpers/metadata.rs":"abb82cefe57fc10d87c4fe5a4846eacd97ca3306851e28b7c7699fbdec412ddf","src/helpers/mod.rs":"928c2e83113fac0183b291b2e064bd6444140698e4b4f2410e55d85ea1deab28","src/helpers/type_props.rs":"9f7227dfe0f9ab4f1ee4dfdcb960c49db4706497861ae82cc9a9db904287ebab","src/helpers/variant_props.rs":"c007bed549c30a6c9a64521639608e7dd3e6f9c70553ec78a183ebda02bddd54","src/lib.rs":"d8aef53e8def3751c9f11b73f1bb9929e38cb11573072539aeaadeeec19f60e1","src/macros/enum_count.rs":"c3f068684816e891171537745c5a4a86bbb76f74578e079880a874ef0d1e7fc5","src/macros/enum_discriminants.rs":"d80616c8889ace6e1f1e8eb036140a7127bb0a536414a20cc984933b72aa41c0","src/macros/enum_is.rs":"a67764b68d10774516aec79b4a121aa8526b85c1ba4eb19406ea839925ac2fbf","src/macros/enum_iter.rs":"aded711dc8a9c334f5ac9882a6c745f48148c98f95fae1634ff01eae4eb43909","src/macros/enum_messages.rs":"ad5fc215c0e992dc09024c3ad76b8bd18a56147170bab71ab964e58c44e82cad","src/macros/enum_properties.rs":"c1a386c408a09b7af7754b0e28220ebae02abd75b123d0edac8a0f00880a633b","src/macros/enum_table.rs":"8002a82697ae43cba9cbb77baf3c6aa60f810f948c7ca97d46f0a2a96e5dbdfe","src/macros/enum_try_as.rs":"6299527af91a6478ca48c56871c2649cb19eaa371186b08b81fc21bea76b18c6","src/macros/enum_variant_array.rs":"4a82897758e6059aae96e8d999e7c69e226bd61fe54c0d9cf610bdfd38e407b9","src/macros/enum_variant_names.rs":"9c3bac48f80b7aab75d779377de56ba143e7f831d659bb4e1070ee4e6181d2fe","src/macros/from_repr.rs":"83b62edd8bfe91db286bd1531a77082d30d4f9d4ee8185f7a95689fa4860365f","src/macros/mod.rs":"d3f44f5625d76d0f114ff394d6b95723ca9f6b2a089784c09b12dab42f54cc47","src/macros/strings/as_ref_str.rs":"9f7b73f0848d346f54f0efb78de66da53c29b4d22386075554eed603e4fdb93d","src/macros/strings/display.rs":"cca176648abedbed3955ae5cbd254ea8c2dd0d8f8b3b134914258e13dea0b0a4","src/macros/strings/from_string.rs":"913f990421d76985c4a609fc13d58f31c7b25dfc48f37c564feaf48a61e66fe0","src/macros/strings/mod.rs":"5f0003e2cb561686d347d008fd890d52a691e40bdbeef8a36fadc11512abcfbe","src/macros/strings/to_string.rs":"ef77f2087f20dfc2775324e99e178bc40831c1a3017de1a58104b901daced823"}}
\ No newline at end of file
+{"package":null,"files":{".cargo-checksum.json":"1d8e73d5c55a6513198141ed2cf6fa27617169585d8518d73b4e304c54390708","Android.bp":"5bd38a3eeeee7340b6b75845974bde91cd01a62539e32036cb49a93a0558ac6b","Cargo.toml":"06632f61ac20770365030a7dbd1affcdf505cfd9cfa20269e864abcc07d84f9e","LICENSE":"1884079d8260fd6643f913346f742df6dabc32a0d1d1a973f6c70b2ae20383fe","METADATA":"f9a7cfb46e7b7fdfeb5d67d1ee9aeab98bb29c5ca0ec0e54465308538bccf8ed","MODULE_LICENSE_MIT":"0d6f8afa3940b7f06bebee651376d43bc8b0d5b437337be2696d30377451e93a","README.md":"bc5a072044da2a52d2a656564d830e2960cfb8f242a68812cb03290cb7b247b2","TEST_MAPPING":"130934553eb809f532f064b6d924421ef21dc989325f59a50bd6f726f2cba884","cargo_embargo.json":"fa702ccdadce959e0baa3621834e37c34b5b20d1d2993055e3efbb9ad62a03b8","src/helpers/case_style.rs":"a401e30dc1198a382681dfbc7edabe641df80e6717b6b57ad3d8f9d3457c24ca","src/helpers/inner_variant_props.rs":"1654fe72b87e6cc7806e4169727a4715f3bd33820c592db5ec6d72e6e3b35c49","src/helpers/metadata.rs":"31ba36e56052b96908f85095bec8876e08e7cc28968015d7ae0f9d8fcc30bb44","src/helpers/mod.rs":"9f40e9f1ac4e34b1af4d78be2ff89dced14e08a4ffcc0ce1f16833fefedff3fc","src/helpers/type_props.rs":"b4aa27f2cf6703eeda71d919300fc55a74bb3c1ca67b15f0c77a98d062521075","src/helpers/variant_props.rs":"fa790a9bc7c2690b697b0efe416dccdb5e5808e587dfa8a0586f94d2d54beabd","src/lib.rs":"9e80e54e65916686c41c2752fcf2cb9dd3889ced1041e3aa248bda341a309b89","src/macros/enum_count.rs":"c3f068684816e891171537745c5a4a86bbb76f74578e079880a874ef0d1e7fc5","src/macros/enum_discriminants.rs":"6ad2e73219f48f8a9def9e4e2bfc51719b2c560ebce3bfab323271df9941f57b","src/macros/enum_is.rs":"a67764b68d10774516aec79b4a121aa8526b85c1ba4eb19406ea839925ac2fbf","src/macros/enum_iter.rs":"b040954e5e3ef6987b7d22ae1b34ce879579f5a18111b90a4c59c1298690c2a0","src/macros/enum_messages.rs":"1b2680ec9f423120c012640f971690be2dd22d88cddb194d22f99a939b365049","src/macros/enum_properties.rs":"fd3a1bb536c356c4ab3e64b62385c92ea7a903a599e795ab4bc80dbb55dbb085","src/macros/enum_table.rs":"0fff3e080937fed589e21eef15b2016b365bcea1339daa8f6017ffdc5f38732b","src/macros/enum_try_as.rs":"c486284310825ccb6f40e835d664999056d302254ee4b9539dab45a6c9559e01","src/macros/enum_variant_array.rs":"4a82897758e6059aae96e8d999e7c69e226bd61fe54c0d9cf610bdfd38e407b9","src/macros/enum_variant_names.rs":"9c3bac48f80b7aab75d779377de56ba143e7f831d659bb4e1070ee4e6181d2fe","src/macros/from_repr.rs":"7045d34969935d2dbe0b81c34e56585cc0f72209bb49f7d31d988a7325457a43","src/macros/mod.rs":"d3f44f5625d76d0f114ff394d6b95723ca9f6b2a089784c09b12dab42f54cc47","src/macros/strings/as_ref_str.rs":"78e9be641e2717368d4a010ded162145d31e23fc8a4cf31b0441a7bbae69cb77","src/macros/strings/display.rs":"74f3502d7a5c1d55fb02d49fdba112b014806df7bfdef8e6ae96f635294193d6","src/macros/strings/from_string.rs":"16e8322c326e6e92980a9973d99908a79fc16d075e9e5f9af368eb1cf68a272b","src/macros/strings/mod.rs":"40cff9e434a44ec4b8bb8e184d47ed15a1ad361b1dbcecabf3ac50025e3db1db","src/macros/strings/to_string.rs":"ef77f2087f20dfc2775324e99e178bc40831c1a3017de1a58104b901daced823"}}
\ No newline at end of file
diff --git a/crates/strum_macros/.cargo-checksum.json b/crates/strum_macros/.cargo-checksum.json
index 1ba0b9c..d581966 100644
--- a/crates/strum_macros/.cargo-checksum.json
+++ b/crates/strum_macros/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"8ec1aea0236e97817ede93c32ac56fcd04bf9cc561fa8a553ea329fa0fa639e2","LICENSE":"8bce3b45e49ecd1461f223b46de133d8f62cd39f745cfdaf81bee554b908bd42","README.md":"df67b984209ce474de5d60994983f6d2db0ac3b73bcfc2b1329871b0035c57e6","src/helpers/case_style.rs":"ac429454fad24d1a5a9829711f2024ae9477ffad7cc293b711fe588d1a5e1edf","src/helpers/inner_variant_props.rs":"09c4a2c73aadaaa934e6a20b429b99d4229ce76a4cc1edc916298100d971deb4","src/helpers/metadata.rs":"a9391071f1d4750781eda79bdf4553e77c65c28b1df87dfb3d00df6b290c18dd","src/helpers/mod.rs":"dc171dd27e723aede6c45cb981d48c710f42167afb06a5fbf013470a2962b9f2","src/helpers/type_props.rs":"cb1cdfb0e7927d3b0e364237e7048285ef5968e036d2ebacea642c66d96cc669","src/helpers/variant_props.rs":"36cc466e29b20246f87b9b87d39e4d23545596c522a201e0fb320ac2b231b045","src/lib.rs":"6b3d94635c078f4659500e31c3b682be6a64b5fb4b757e34d9aae3fa37afc10e","src/macros/enum_count.rs":"44084ab800ca8fca3b17f76c6025e8e59855598c0119807ce7bc80d5dc345d99","src/macros/enum_discriminants.rs":"98abbefad100dda4aaafa959ebb9fa77f518dd483414113e6c8bd1eea193bdff","src/macros/enum_is.rs":"cd63fb79f4f9b3479f11bce2ad45d3cb5d23f1d5c9c2a5fbb7af7e813fb70fa7","src/macros/enum_iter.rs":"462f949e7cb4ff3b7a7e30b723a3f86609e0e14c0f8e6b76e095376b0277396d","src/macros/enum_messages.rs":"ee89c3a10ebb553aa9c342f4b3b4346e97be1744fc5df72f580a331d4ea87393","src/macros/enum_properties.rs":"a9e1bf27504d46df689aad8910c7ad8ae7b3780ee97b6e659b2b19e481474030","src/macros/enum_table.rs":"434da77cbca12082d4daeba28ef0e416cea3064f1f641b31f4a330589369e04f","src/macros/enum_try_as.rs":"8bd311522786f0186290ea31a6f3483aa3fa23ccb3441b7fcf9b3743c9d3670b","src/macros/enum_variant_array.rs":"cb8de5cb5841fa9514c423c195b47a2fc13b9f5fb257093311fbb9c136c737d9","src/macros/enum_variant_names.rs":"ad4d2f87bf26e4d07327896118382a4b83c2cca5de6fdfecca6e7639eb73118b","src/macros/from_repr.rs":"561a6f10372c365674e064b31c6eb4c531ffa0b39f03476452bb0746201d579d","src/macros/mod.rs":"c94b29d4ad0f40a7803605d42647cc9fafec76545c7f3c435fe675a3102eb0ef","src/macros/strings/as_ref_str.rs":"594f29efd111ceef258ab0dd449db4cb52e638e1bd17efe589c5a90ee03686b9","src/macros/strings/display.rs":"5e466307196c428da9d31f8e7db46976a077d3e48805d93fa8a178563cc5b599","src/macros/strings/from_string.rs":"53d298f6859df3c13197a8bd303971d2a9ac14cb9860ea1e7c4df1bffdea58bd","src/macros/strings/mod.rs":"b7937f72a46c807fd87c787f3d23029509565a0388a30106e7026363782f2b56","src/macros/strings/to_string.rs":"983e6c1b1dec145acfa0c6a7ef8ff01d30507145753a1d85d0387c5ab61f6fa1"},"package":"4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"}
\ No newline at end of file
+{"files":{"Cargo.toml":"5462d13348e20938685838699bb51ca8c33d2f3156d3d39a43f73894e019e23e","LICENSE":"8bce3b45e49ecd1461f223b46de133d8f62cd39f745cfdaf81bee554b908bd42","README.md":"fbde582a544c0f2a60eb2b274ef60bbab5cf6f527e4dba0170e440898a8e10c5","src/helpers/case_style.rs":"ac429454fad24d1a5a9829711f2024ae9477ffad7cc293b711fe588d1a5e1edf","src/helpers/inner_variant_props.rs":"70f8056195979cc700717f0eed5743c9320246bd3dda675429ad3bacffe26ad5","src/helpers/metadata.rs":"ad83eeedec42e122a36f9207f4a8fee5f25728f8d22886f93487376a3bbcbb01","src/helpers/mod.rs":"205eb143d1ae494333a5ce2f254bf6f1fbe73dec925075fc6cc5e34df9db46b5","src/helpers/type_props.rs":"62ad9f5caa67bc86b3b8ab340f19df787bd6b5d54ab629a088f7e1f3269970d8","src/helpers/variant_props.rs":"3b12e69e354b9966281d71842aa95319826c2b642c9955c6ea75dfe834363468","src/lib.rs":"cb5536c5316066e39f8657f3614a68a7876629e66b992e5646fb0fd702a08766","src/macros/enum_count.rs":"44084ab800ca8fca3b17f76c6025e8e59855598c0119807ce7bc80d5dc345d99","src/macros/enum_discriminants.rs":"91da7a9b42f2b97fecea5a62010dd7b9b77aedbadc862e008a1f0a4712db0336","src/macros/enum_is.rs":"cd63fb79f4f9b3479f11bce2ad45d3cb5d23f1d5c9c2a5fbb7af7e813fb70fa7","src/macros/enum_iter.rs":"c1c7253945d30294e0bd1916847fed1c9d795be02be4ba293f30dd4ba9bd70d4","src/macros/enum_messages.rs":"bf8a6e007a9833b78648cfe99adbafcfd4b72659d1e7d874149ec8f1a987b241","src/macros/enum_properties.rs":"e9f64d4c20a7730ee846ab91aeee24042d18bcda199763133a8ea0d166101a1b","src/macros/enum_table.rs":"86a1b1cc43516578e013c80b4ed4a14fc94e710c1cb7a75229fac465e2cf957c","src/macros/enum_try_as.rs":"ffd5b5ab740d80fd9e08d3db356584fd05e3194ada8d89dfe4f3e825016c1e85","src/macros/enum_variant_array.rs":"cb8de5cb5841fa9514c423c195b47a2fc13b9f5fb257093311fbb9c136c737d9","src/macros/enum_variant_names.rs":"ad4d2f87bf26e4d07327896118382a4b83c2cca5de6fdfecca6e7639eb73118b","src/macros/from_repr.rs":"f06358808bb69eed2c28cccb15865c6fa3c8fb91435fcd2c083a06af3e6f404b","src/macros/mod.rs":"c94b29d4ad0f40a7803605d42647cc9fafec76545c7f3c435fe675a3102eb0ef","src/macros/strings/as_ref_str.rs":"dc84e6627fd0ddea8a5ef60cf999f8da15c26f77d3bbebca01343ecef7e18128","src/macros/strings/display.rs":"b197fbc90acde0ce615f0be4d36065527b8bb50fc6ec8a227d5684c448f82df4","src/macros/strings/from_string.rs":"dced80df02abc3eba9b59402132eafc5b6220d48f7630f5eac4a4444d6d546eb","src/macros/strings/mod.rs":"95d921d854704028ae38961d7ebba13fbb3f6ee35d131de2c3a514594f435058","src/macros/strings/to_string.rs":"983e6c1b1dec145acfa0c6a7ef8ff01d30507145753a1d85d0387c5ab61f6fa1"},"package":"c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"}
\ No newline at end of file
diff --git a/crates/strum_macros/Android.bp b/crates/strum_macros/Android.bp
index 4459c50..318686f 100644
--- a/crates/strum_macros/Android.bp
+++ b/crates/strum_macros/Android.bp
@@ -17,9 +17,9 @@
     name: "libstrum_macros",
     crate_name: "strum_macros",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.26.4",
+    cargo_pkg_version: "0.27.1",
     crate_root: "src/lib.rs",
-    edition: "2018",
+    edition: "2021",
     rustlibs: [
         "libheck",
         "libproc_macro2",
@@ -34,19 +34,18 @@
     host_cross_supported: false,
     crate_name: "strum_macros",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.26.4",
+    cargo_pkg_version: "0.27.1",
     crate_root: "src/lib.rs",
     test_suites: ["general-tests"],
     auto_gen_config: true,
     test_options: {
         unit_test: true,
     },
-    edition: "2018",
+    edition: "2021",
     rustlibs: [
         "libheck",
         "libproc_macro2",
         "libquote",
-        "libstrum",
         "libsyn",
     ],
     proc_macros: ["librustversion"],
diff --git a/crates/strum_macros/Cargo.toml b/crates/strum_macros/Cargo.toml
index b3ae870..8f14451 100644
--- a/crates/strum_macros/Cargo.toml
+++ b/crates/strum_macros/Cargo.toml
@@ -10,15 +10,11 @@
 # See Cargo.toml.orig for the original contents.
 
 [package]
-edition = "2018"
+edition = "2021"
+rust-version = "1.66.1"
 name = "strum_macros"
-version = "0.26.4"
+version = "0.27.1"
 authors = ["Peter Glotfelty <peter.glotfelty@microsoft.com>"]
-build = false
-autobins = false
-autoexamples = false
-autotests = false
-autobenches = false
 description = "Helpful macros for working with enums and strings"
 homepage = "https://github.com/Peternator7/strum"
 documentation = "https://docs.rs/strum"
@@ -38,7 +34,6 @@
 
 [lib]
 name = "strum_macros"
-path = "src/lib.rs"
 proc-macro = true
 
 [dependencies.heck]
@@ -55,10 +50,6 @@
 
 [dependencies.syn]
 version = "2.0"
-features = [
-    "parsing",
-    "extra-traits",
-]
+features = ["parsing"]
 
-[dev-dependencies.strum]
-version = "0.26"
+[dev-dependencies]
diff --git a/crates/strum_macros/METADATA b/crates/strum_macros/METADATA
index 86542f3..f31fe74 100644
--- a/crates/strum_macros/METADATA
+++ b/crates/strum_macros/METADATA
@@ -1,17 +1,17 @@
 name: "strum_macros"
 description: "Helpful macros for working with enums and strings"
 third_party {
-  version: "0.26.4"
+  version: "0.27.1"
   license_type: NOTICE
   last_upgrade_date {
     year: 2025
     month: 2
-    day: 20
+    day: 24
   }
   homepage: "https://crates.io/crates/strum_macros"
   identifier {
     type: "Archive"
-    value: "https://static.crates.io/crates/strum_macros/strum_macros-0.26.4.crate"
-    version: "0.26.4"
+    value: "https://static.crates.io/crates/strum_macros/strum_macros-0.27.1.crate"
+    version: "0.27.1"
   }
 }
diff --git a/crates/strum_macros/README.md b/crates/strum_macros/README.md
index 04b37fc..6fef752 100644
--- a/crates/strum_macros/README.md
+++ b/crates/strum_macros/README.md
@@ -11,7 +11,7 @@
 
 # Compatibility
 
-Strum is currently compatible with versions of rustc >= 1.56.1. Pull Requests that improve compatibility with older
+Strum is currently compatible with versions of rustc >= 1.66.1. Pull Requests that improve compatibility with older
 versions are welcome. The project goal is to support a rust version for at least 2 years after release 
 and even longer is preferred since this project changes slowly.
 
@@ -22,11 +22,11 @@
 
 ```toml
 [dependencies]
-strum = "0.26"
-strum_macros = "0.26"
+strum = "0.27"
+strum_macros = "0.27"
 
 # You can also use the "derive" feature, and import the macros directly from "strum"
-# strum = { version = "0.26", features = ["derive"] }
+# strum = { version = "0.27", features = ["derive"] }
 ```
 
 # Strum Macros
diff --git a/crates/strum_macros/src/helpers/inner_variant_props.rs b/crates/strum_macros/src/helpers/inner_variant_props.rs
index bc0fe79..f37bac9 100644
--- a/crates/strum_macros/src/helpers/inner_variant_props.rs
+++ b/crates/strum_macros/src/helpers/inner_variant_props.rs
@@ -6,7 +6,7 @@
     fn get_variant_inner_properties(&self) -> syn::Result<StrumInnerVariantProperties>;
 }
 
-#[derive(Clone, Eq, PartialEq, Debug, Default)]
+#[derive(Clone, Default)]
 pub struct StrumInnerVariantProperties {
     pub default_with: Option<LitStr>,
 }
diff --git a/crates/strum_macros/src/helpers/metadata.rs b/crates/strum_macros/src/helpers/metadata.rs
index 94100a7..21a6d36 100644
--- a/crates/strum_macros/src/helpers/metadata.rs
+++ b/crates/strum_macros/src/helpers/metadata.rs
@@ -16,8 +16,11 @@
 
     // enum metadata
     custom_keyword!(serialize_all);
+    custom_keyword!(const_into_str);
     custom_keyword!(use_phf);
     custom_keyword!(prefix);
+    custom_keyword!(parse_err_ty);
+    custom_keyword!(parse_err_fn);
 
     // enum discriminant metadata
     custom_keyword!(derive);
@@ -29,6 +32,7 @@
     custom_keyword!(detailed_message);
     custom_keyword!(serialize);
     custom_keyword!(to_string);
+    custom_keyword!(transparent);
     custom_keyword!(disabled);
     custom_keyword!(default);
     custom_keyword!(default_with);
@@ -51,6 +55,15 @@
         kw: kw::prefix,
         prefix: LitStr,
     },
+    ParseErrTy {
+        kw: kw::parse_err_ty,
+        path: Path,
+    },
+    ParseErrFn {
+        kw: kw::parse_err_fn,
+        path: Path,
+    },
+    ConstIntoStr(kw::const_into_str),
 }
 
 impl Parse for EnumMeta {
@@ -80,6 +93,18 @@
             input.parse::<Token![=]>()?;
             let prefix = input.parse()?;
             Ok(EnumMeta::Prefix { kw, prefix })
+        } else if lookahead.peek(kw::parse_err_ty) {
+            let kw = input.parse::<kw::parse_err_ty>()?;
+            input.parse::<Token![=]>()?;
+            let path: Path = input.parse()?;
+            Ok(EnumMeta::ParseErrTy { kw, path })
+        } else if lookahead.peek(kw::parse_err_fn) {
+            let kw = input.parse::<kw::parse_err_fn>()?;
+            input.parse::<Token![=]>()?;
+            let path: Path = input.parse()?;
+            Ok(EnumMeta::ParseErrFn { kw, path })
+        } else if lookahead.peek(kw::const_into_str) {
+            Ok(EnumMeta::ConstIntoStr(input.parse()?))
         } else {
             Err(lookahead.error())
         }
@@ -87,7 +112,7 @@
 }
 
 pub enum EnumDiscriminantsMeta {
-    Derive { kw: kw::derive, paths: Vec<Path> },
+    Derive { _kw: kw::derive, paths: Vec<Path> },
     Name { kw: kw::name, name: Ident },
     Vis { kw: kw::vis, vis: Visibility },
     Other { path: Path, nested: TokenStream },
@@ -96,12 +121,12 @@
 impl Parse for EnumDiscriminantsMeta {
     fn parse(input: ParseStream) -> syn::Result<Self> {
         if input.peek(kw::derive) {
-            let kw = input.parse()?;
+            let _kw = input.parse()?;
             let content;
             parenthesized!(content in input);
             let paths = content.parse_terminated(Path::parse, Token![,])?;
             Ok(EnumDiscriminantsMeta::Derive {
-                kw,
+                _kw,
                 paths: paths.into_iter().collect(),
             })
         } else if input.peek(kw::name) {
@@ -154,7 +179,7 @@
         value: LitStr,
     },
     Serialize {
-        kw: kw::serialize,
+        _kw: kw::serialize,
         value: LitStr,
     },
     Documentation {
@@ -164,6 +189,7 @@
         kw: kw::to_string,
         value: LitStr,
     },
+    Transparent(kw::transparent),
     Disabled(kw::disabled),
     Default(kw::default),
     DefaultWith {
@@ -175,8 +201,8 @@
         value: bool,
     },
     Props {
-        kw: kw::props,
-        props: Vec<(LitStr, LitStr)>,
+        _kw: kw::props,
+        props: Vec<(LitStr, Lit)>,
     },
 }
 
@@ -194,15 +220,17 @@
             let value = input.parse()?;
             Ok(VariantMeta::DetailedMessage { kw, value })
         } else if lookahead.peek(kw::serialize) {
-            let kw = input.parse()?;
+            let _kw = input.parse()?;
             let _: Token![=] = input.parse()?;
             let value = input.parse()?;
-            Ok(VariantMeta::Serialize { kw, value })
+            Ok(VariantMeta::Serialize { _kw, value })
         } else if lookahead.peek(kw::to_string) {
             let kw = input.parse()?;
             let _: Token![=] = input.parse()?;
             let value = input.parse()?;
             Ok(VariantMeta::ToString { kw, value })
+        } else if lookahead.peek(kw::transparent) {
+            Ok(VariantMeta::Transparent(input.parse()?))
         } else if lookahead.peek(kw::disabled) {
             Ok(VariantMeta::Disabled(input.parse()?))
         } else if lookahead.peek(kw::default) {
@@ -222,12 +250,12 @@
             };
             Ok(VariantMeta::AsciiCaseInsensitive { kw, value })
         } else if lookahead.peek(kw::props) {
-            let kw = input.parse()?;
+            let _kw = input.parse()?;
             let content;
             parenthesized!(content in input);
             let props = content.parse_terminated(Prop::parse, Token![,])?;
             Ok(VariantMeta::Props {
-                kw,
+                _kw,
                 props: props
                     .into_iter()
                     .map(|Prop(k, v)| (LitStr::new(&k.to_string(), k.span()), v))
@@ -239,7 +267,7 @@
     }
 }
 
-struct Prop(Ident, LitStr);
+struct Prop(Ident, Lit);
 
 impl Parse for Prop {
     fn parse(input: ParseStream) -> syn::Result<Self> {
@@ -295,7 +323,6 @@
         })
 }
 
-#[derive(Debug)]
 pub enum InnerVariantMeta {
     DefaultWith { kw: kw::default_with, value: LitStr },
 }
diff --git a/crates/strum_macros/src/helpers/mod.rs b/crates/strum_macros/src/helpers/mod.rs
index 23d60b5..13a7f89 100644
--- a/crates/strum_macros/src/helpers/mod.rs
+++ b/crates/strum_macros/src/helpers/mod.rs
@@ -13,6 +13,13 @@
 use quote::ToTokens;
 use syn::spanned::Spanned;
 
+pub fn missing_parse_err_attr_error() -> syn::Error {
+    syn::Error::new(
+        Span::call_site(),
+        "`parse_err_ty` and `parse_err_fn` attributes are both required.",
+    )
+}
+
 pub fn non_enum_error() -> syn::Error {
     syn::Error::new(Span::call_site(), "This macro only supports enums.")
 }
@@ -25,6 +32,16 @@
     )
 }
 
+pub fn non_single_field_variant_error(attr: &str) -> syn::Error {
+    syn::Error::new(
+        Span::call_site(),
+        format_args!(
+            "The [`{}`] attribute only supports enum variants with a single field",
+            attr
+        ),
+    )
+}
+
 pub fn strum_discriminants_passthrough_error(span: &impl Spanned) -> syn::Error {
     syn::Error::new(
         span.span(),
diff --git a/crates/strum_macros/src/helpers/type_props.rs b/crates/strum_macros/src/helpers/type_props.rs
index 7302853..ab84021 100644
--- a/crates/strum_macros/src/helpers/type_props.rs
+++ b/crates/strum_macros/src/helpers/type_props.rs
@@ -11,8 +11,10 @@
     fn get_type_properties(&self) -> syn::Result<StrumTypeProperties>;
 }
 
-#[derive(Debug, Clone, Default)]
+#[derive(Clone, Default)]
 pub struct StrumTypeProperties {
+    pub parse_err_ty: Option<Path>,
+    pub parse_err_fn: Option<Path>,
     pub case_style: Option<CaseStyle>,
     pub ascii_case_insensitive: bool,
     pub crate_module_path: Option<Path>,
@@ -23,6 +25,7 @@
     pub use_phf: bool,
     pub prefix: Option<LitStr>,
     pub enum_repr: Option<TokenStream>,
+    pub const_into_str: bool,
 }
 
 impl HasTypeProperties for DeriveInput {
@@ -32,11 +35,15 @@
         let strum_meta = self.get_metadata()?;
         let discriminants_meta = self.get_discriminants_metadata()?;
 
+        let mut parse_err_ty_kw = None;
+        let mut parse_err_fn_kw = None;
         let mut serialize_all_kw = None;
         let mut ascii_case_insensitive_kw = None;
         let mut use_phf_kw = None;
         let mut crate_module_path_kw = None;
         let mut prefix_kw = None;
+        let mut const_into_str = None;
+
         for meta in strum_meta {
             match meta {
                 EnumMeta::SerializeAll { case_style, kw } => {
@@ -82,6 +89,30 @@
                     prefix_kw = Some(kw);
                     output.prefix = Some(prefix);
                 }
+                EnumMeta::ParseErrTy { path, kw } => {
+                    if let Some(fst_kw) = parse_err_ty_kw {
+                        return Err(occurrence_error(fst_kw, kw, "parse_err_ty"));
+                    }
+
+                    parse_err_ty_kw = Some(kw);
+                    output.parse_err_ty = Some(path);
+                }
+                EnumMeta::ParseErrFn { path, kw } => {
+                    if let Some(fst_kw) = parse_err_fn_kw {
+                        return Err(occurrence_error(fst_kw, kw, "parse_err_fn"));
+                    }
+
+                    parse_err_fn_kw = Some(kw);
+                    output.parse_err_fn = Some(path);
+                }
+                EnumMeta::ConstIntoStr(kw) => {
+                    if let Some(fst_kw) = const_into_str {
+                        return Err(occurrence_error(fst_kw, kw, "const_into_str"));
+                    }
+
+                    const_into_str = Some(kw);
+                    output.const_into_str = true;
+                }
             }
         }
 
diff --git a/crates/strum_macros/src/helpers/variant_props.rs b/crates/strum_macros/src/helpers/variant_props.rs
index 681c7c0..a9ed43d 100644
--- a/crates/strum_macros/src/helpers/variant_props.rs
+++ b/crates/strum_macros/src/helpers/variant_props.rs
@@ -1,5 +1,5 @@
 use std::default::Default;
-use syn::{Ident, LitStr, Variant};
+use syn::{Ident, Lit, LitStr, Variant};
 
 use super::case_style::{CaseStyle, CaseStyleHelpers};
 use super::metadata::{kw, VariantExt, VariantMeta};
@@ -9,8 +9,9 @@
     fn get_variant_properties(&self) -> syn::Result<StrumVariantProperties>;
 }
 
-#[derive(Clone, Eq, PartialEq, Debug, Default)]
+#[derive(Clone, Default)]
 pub struct StrumVariantProperties {
+    pub transparent: Option<kw::transparent>,
     pub disabled: Option<kw::disabled>,
     pub default: Option<kw::default>,
     pub default_with: Option<LitStr>,
@@ -18,7 +19,7 @@
     pub message: Option<LitStr>,
     pub detailed_message: Option<LitStr>,
     pub documentation: Vec<LitStr>,
-    pub string_props: Vec<(LitStr, LitStr)>,
+    pub props: Vec<(LitStr, Lit)>,
     serialize: Vec<LitStr>,
     pub to_string: Option<LitStr>,
     ident: Option<Ident>,
@@ -73,6 +74,7 @@
 
         let mut message_kw = None;
         let mut detailed_message_kw = None;
+        let mut transparent_kw = None;
         let mut disabled_kw = None;
         let mut default_kw = None;
         let mut default_with_kw = None;
@@ -110,6 +112,14 @@
                     to_string_kw = Some(kw);
                     output.to_string = Some(value);
                 }
+                VariantMeta::Transparent(kw) => {
+                    if let Some(fst_kw) = transparent_kw {
+                        return Err(occurrence_error(fst_kw, kw, "transparent"));
+                    }
+
+                    transparent_kw = Some(kw);
+                    output.transparent = Some(kw);
+                }
                 VariantMeta::Disabled(kw) => {
                     if let Some(fst_kw) = disabled_kw {
                         return Err(occurrence_error(fst_kw, kw, "disabled"));
@@ -143,7 +153,7 @@
                     output.ascii_case_insensitive = Some(value);
                 }
                 VariantMeta::Props { props, .. } => {
-                    output.string_props.extend(props);
+                    output.props.extend(props);
                 }
             }
         }
diff --git a/crates/strum_macros/src/lib.rs b/crates/strum_macros/src/lib.rs
index 38e81f2..817c0aa 100644
--- a/crates/strum_macros/src/lib.rs
+++ b/crates/strum_macros/src/lib.rs
@@ -54,7 +54,13 @@
 /// If you have a large enum, you may want to consider using the `use_phf` attribute here. It leverages
 /// perfect hash functions to parse much quicker than a standard `match`. (MSRV 1.46)
 ///
-/// # Example howto use `EnumString`
+/// The default error type is `strum::ParseError`. This can be overriden by applying both the
+/// `parse_err_ty` and `parse_err_fn` attributes at the type level.  `parse_error_fn` should be a
+/// function that accepts an `&str` and returns the type `parse_error_ty`. See
+/// [this test case](https://github.com/Peternator7/strum/blob/9db3c4dc9b6f585aeb9f5f15f9cc18b6cf4fd780/strum_tests/tests/from_str.rs#L233)
+/// for an example.
+///
+/// # Example how to use `EnumString`
 /// ```
 /// use std::str::FromStr;
 /// use strum_macros::EnumString;
@@ -154,10 +160,13 @@
 /// let yellow = Color::Yellow;
 /// assert_eq!("Yellow", yellow.as_ref());
 /// // or for string formatting
-/// println!(
-///     "blue: {} green: {}",
-///     Color::Blue(10).as_ref(),
-///     Color::Green { range: 42 }.as_ref()
+/// assert_eq!(
+///    "blue: Blue green: Green",
+///    format!(
+///        "blue: {} green: {}",
+///        Color::Blue(10).as_ref(),
+///        Color::Green { range: 42 }.as_ref()
+///    )
 /// );
 ///
 /// // With prefix on all variants
@@ -237,7 +246,8 @@
 /// meaning that the variants must not have any data.
 ///
 /// ```
-/// use strum::VariantArray;
+/// use strum::VariantArray as _;
+/// use strum_macros::VariantArray;
 ///
 /// #[derive(VariantArray, Debug, PartialEq, Eq)]
 /// enum Op {
@@ -411,10 +421,13 @@
 /// let yellow = Color::Yellow;
 /// assert_eq!(String::from("Yellow"), yellow.to_string());
 /// // or for string formatting
-/// println!(
-///     "blue: {} green: {}",
-///     Color::Blue(10),
-///     Color::Green { range: 42 }
+/// assert_eq!(
+///    "blue: Blue green: Green",
+///    format!(
+///        "blue: {} green: {}",
+///        Color::Blue(10),
+///        Color::Green { range: 42 }
+///    )
 /// );
 /// // you can also use named fields in message
 /// let purple = Color::Purple { sat: 10 };
@@ -429,7 +442,7 @@
     toks.into()
 }
 
-/// Creates a new type that iterates of the variants of an enum.
+/// Creates a new type that iterates over the variants of an enum.
 ///
 /// Iterate over the variants of an Enum. Any additional data on your variants will be set to `Default::default()`.
 /// The macro implements [`strum::IntoEnumIterator`](https://docs.rs/strum/latest/strum/trait.IntoEnumIterator.html) on your enum and creates a new type called `YourEnumIter` that is the iterator object.
@@ -830,8 +843,8 @@
 /// ```
 /// // Bring trait into scope
 /// use std::str::FromStr;
-/// use strum::{IntoEnumIterator, EnumMessage};
-/// use strum_macros::{EnumDiscriminants, EnumIter, EnumString};
+/// use strum::{IntoEnumIterator, EnumMessage as _};
+/// use strum_macros::{EnumDiscriminants, EnumIter, EnumString, EnumMessage};
 ///
 /// #[derive(Debug)]
 /// struct NonDefault;
diff --git a/crates/strum_macros/src/macros/enum_discriminants.rs b/crates/strum_macros/src/macros/enum_discriminants.rs
index f7d6372..8dc4aaa 100644
--- a/crates/strum_macros/src/macros/enum_discriminants.rs
+++ b/crates/strum_macros/src/macros/enum_discriminants.rs
@@ -22,6 +22,7 @@
 
     // Derives for the generated enum
     let type_properties = ast.get_type_properties()?;
+    let strum_module_path = type_properties.crate_module_path();
 
     let derives = type_properties.discriminant_derives;
 
@@ -35,7 +36,8 @@
     let discriminants_name = type_properties.discriminant_name.unwrap_or(default_name);
     let discriminants_vis = type_properties
         .discriminant_vis
-        .unwrap_or_else(|| vis.clone());
+        .as_ref()
+        .unwrap_or_else(|| &vis);
 
     // Pass through all other attributes
     let pass_though_attributes = type_properties.discriminant_others;
@@ -132,6 +134,7 @@
     let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
     let impl_from = quote! {
         impl #impl_generics ::core::convert::From< #name #ty_generics > for #discriminants_name #where_clause {
+            #[inline]
             fn from(val: #name #ty_generics) -> #discriminants_name {
                 #from_fn_body
             }
@@ -149,6 +152,7 @@
 
         quote! {
             impl #impl_generics ::core::convert::From< #enum_life #name #ty_generics > for #discriminants_name #where_clause {
+                #[inline]
                 fn from(val: #enum_life #name #ty_generics) -> #discriminants_name {
                     #from_fn_body
                 }
@@ -156,6 +160,26 @@
         }
     };
 
+    // For now, only implement IntoDiscriminant if the user has not overriden the visibility.
+    let impl_into_discriminant = match type_properties.discriminant_vis {
+        // If the visibilty is unspecified or `pub` then we implement IntoDiscriminant
+        None | Some(syn::Visibility::Public(..)) => quote! {
+            impl #impl_generics #strum_module_path::IntoDiscriminant for #name #ty_generics #where_clause {
+                type Discriminant = #discriminants_name;
+
+                #[inline]
+                fn discriminant(&self) -> Self::Discriminant {
+                    <Self::Discriminant as ::core::convert::From<&Self>>::from(self)
+                }
+            }
+        },
+        // If it's something restricted such as `pub(super)` then we skip implementing the
+        // trait for now. There are certainly scenarios where they could be equivalent, but
+        // as a heuristic, if someone is overriding the visibility, it's because they want
+        // the discriminant type to be less visible than the original type.
+        _ => quote! {},
+    };
+
     Ok(quote! {
         /// Auto-generated discriminant enum variants
         #derives
@@ -165,6 +189,7 @@
             #(#discriminants),*
         }
 
+        #impl_into_discriminant
         #impl_from
         #impl_from_ref
     })
diff --git a/crates/strum_macros/src/macros/enum_iter.rs b/crates/strum_macros/src/macros/enum_iter.rs
index f8a2070..6145bf9 100644
--- a/crates/strum_macros/src/macros/enum_iter.rs
+++ b/crates/strum_macros/src/macros/enum_iter.rs
@@ -23,9 +23,9 @@
 
     let phantom_data = if gen.type_params().count() > 0 {
         let g = gen.type_params().map(|param| &param.ident);
-        quote! { < ( #(#g),* ) > }
+        quote! { < fn() -> ( #(#g),* ) > }
     } else {
-        quote! { < () > }
+        quote! { < fn() -> () > }
     };
 
     let variants = match &ast.data {
@@ -100,6 +100,8 @@
 
         impl #impl_generics #strum_module_path::IntoEnumIterator for #name #ty_generics #where_clause {
             type Iterator = #iter_name #ty_generics;
+
+            #[inline]
             fn iter() -> #iter_name #ty_generics {
                 #iter_name {
                     idx: 0,
@@ -112,15 +114,18 @@
         impl #impl_generics Iterator for #iter_name #ty_generics #where_clause {
             type Item = #name #ty_generics;
 
+            #[inline]
             fn next(&mut self) -> ::core::option::Option<<Self as Iterator>::Item> {
                 self.nth(0)
             }
 
+            #[inline]
             fn size_hint(&self) -> (usize, ::core::option::Option<usize>) {
                 let t = if self.idx + self.back_idx >= #variant_count { 0 } else { #variant_count - self.idx - self.back_idx };
                 (t, Some(t))
             }
 
+            #[inline]
             fn nth(&mut self, n: usize) -> ::core::option::Option<<Self as Iterator>::Item> {
                 let idx = self.idx + n + 1;
                 if idx + self.back_idx > #variant_count {
@@ -137,12 +142,14 @@
         }
 
         impl #impl_generics ExactSizeIterator for #iter_name #ty_generics #where_clause {
+            #[inline]
             fn len(&self) -> usize {
                 self.size_hint().0
             }
         }
 
         impl #impl_generics DoubleEndedIterator for #iter_name #ty_generics #where_clause {
+            #[inline]
             fn next_back(&mut self) -> ::core::option::Option<<Self as Iterator>::Item> {
                 let back_idx = self.back_idx + 1;
 
@@ -162,6 +169,7 @@
         impl #impl_generics ::core::iter::FusedIterator for #iter_name #ty_generics #where_clause { }
 
         impl #impl_generics Clone for #iter_name #ty_generics #where_clause {
+            #[inline]
             fn clone(&self) -> #iter_name #ty_generics {
                 #iter_name {
                     idx: self.idx,
diff --git a/crates/strum_macros/src/macros/enum_messages.rs b/crates/strum_macros/src/macros/enum_messages.rs
index 2dad411..2bc458d 100644
--- a/crates/strum_macros/src/macros/enum_messages.rs
+++ b/crates/strum_macros/src/macros/enum_messages.rs
@@ -113,24 +113,28 @@
 
     Ok(quote! {
         impl #impl_generics #strum_module_path::EnumMessage for #name #ty_generics #where_clause {
+            #[inline]
             fn get_message(&self) -> ::core::option::Option<&'static str> {
                 match self {
                     #(#arms),*
                 }
             }
 
+            #[inline]
             fn get_detailed_message(&self) -> ::core::option::Option<&'static str> {
                 match self {
                     #(#detailed_arms),*
                 }
             }
 
+            #[inline]
             fn get_documentation(&self) -> ::core::option::Option<&'static str> {
                 match self {
                     #(#documentation_arms),*
                 }
             }
 
+            #[inline]
             fn get_serializations(&self) -> &'static [&'static str] {
                 match self {
                     #(#serializations),*
diff --git a/crates/strum_macros/src/macros/enum_properties.rs b/crates/strum_macros/src/macros/enum_properties.rs
index 2583096..4ba9af3 100644
--- a/crates/strum_macros/src/macros/enum_properties.rs
+++ b/crates/strum_macros/src/macros/enum_properties.rs
@@ -1,9 +1,24 @@
+use std::collections::HashMap;
+
 use proc_macro2::TokenStream;
 use quote::quote;
-use syn::{Data, DeriveInput, Fields};
+use syn::{Data, DeriveInput, Fields, Lit};
 
 use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};
 
+#[derive(Hash, PartialEq, Eq)]
+enum PropertyType {
+    String,
+    Integer,
+    Bool,
+}
+
+const PROPERTY_TYPES: [PropertyType; 3] = [
+    PropertyType::String,
+    PropertyType::Integer,
+    PropertyType::Bool,
+];
+
 pub fn enum_properties_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
     let name = &ast.ident;
     let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
@@ -14,11 +29,12 @@
     let type_properties = ast.get_type_properties()?;
     let strum_module_path = type_properties.crate_module_path();
 
-    let mut arms = Vec::new();
+    let mut built_arms: HashMap<_, _> = PROPERTY_TYPES.iter().map(|p| (p, Vec::new())).collect();
+
     for variant in variants {
         let ident = &variant.ident;
         let variant_properties = variant.get_variant_properties()?;
-        let mut string_arms = Vec::new();
+        let mut arms: HashMap<_, _> = PROPERTY_TYPES.iter().map(|p| (p, Vec::new())).collect();
         // But you can disable the messages.
         if variant_properties.disabled.is_some() {
             continue;
@@ -30,32 +46,69 @@
             Fields::Named(..) => quote! { {..} },
         };
 
-        for (key, value) in variant_properties.string_props {
-            string_arms.push(quote! { #key => ::core::option::Option::Some( #value )});
+        for (key, value) in variant_properties.props {
+            let property_type = match value {
+                Lit::Str(..) => PropertyType::String,
+                Lit::Bool(..) => PropertyType::Bool,
+                Lit::Int(..) => PropertyType::Integer,
+                _ => todo!("TODO"),
+            };
+
+            arms.get_mut(&property_type)
+                .unwrap()
+                .push(quote! { #key => ::core::option::Option::Some( #value )});
         }
 
-        string_arms.push(quote! { _ => ::core::option::Option::None });
-
-        arms.push(quote! {
-            &#name::#ident #params => {
-                match prop {
-                    #(#string_arms),*
+        for property in &PROPERTY_TYPES {
+            arms.get_mut(&property)
+                .unwrap()
+                .push(quote! { _ => ::core::option::Option::None });
+            let arms_as_string = &arms[property];
+            built_arms.get_mut(&property).unwrap().push(quote! {
+                &#name::#ident #params => {
+                    match prop {
+                        #(#arms_as_string),*
+                    }
                 }
-            }
-        });
+            });
+        }
     }
 
-    if arms.len() < variants.len() {
-        arms.push(quote! { _ => ::core::option::Option::None });
+    for (_, arms) in built_arms.iter_mut() {
+        if arms.len() < variants.len() {
+            arms.push(quote! { _ => ::core::option::Option::None });
+        }
     }
 
+    let (built_string_arms, built_int_arms, built_bool_arms) = (
+        &built_arms[&PropertyType::String],
+        &built_arms[&PropertyType::Integer],
+        &built_arms[&PropertyType::Bool],
+    );
+
     Ok(quote! {
         impl #impl_generics #strum_module_path::EnumProperty for #name #ty_generics #where_clause {
+            #[inline]
             fn get_str(&self, prop: &str) -> ::core::option::Option<&'static str> {
                 match self {
-                    #(#arms),*
+                    #(#built_string_arms),*
                 }
             }
+
+            #[inline]
+            fn get_int(&self, prop: &str) -> ::core::option::Option<i64> {
+                match self {
+                    #(#built_int_arms),*
+                }
+            }
+
+            #[inline]
+            fn get_bool(&self, prop: &str) -> ::core::option::Option<bool> {
+                match self {
+                    #(#built_bool_arms),*
+                }
+            }
+
         }
     })
 }
diff --git a/crates/strum_macros/src/macros/enum_table.rs b/crates/strum_macros/src/macros/enum_table.rs
index f9d4e81..cfcf270 100644
--- a/crates/strum_macros/src/macros/enum_table.rs
+++ b/crates/strum_macros/src/macros/enum_table.rs
@@ -58,7 +58,7 @@
         }
 
         // Error on variants with data
-        if variant.fields != Fields::Unit {
+        if !matches!(variant.fields, Fields::Unit) {
             return Err(syn::Error::new(
                 variant.fields.span(),
                 "`EnumTable` doesn't support enums with non-unit variants",
@@ -133,6 +133,7 @@
 
         impl<T> #table_name<T> {
             #[doc = #doc_new]
+            #[inline]
             #vis fn new(
                 #(#snake_idents: T,)*
             ) -> #table_name<T> {
@@ -142,6 +143,7 @@
             }
 
             #[doc = #doc_closure]
+            #[inline]
             #vis fn from_closure<F: Fn(#name)->T>(func: F) -> #table_name<T> {
               #table_name {
                 #(#closure_fields)*
@@ -149,6 +151,7 @@
             }
 
             #[doc = #doc_transform]
+            #[inline]
             #vis fn transform<U, F: Fn(#name, &T)->U>(&self, func: F) -> #table_name<U> {
               #table_name {
                 #(#transform_fields)*
@@ -160,6 +163,7 @@
         impl<T> ::core::ops::Index<#name> for #table_name<T> {
             type Output = T;
 
+            #[inline]
             fn index(&self, idx: #name) -> &T {
                 match idx {
                     #(#get_matches)*
@@ -169,6 +173,7 @@
         }
 
         impl<T> ::core::ops::IndexMut<#name> for #table_name<T> {
+            #[inline]
             fn index_mut(&mut self, idx: #name) -> &mut T {
                 match idx {
                     #(#get_matches_mut)*
@@ -179,6 +184,7 @@
 
         impl<T> #table_name<::core::option::Option<T>> {
             #[doc = #doc_option_all]
+            #[inline]
             #vis fn all(self) -> ::core::option::Option<#table_name<T>> {
                 if let #table_name {
                     #(#snake_idents: ::core::option::Option::Some(#snake_idents),)*
@@ -194,6 +200,7 @@
 
         impl<T, E> #table_name<::core::result::Result<T, E>> {
             #[doc = #doc_result_all_ok]
+            #[inline]
             #vis fn all_ok(self) -> ::core::result::Result<#table_name<T>, E> {
                 ::core::result::Result::Ok(#table_name {
                     #(#snake_idents: self.#snake_idents?,)*
diff --git a/crates/strum_macros/src/macros/enum_try_as.rs b/crates/strum_macros/src/macros/enum_try_as.rs
index c6d0127..470d80a 100644
--- a/crates/strum_macros/src/macros/enum_try_as.rs
+++ b/crates/strum_macros/src/macros/enum_try_as.rs
@@ -23,7 +23,7 @@
                 syn::Fields::Unnamed(values) => {
                     let variant_name = &variant.ident;
                     let types: Vec<_> = values.unnamed.iter().map(|field| {
-                        field.to_token_stream()
+                        field.ty.to_token_stream()
                     }).collect();
                     let field_names: Vec<_> = values.unnamed.iter().enumerate().map(|(i, _)| {
                         let name = "x".repeat(i + 1);
diff --git a/crates/strum_macros/src/macros/from_repr.rs b/crates/strum_macros/src/macros/from_repr.rs
index 78bbb28..f372b6e 100644
--- a/crates/strum_macros/src/macros/from_repr.rs
+++ b/crates/strum_macros/src/macros/from_repr.rs
@@ -113,6 +113,7 @@
         #[allow(clippy::use_self)]
         impl #impl_generics #name #ty_generics #where_clause {
             #[doc = "Try to create [Self] from the raw representation"]
+            #[inline]
             #vis #const_if_possible fn from_repr(discriminant: #discriminant_type) -> Option<#name #ty_generics> {
                 #(#constant_defs)*
                 match discriminant {
diff --git a/crates/strum_macros/src/macros/strings/as_ref_str.rs b/crates/strum_macros/src/macros/strings/as_ref_str.rs
index 8d44f81..4248171 100644
--- a/crates/strum_macros/src/macros/strings/as_ref_str.rs
+++ b/crates/strum_macros/src/macros/strings/as_ref_str.rs
@@ -2,9 +2,14 @@
 use quote::quote;
 use syn::{parse_quote, Data, DeriveInput, Fields};
 
-use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};
+use crate::helpers::{
+    non_enum_error, non_single_field_variant_error, HasStrumVariantProperties, HasTypeProperties,
+};
 
-fn get_arms(ast: &DeriveInput) -> syn::Result<Vec<TokenStream>> {
+fn get_arms<F>(ast: &DeriveInput, transparent_fn: F) -> syn::Result<Vec<TokenStream>>
+where
+    F: Fn(&TokenStream) -> TokenStream,
+{
     let name = &ast.ident;
     let mut arms = Vec::new();
     let variants = match &ast.data {
@@ -22,12 +27,21 @@
             continue;
         }
 
+        if let Some(..) = variant_properties.transparent {
+            let arm = super::extract_single_field_variant_and_then(name, variant, |tok| {
+                transparent_fn(tok)
+            })
+            .map_err(|_| non_single_field_variant_error("transparent"))?;
+
+            arms.push(arm);
+            continue;
+        }
+
         // Look at all the serialize attributes.
         // Use `to_string` attribute (not `as_ref_str` or something) to keep things consistent
         // (i.e. always `enum.as_ref().to_string() == enum.to_string()`).
         let output = variant_properties
             .get_preferred_name(type_properties.case_style, type_properties.prefix.as_ref());
-
         let params = match variant.fields {
             Fields::Unit => quote! {},
             Fields::Unnamed(..) => quote! { (..) },
@@ -52,9 +66,13 @@
 pub fn as_ref_str_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
     let name = &ast.ident;
     let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
-    let arms = get_arms(ast)?;
+    let arms = get_arms(ast, |tok| {
+        quote! { ::core::convert::AsRef::<str>::as_ref(#tok) }
+    })?;
+
     Ok(quote! {
         impl #impl_generics ::core::convert::AsRef<str> for #name #ty_generics #where_clause {
+            #[inline]
             fn as_ref(&self) -> &str {
                 match *self {
                     #(#arms),*
@@ -75,7 +93,10 @@
 ) -> syn::Result<TokenStream> {
     let name = &ast.ident;
     let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
-    let arms = get_arms(ast)?;
+    let arms = &get_arms(ast, |tok| {
+        quote! { ::core::convert::From::from(#tok) }
+    })?;
+
     let type_properties = ast.get_type_properties()?;
     let strum_module_path = type_properties.crate_module_path();
 
@@ -86,12 +107,11 @@
             parse_quote!('_derivative_strum),
         )));
     let (impl_generics2, _, _) = generics.split_for_impl();
-    let arms2 = arms.clone();
-    let arms3 = arms.clone();
 
     Ok(match trait_variant {
         GenerateTraitVariant::AsStaticStr => quote! {
             impl #impl_generics #strum_module_path::AsStaticRef<str> for #name #ty_generics #where_clause {
+                #[inline]
                 fn as_static(&self) -> &'static str {
                     match *self {
                         #(#arms),*
@@ -99,19 +119,43 @@
                 }
             }
         },
+        GenerateTraitVariant::From if !type_properties.const_into_str => quote! {
+            impl #impl_generics ::core::convert::From<#name #ty_generics> for &'static str #where_clause {
+                #[inline]
+                fn from(x: #name #ty_generics) -> &'static str {
+                    match x {
+                        #(#arms),*
+                    }
+                }
+            }
+            impl #impl_generics2 ::core::convert::From<&'_derivative_strum #name #ty_generics> for &'static str #where_clause {
+                #[inline]
+                fn from(x: &'_derivative_strum #name #ty_generics) -> &'static str {
+                    match *x {
+                        #(#arms),*
+                    }
+                }
+            }
+        },
         GenerateTraitVariant::From => quote! {
+            impl #impl_generics #name #ty_generics #where_clause {
+                pub const fn into_str(&self) -> &'static str {
+                    match self {
+                        #(#arms),*
+                    }
+                }
+            }
+
             impl #impl_generics ::core::convert::From<#name #ty_generics> for &'static str #where_clause {
                 fn from(x: #name #ty_generics) -> &'static str {
                     match x {
-                        #(#arms2),*
+                        #(#arms),*
                     }
                 }
             }
             impl #impl_generics2 ::core::convert::From<&'_derivative_strum #name #ty_generics> for &'static str #where_clause {
                 fn from(x: &'_derivative_strum #name #ty_generics) -> &'static str {
-                    match *x {
-                        #(#arms3),*
-                    }
+                    x.into_str()
                 }
             }
         },
diff --git a/crates/strum_macros/src/macros/strings/display.rs b/crates/strum_macros/src/macros/strings/display.rs
index 5e7a422..cfce6c8 100644
--- a/crates/strum_macros/src/macros/strings/display.rs
+++ b/crates/strum_macros/src/macros/strings/display.rs
@@ -2,7 +2,9 @@
 use quote::quote;
 use syn::{punctuated::Punctuated, Data, DeriveInput, Fields, LitStr, Token};
 
-use crate::helpers::{non_enum_error, HasStrumVariantProperties, HasTypeProperties};
+use crate::helpers::{
+    non_enum_error, non_single_field_variant_error, HasStrumVariantProperties, HasTypeProperties,
+};
 
 pub fn display_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
     let name = &ast.ident;
@@ -23,6 +25,16 @@
             continue;
         }
 
+        if let Some(..) = variant_properties.transparent {
+            let arm = super::extract_single_field_variant_and_then(name, variant, |tok| {
+                quote! { ::core::fmt::Display::fmt(#tok, f) }
+            })
+            .map_err(|_| non_single_field_variant_error("transparent"))?;
+
+            arms.push(arm);
+            continue;
+        }
+
         // Look at all the serialize attributes.
         let output = variant_properties
             .get_preferred_name(type_properties.case_style, type_properties.prefix.as_ref());
@@ -37,7 +49,8 @@
                     .enumerate()
                     .map(|(index, field)| {
                         assert!(field.ident.is_none());
-                        let ident = syn::parse_str::<Ident>(format!("field{}", index).as_str()).unwrap();
+                        let ident =
+                            syn::parse_str::<Ident>(format!("field{}", index).as_str()).unwrap();
                         quote! { ref #ident }
                     })
                     .collect();
@@ -59,86 +72,87 @@
         };
 
         if variant_properties.to_string.is_none() && variant_properties.default.is_some() {
-            match &variant.fields {
-                Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
-                    arms.push(quote! { #name::#ident(ref s) => ::core::fmt::Display::fmt(s, f) });
-                }
-                _ => {
-                    return Err(syn::Error::new_spanned(
-                        variant,
-                        "Default only works on newtype structs with a single String field",
-                    ))
-                }
-            }
-        } else {
-            let arm = match variant.fields {
-                Fields::Named(ref field_names) => {
-                    let used_vars = capture_format_string_idents(&output)?;
-                    if used_vars.is_empty() {
-                        quote! { #name::#ident #params => ::core::fmt::Display::fmt(#output, f) }
-                    } else {
-                        // Create args like 'name = name, age = age' for format macro
-                        let args: Punctuated<_, Token!(,)> = field_names
-                            .named
-                            .iter()
-                            .filter_map(|field| {
-                                let ident = field.ident.as_ref().unwrap();
-                                // Only contain variables that are used in format string
-                                if !used_vars.contains(ident) {
-                                    None
-                                } else {
-                                    Some(quote! { #ident = #ident })
-                                }
-                            })
-                            .collect();
-
-                        quote! {
-                            #[allow(unused_variables)]
-                            #name::#ident #params => ::core::fmt::Display::fmt(&format!(#output, #args), f)
-                        }
-                    }
-                },
-                Fields::Unnamed(ref unnamed_fields) => {
-                    let used_vars = capture_format_strings(&output)?;
-                    if used_vars.iter().any(String::is_empty) {
-                        return Err(syn::Error::new_spanned(
-                            &output,
-                            "Empty {} is not allowed; Use manual numbering ({0})",
-                        ))
-                    }
-                    if used_vars.is_empty() {
-                        quote! { #name::#ident #params => ::core::fmt::Display::fmt(#output, f) }
-                    } else {
-                        let args: Punctuated<_, Token!(,)> = unnamed_fields
-                            .unnamed
-                            .iter()
-                            .enumerate()
-                            .map(|(index, field)| {
-                                assert!(field.ident.is_none());
-                                syn::parse_str::<Ident>(format!("field{}", index).as_str()).unwrap()
-                            })
-                            .collect();
-                        quote! {
-                            #[allow(unused_variables)]
-                            #name::#ident #params => ::core::fmt::Display::fmt(&format!(#output, #args), f)
-                        }
-                    }
-                }
-                Fields::Unit => {
-                    let used_vars = capture_format_strings(&output)?;
-                    if !used_vars.is_empty() {
-                        return Err(syn::Error::new_spanned(
-                            &output,
-                            "Unit variants do not support interpolation",
-                        ));
-                    }
-
-                    quote! { #name::#ident #params => ::core::fmt::Display::fmt(#output, f) }
-                }
-            };
+            let arm = super::extract_single_field_variant_and_then(name, variant, |tok| {
+                quote! { ::core::fmt::Display::fmt(#tok, f)}
+            })
+            .map_err(|_| {
+                syn::Error::new_spanned(
+                    variant,
+                    "Default only works on newtype structs with a single String field",
+                )
+            })?;
 
             arms.push(arm);
+            continue;
         }
+
+        let arm = match variant.fields {
+            Fields::Named(ref field_names) => {
+                let used_vars = capture_format_string_idents(&output)?;
+                if used_vars.is_empty() {
+                    quote! { #name::#ident #params => ::core::fmt::Display::fmt(#output, f) }
+                } else {
+                    // Create args like 'name = name, age = age' for format macro
+                    let args: Punctuated<_, Token!(,)> = field_names
+                        .named
+                        .iter()
+                        .filter_map(|field| {
+                            let ident = field.ident.as_ref().unwrap();
+                            // Only contain variables that are used in format string
+                            if !used_vars.contains(ident) {
+                                None
+                            } else {
+                                Some(quote! { #ident = #ident })
+                            }
+                        })
+                        .collect();
+
+                    quote! {
+                        #[allow(unused_variables)]
+                        #name::#ident #params => ::core::fmt::Display::fmt(&format_args!(#output, #args), f)
+                    }
+                }
+            }
+            Fields::Unnamed(ref unnamed_fields) => {
+                let used_vars = capture_format_strings(&output)?;
+                if used_vars.iter().any(String::is_empty) {
+                    return Err(syn::Error::new_spanned(
+                        &output,
+                        "Empty {} is not allowed; Use manual numbering ({0})",
+                    ));
+                }
+                if used_vars.is_empty() {
+                    quote! { #name::#ident #params => ::core::fmt::Display::fmt(#output, f) }
+                } else {
+                    let args: Punctuated<_, Token!(,)> = unnamed_fields
+                        .unnamed
+                        .iter()
+                        .enumerate()
+                        .map(|(index, field)| {
+                            assert!(field.ident.is_none());
+                            syn::parse_str::<Ident>(format!("field{}", index).as_str()).unwrap()
+                        })
+                        .collect();
+                    quote! {
+                        #[allow(unused_variables)]
+                        #name::#ident #params => ::core::fmt::Display::fmt(&format!(#output, #args), f)
+                    }
+                }
+            }
+            Fields::Unit => {
+                let used_vars = capture_format_strings(&output)?;
+                if !used_vars.is_empty() {
+                    return Err(syn::Error::new_spanned(
+                        &output,
+                        "Unit variants do not support interpolation",
+                    ));
+                }
+
+                quote! { #name::#ident #params => ::core::fmt::Display::fmt(#output, f) }
+            }
+        };
+
+        arms.push(arm);
     }
 
     if arms.len() < variants.len() {
@@ -157,14 +171,17 @@
 }
 
 fn capture_format_string_idents(string_literal: &LitStr) -> syn::Result<Vec<Ident>> {
-    capture_format_strings(string_literal)?.into_iter().map(|ident| {
-        syn::parse_str::<Ident>(ident.as_str()).map_err(|_| {
-            syn::Error::new_spanned(
-                string_literal,
-                "Invalid identifier inside format string bracket",
-            )
+    capture_format_strings(string_literal)?
+        .into_iter()
+        .map(|ident| {
+            syn::parse_str::<Ident>(ident.as_str()).map_err(|_| {
+                syn::Error::new_spanned(
+                    string_literal,
+                    "Invalid identifier inside format string bracket",
+                )
+            })
         })
-    }).collect()
+        .collect()
 }
 
 fn capture_format_strings(string_literal: &LitStr) -> syn::Result<Vec<String>> {
diff --git a/crates/strum_macros/src/macros/strings/from_string.rs b/crates/strum_macros/src/macros/strings/from_string.rs
index de32cbb..505f89f 100644
--- a/crates/strum_macros/src/macros/strings/from_string.rs
+++ b/crates/strum_macros/src/macros/strings/from_string.rs
@@ -1,10 +1,10 @@
 use proc_macro2::TokenStream;
 use quote::quote;
-use syn::{Data, DeriveInput, Fields};
+use syn::{parse_quote, Data, DeriveInput, Fields, Path};
 
 use crate::helpers::{
-    non_enum_error, occurrence_error, HasInnerVariantProperties, HasStrumVariantProperties,
-    HasTypeProperties,
+    missing_parse_err_attr_error, non_enum_error, occurrence_error, HasInnerVariantProperties,
+    HasStrumVariantProperties, HasTypeProperties,
 };
 
 pub fn from_string_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
@@ -19,9 +19,25 @@
     let strum_module_path = type_properties.crate_module_path();
 
     let mut default_kw = None;
-    let mut default =
-        quote! { ::core::result::Result::Err(#strum_module_path::ParseError::VariantNotFound) };
+    let (mut default_err_ty, mut default) = match (
+        type_properties.parse_err_ty,
+        type_properties.parse_err_fn,
+    ) {
+        (None, None) => (
+            quote! { #strum_module_path::ParseError },
+            quote! { ::core::result::Result::Err(#strum_module_path::ParseError::VariantNotFound) },
+        ),
+        (Some(ty), Some(f)) => {
+            let ty_path: Path = parse_quote!(#ty);
+            let fn_path: Path = parse_quote!(#f);
 
+            (
+                quote! { #ty_path },
+                quote! { ::core::result::Result::Err(#fn_path(s)) },
+            )
+        }
+        _ => return Err(missing_parse_err_attr_error()),
+    };
     let mut phf_exact_match_arms = Vec::new();
     let mut standard_match_arms = Vec::new();
     for variant in variants {
@@ -37,8 +53,21 @@
                 return Err(occurrence_error(fst_kw, kw, "default"));
             }
 
+            default_kw = Some(kw);
+            default_err_ty = quote! { #strum_module_path::ParseError };
+
             match &variant.fields {
-                Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {}
+                Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
+                    default = quote! {
+                        ::core::result::Result::Ok(#name::#ident(s.into()))
+                    };
+                }
+                Fields::Named(ref f) if f.named.len() == 1 => {
+                    let field_name = f.named.last().unwrap().ident.as_ref().unwrap();
+                    default = quote! {
+                        ::core::result::Result::Ok(#name::#ident { #field_name : s.into() } )
+                    };
+                }
                 _ => {
                     return Err(syn::Error::new_spanned(
                         variant,
@@ -46,10 +75,7 @@
                     ))
                 }
             }
-            default_kw = Some(kw);
-            default = quote! {
-                ::core::result::Result::Ok(#name::#ident(s.into()))
-            };
+
             continue;
         }
 
@@ -146,7 +172,9 @@
     let from_str = quote! {
         #[allow(clippy::use_self)]
         impl #impl_generics ::core::str::FromStr for #name #ty_generics #where_clause {
-            type Err = #strum_module_path::ParseError;
+            type Err = #default_err_ty;
+
+            #[inline]
             fn from_str(s: &str) -> ::core::result::Result< #name #ty_generics , <Self as ::core::str::FromStr>::Err> {
                 #phf_body
                 #standard_match_body
@@ -158,7 +186,7 @@
         &impl_generics,
         &ty_generics,
         where_clause,
-        &strum_module_path,
+        &default_err_ty,
     );
 
     Ok(quote! {
@@ -184,12 +212,14 @@
     impl_generics: &syn::ImplGenerics,
     ty_generics: &syn::TypeGenerics,
     where_clause: Option<&syn::WhereClause>,
-    strum_module_path: &syn::Path,
+    default_err_ty: &TokenStream,
 ) -> TokenStream {
     quote! {
         #[allow(clippy::use_self)]
         impl #impl_generics ::core::convert::TryFrom<&str> for #name #ty_generics #where_clause {
-            type Error = #strum_module_path::ParseError;
+            type Error = #default_err_ty;
+
+            #[inline]
             fn try_from(s: &str) -> ::core::result::Result< #name #ty_generics , <Self as ::core::convert::TryFrom<&str>>::Error> {
                 ::core::str::FromStr::from_str(s)
             }
diff --git a/crates/strum_macros/src/macros/strings/mod.rs b/crates/strum_macros/src/macros/strings/mod.rs
index e416f4b..041e63b 100644
--- a/crates/strum_macros/src/macros/strings/mod.rs
+++ b/crates/strum_macros/src/macros/strings/mod.rs
@@ -1,4 +1,49 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{Fields, Ident, Variant};
+
 pub mod as_ref_str;
 pub mod display;
 pub mod from_string;
 pub mod to_string;
+
+struct NonSingleFieldEnum;
+
+fn extract_single_field_variant_and_then<F>(
+    name: &Ident,
+    variant: &Variant,
+    return_val_fn: F,
+) -> Result<TokenStream, NonSingleFieldEnum>
+where
+    F: Fn(&TokenStream) -> TokenStream,
+{
+    let variant_ident = &variant.ident;
+
+    let pattern_and_return = match &variant.fields {
+        Fields::Unnamed(f) if f.unnamed.len() == 1 => {
+            let ident = &quote! { field0 };
+            let ref_kw = match f.unnamed.last().unwrap().ty {
+                syn::Type::Reference(..) => quote! { },
+                _ => quote! { ref },
+            };
+
+            let ret_val = return_val_fn(ident);
+            quote! { (#ref_kw #ident) => #ret_val }
+        }
+        Fields::Named(f) if f.named.len() == 1 => {
+            let field = f.named.last().unwrap();
+            let ref_kw = match field.ty {
+                syn::Type::Reference(..) => quote! { },
+                _ => quote! { ref },
+            };
+
+            let ident = field.ident.as_ref().unwrap();
+            let ident = &quote! { #ident };
+            let ret_val = return_val_fn(ident);
+            quote! { { #ref_kw #ident} => #ret_val }
+        }
+        _ => return Err(NonSingleFieldEnum),
+    };
+
+    Ok(quote! { #name::#variant_ident #pattern_and_return })
+}
diff --git a/pseudo_crate/Cargo.lock b/pseudo_crate/Cargo.lock
index efb217e..86a03f9 100644
--- a/pseudo_crate/Cargo.lock
+++ b/pseudo_crate/Cargo.lock
@@ -5857,9 +5857,9 @@
 
 [[package]]
 name = "strum_macros"
-version = "0.26.4"
+version = "0.27.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
+checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
 dependencies = [
  "heck 0.5.0",
  "proc-macro2 1.0.93",
diff --git a/pseudo_crate/Cargo.toml b/pseudo_crate/Cargo.toml
index 040c107..7f1cfd4 100644
--- a/pseudo_crate/Cargo.toml
+++ b/pseudo_crate/Cargo.toml
@@ -342,7 +342,7 @@
 strck = "=1.0.0"
 strsim = "=0.11.1"
 strum = "=0.27.1"
-strum_macros = "=0.26.4"
+strum_macros = "=0.27.1"
 syn = "=2.0.98"
 syn-mid = "=0.6.0"
 sync_wrapper = "=1.0.2"