fromSerializable<T> method

T? fromSerializable<T>()

Attempts to convert a serialized value to type T

Implementation

T? fromSerializable<T>() {
  final Object? self = this;

  if (self == null) return null;

  // Assert supported types early in development
  final String typeString = T.toString();
  assert(
    _isSupportedType(typeString),
    'Type $typeString is not supported for deserialization. '
    'Supported types:\n'
    '''• Simple types: int, double, String, bool, DateTime, Duration, Uri, Color, Object?, dynamic\n'''
    '''• Simple lists: List<int>, List<double>, List<String>, List<bool>, List<DateTime>, List<Duration>, List<Color>, List<Object?>\n'''
    '''• JSON map lists: List<Map<String, Object?>>, List<Map<String, dynamic>>\n'''
    '''• Simple maps: Map<String, int>, Map<String, double>, Map<String, String>, '''
    '''Map<String, bool>, Map<String, DateTime>, Map<String, Duration>, Map<String, Color>, Map<String, Object?>, Map<String, dynamic>\n\n'''
    '''For complex nested structures, create a model class that extends BaseDataModel.''',
  );

  // Direct type match
  if (self is T) return self as T?;

  // String type handling
  if (T == String) {
    return self.toString() as T?;
  }

  // Int type handling
  if (T == int) {
    if (self is int) return self as T?;
    if (self is double) return self.toInt() as T?;
    if (self is String) return int.tryParse(self) as T?;
    if (self is bool) return (self ? 1 : 0) as T?;
    return null;
  }

  // Double type handling
  if (T == double) {
    if (self is double) return self as T?;
    if (self is int) return self.toDouble() as T?;
    if (self is String) return double.tryParse(self) as T?;
    if (self is bool) return (self ? 1.0 : 0.0) as T?;
    return null;
  }

  // Bool type handling
  if (T == bool) {
    if (self is bool) return self as T?;
    if (self is int) return (self != 0) as T?;
    if (self is double) return (self != 0.0) as T?;
    if (self is String) {
      final String lower = self.toLowerCase();
      if (lower.compareWithoutCaseAny(<String>['true', '1', 'yes', 'on'])) {
        return true as T?;
      }
      if (lower.compareWithoutCaseAny(<String>['false', '0', 'no', 'off'])) {
        return false as T?;
      }
    }
    return null;
  }

  // DateTime type handling
  if (T == DateTime) {
    if (self is DateTime) return self as T?;
    if (self is String) {
      try {
        return DateTime.parse(self) as T?;
      } catch (e) {
        return null;
      }
    }
    if (self is int) {
      try {
        return DateTime.fromMillisecondsSinceEpoch(self) as T?;
      } catch (e) {
        return null;
      }
    }
    return null;
  }

  // Duration type handling
  if (T == Duration) {
    if (self is Duration) return self as T?;
    if (self is int) {
      try {
        return Duration(microseconds: self) as T?;
      } catch (e) {
        return null;
      }
    }
    if (self is String) {
      final int? microseconds = int.tryParse(self);
      if (microseconds != null) {
        try {
          return Duration(microseconds: microseconds) as T?;
        } catch (e) {
          return null;
        }
      }
    }
    return null;
  }

  // Uri type handling
  if (T == Uri) {
    if (self is Uri) return self as T?;
    if (self is String) {
      try {
        return Uri.parse(self) as T?;
      } catch (e) {
        return null;
      }
    }
    return null;
  }

  // Color type handling
  if (T == Color) {
    if (self is Color) return self as T?;
    if (self is String) {
      try {
        return self.toColor() as T?;
      } catch (e) {
        return null;
      }
    }
    return null;
  }

  if (T == Uint8List) {
    if (self is Uint8List) return self as T?;
    if (self is List<int>) {
      try {
        return Uint8List.fromList(self) as T?;
      } catch (e) {
        return null;
      }
    }
    if (self is String) {
      try {
        // Decode Base64 string to Uint8List
        return base64Decode(self) as T?;
      } catch (e) {
        // If Base64 decoding fails, try UTF-8 encoding as fallback
        try {
          return Uint8List.fromList(utf8.encode(self)) as T?;
        } catch (fallbackError) {
          return null;
        }
      }
    }
    return null;
  }

  // Map type handling - check if T is a Map type
  if (typeString.startsWith('Map')) {
    final Map<String, Object?>? mapResult = toMap();
    if (mapResult == null) return null;

    // Handle specific common map types to maintain proper typing
    if (T == Map<String, int>) {
      return mapResult.map(
            (String key, Object? value) =>
                MapEntry<String, int>(key, _safeInt(value)),
          )
          as T?;
    }
    if (T == Map<String, double>) {
      return mapResult.map(
            (String key, Object? value) =>
                MapEntry<String, double>(key, _safeDouble(value)),
          )
          as T?;
    }
    if (T == Map<String, String>) {
      return mapResult.map(
            (String key, Object? value) =>
                MapEntry<String, String>(key, _safeString(value)),
          )
          as T?;
    }
    if (T == Map<String, bool>) {
      return mapResult.map(
            (String key, Object? value) =>
                MapEntry<String, bool>(key, _safeBool(value)),
          )
          as T?;
    }
    if (T == Map<String, DateTime>) {
      return mapResult.map(
            (String key, Object? value) =>
                MapEntry<String, DateTime>(key, _safeDateTime(value)),
          )
          as T?;
    }
    if (T == Map<String, Duration>) {
      return mapResult.map(
            (String key, Object? value) =>
                MapEntry<String, Duration>(key, _safeDuration(value)),
          )
          as T?;
    }
    if (T == Map<String, Color>) {
      return mapResult.map(
            (String key, Object? value) =>
                MapEntry<String, Color>(key, _safeColor(value)),
          )
          as T?;
    }
    if (T == Map<String, Object?>) {
      return mapResult as T?;
    }
    if (T == Map<String, dynamic>) {
      return mapResult.cast<String, Object?>() as T?;
    }

    // Note: Unsupported types are caught by assert at method start
    // Default fallback for simple unsupported types
    return mapResult as T?;
  }

  // List type handling - check if T is a List type
  if (typeString.startsWith('List')) {
    final List<Object?>? listResult = toList();
    if (listResult == null) return null;

    // Handle only simple typed lists and common map lists
    if (T == List<int>) {
      return listResult.map(_safeInt).toList() as T?;
    }
    if (T == List<double>) {
      return listResult.map(_safeDouble).toList() as T?;
    }
    if (T == List<String>) {
      return listResult.map(_safeString).toList() as T?;
    }
    if (T == List<bool>) {
      return listResult.map(_safeBool).toList() as T?;
    }
    if (T == List<DateTime>) {
      return listResult.map(_safeDateTime).toList() as T?;
    }
    if (T == List<Duration>) {
      return listResult.map(_safeDuration).toList() as T?;
    }
    if (T == List<Color>) {
      return listResult.map(_safeColor).toList() as T?;
    }
    if (T == List<Object?>) {
      return listResult as T?;
    }

    // Handle common map list types for JSON data
    if (T == List<Map<String, Object?>>) {
      return listResult.map(_safeMap).toList() as T?;
    }
    if (T == List<Map<String, dynamic>>) {
      return listResult.map(_safeMapDynamic).toList() as T?;
    }

    // Note: Unsupported types are caught by assert at method start

    // Default fallback for simple unsupported types
    return listResult as T?;
  }

  // Map type handling - check if T is a Map type
  if (typeString.startsWith('Map')) {
    final Map<String, Object?>? mapResult = toMap();
    if (mapResult == null) return null;
  }

  // Collection types - return as-is if type matches
  if (self is T) {
    return self as T;
  }

  // JSON string parsing for collections
  if (self is String) {
    try {
      final Object? decoded = SafeParser.safeDecodeJson(self);
      if (decoded is T) return decoded;
    } catch (e) {
      // Ignore JSON parsing errors
    }
  }

  return null;
}