1
0

AnyWidget.swift 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. /// A type-erased widget which can be stored without having to propagate
  2. /// the selected backend type through the type system of the whole view graph
  3. /// system of types, which would leak it back into user view implementations
  4. /// making the backend hard to switch for developers.
  5. ///
  6. /// Uses the simplest kind of type erasure because we always know the
  7. /// widget type at time of use anyway so it can simply be cast back to
  8. /// a concrete type before use (removing the need to type-erase specific
  9. /// methods or anything like that).
  10. public class AnyWidget {
  11. /// The wrapped widget.
  12. var widget: Any
  13. /// Erases the specific type of a widget (to allow storage without propagating
  14. /// the selected backend type through the whole type system).
  15. ///
  16. /// - Parameter widget: The widget to type-erase.
  17. public init(_ widget: Any) {
  18. self.widget = widget
  19. }
  20. /// Converts the widget back to its original concrete type.
  21. ///
  22. /// - Precondition: `backend` is the same backend used to create the widget.
  23. ///
  24. /// - Parameter backend: The backend to use to convert the widget.
  25. /// - Returns: The widget as the backend's widget type.
  26. public func concreteWidget<Backend: BaseAppBackend>(
  27. for backend: Backend.Type
  28. ) -> Backend.Widget {
  29. guard let widget = widget as? Backend.Widget else {
  30. fatalError(
  31. "AnyWidget used with incompatible backend \(backend); widget type is \(type(of: widget))"
  32. )
  33. }
  34. return widget
  35. }
  36. /// Converts the widget back to its original concrete type.
  37. ///
  38. /// Often more concise than using ``AnyWidget/concreteWidget(for:)``.
  39. ///
  40. /// - Precondition: The underlying widget is of type `T`.
  41. ///
  42. /// - Returns: The converted widget.
  43. public func into<T>() -> T {
  44. guard let widget = widget as? T else {
  45. fatalError(
  46. "AnyWidget used with incompatible widget type \(T.self); actual widget type is \(type(of: widget))"
  47. )
  48. }
  49. return widget
  50. }
  51. }