Repository: 1Password/typeshare (rust)

Issue:
Write generic decorators to enums with associated types as well
In Swift, default_generic_decorators will apply the decorators to associated generic types on `struct`s, but does not do so for `enum`s. It should write them out to `enum`s as well.

Pull request:
Apply generic constraints to enums
This MR applies default generic constraints to Swift enums with associated values in the same way that it does for structs.

Resolves #121 

Patch:
diff --git a/core/src/language/swift.rs b/core/src/language/swift.rs
index 72c96d4..fdf5282 100644
--- a/core/src/language/swift.rs
+++ b/core/src/language/swift.rs
@@ -442,6 +442,10 @@ impl Language for Swift {
 
         self.write_comments(w, 0, &shared.comments)?;
         let indirect = if shared.is_recursive { "indirect " } else { "" };
+        let generic_constraint_string = self
+            .default_generic_constraints
+            .get_constraints()
+            .join(" & ");
         writeln!(
             w,
             "public {}enum {}{}: {} {{",
@@ -449,8 +453,18 @@ impl Language for Swift {
             enum_name,
             (!e.shared().generic_types.is_empty())
                 .then(|| format!(
-                    "<{}: Codable>",
-                    e.shared().generic_types.join(": Codable, ")
+                    "<{}>",
+                    e.shared()
+                        .generic_types
+                        .iter()
+                        .map(|t| format!(
+                            "{}{}",
+                            t,
+                            (!generic_constraint_string.is_empty())
+                                .then(|| format!(": {}", generic_constraint_string))
+                                .unwrap_or_default()
+                        ))
+                        .join(", ")
                 ))
                 .unwrap_or_default(),
             decs.join(", ")


Test patch:
diff --git a/core/data/tests/test_default_generic_constraints/input.rs b/core/data/tests/test_default_generic_constraints/input.rs
index 429c6ae..527a52d 100644
--- a/core/data/tests/test_default_generic_constraints/input.rs
+++ b/core/data/tests/test_default_generic_constraints/input.rs
@@ -1,4 +1,14 @@
 #[typeshare]
-struct GenericType<T> {
-    field: T
+struct GenericType<K, V> {
+    key: K,
+    value: V
+}
+
+#[typeshare]
+#[serde(tag = "type", content = "content")]
+enum GenericEnum<K, V> {
+    Variant {
+        key: K,
+        value: V
+    }
 }
\ No newline at end of file
diff --git a/core/data/tests/test_default_generic_constraints/output.swift b/core/data/tests/test_default_generic_constraints/output.swift
index 628a654..a555c71 100644
--- a/core/data/tests/test_default_generic_constraints/output.swift
+++ b/core/data/tests/test_default_generic_constraints/output.swift
@@ -1,9 +1,57 @@
 import Foundation
 
-public struct GenericType<T: Codable & Identifiable & Sendable>: Codable {
-	public let field: T
+public struct GenericType<K: Codable & Identifiable & Sendable, V: Codable & Identifiable & Sendable>: Codable {
+	public let key: K
+	public let value: V
 
-	public init(field: T) {
-		self.field = field
+	public init(key: K, value: V) {
+		self.key = key
+		self.value = value
+	}
+}
+
+
+/// Generated type representing the anonymous struct variant `Variant` of the `GenericEnum` Rust enum
+public struct GenericEnumVariantInner<K: Codable & Identifiable & Sendable, V: Codable & Identifiable & Sendable>: Codable {
+	public let key: K
+	public let value: V
+
+	public init(key: K, value: V) {
+		self.key = key
+		self.value = value
+	}
+}
+public enum GenericEnum<K: Codable & Identifiable & Sendable, V: Codable & Identifiable & Sendable>: Codable {
+	case variant(GenericEnumVariantInner<K, V>)
+
+	enum CodingKeys: String, CodingKey, Codable {
+		case variant = "Variant"
+	}
+
+	private enum ContainerCodingKeys: String, CodingKey {
+		case type, content
+	}
+
+	public init(from decoder: Decoder) throws {
+		let container = try decoder.container(keyedBy: ContainerCodingKeys.self)
+		if let type = try? container.decode(CodingKeys.self, forKey: .type) {
+			switch type {
+			case .variant:
+				if let content = try? container.decode(GenericEnumVariantInner<K, V>.self, forKey: .content) {
+					self = .variant(content)
+					return
+				}
+			}
+		}
+		throw DecodingError.typeMismatch(GenericEnum.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for GenericEnum"))
+	}
+
+	public func encode(to encoder: Encoder) throws {
+		var container = encoder.container(keyedBy: ContainerCodingKeys.self)
+		switch self {
+		case .variant(let content):
+			try container.encode(CodingKeys.variant, forKey: .type)
+			try container.encode(content, forKey: .content)
+		}
 	}
 }