def _is_reachable( schema: s_schema.Schema, cast_kwargs: Mapping[str, bool], source: s_types.Type, target: s_types.Type, distance: int, ) -> int: if source == target: return distance casts = schema.get_casts_to_type(target, **cast_kwargs) if not casts: return _NOT_REACHABLE sources = {c.get_from_type(schema) for c in casts} distance += 1 if source in sources: return distance else: return min( _is_reachable(schema, cast_kwargs, source, s, distance) for s in sources )
def is_assignment_castable( schema: s_schema.Schema, source: s_types.Type, target: s_types.Type, ) -> bool: # Implicitly castable implies assignment castable. if is_implicitly_castable(schema, source, target): return True # Assignment casts are valid only as one-hop casts. casts = schema.get_casts_to_type(target, assignment=True) if not casts: return False for c in casts: if c.get_from_type(schema) == source: return True return False
def is_castable( schema: s_schema.Schema, source: s_types.Type, target: s_types.Type, ) -> bool: # Implicitly castable if is_implicitly_castable(schema, source, target): return True elif is_assignment_castable(schema, source, target): return True else: casts = schema.get_casts_to_type(target) if not casts: return False else: for c in casts: if c.get_from_type(schema) == source: return True else: return False