<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 async def serialize_properties(inputs: 'Inputs', property_deps: Dict[str, List['Resource']], input_transformer: Optional[Callable[[str], str]] = None) -> struct_pb2.Struct: """ Serializes an arbitrary Input bag into a Protobuf structure, keeping track of the list of dependent resources in the `deps` list. Serializing properties is inherently async because it awaits any futures that are contained transitively within the input bag. """

    struct = struct_pb2.Struct()
    for k, v in inputs.items():
        deps = []
        result = await serialize_property(v, deps, input_transformer)
        # We treat properties that serialize to None as if they don't exist.
        if result is not None:
            # While serializing to a pb struct, we must "translate" all key names to be what the engine is going to
            # expect. Resources provide the "transform" function for doing this.
            translated_name = k
            if input_transformer is not None:
                translated_name = input_transformer(k)
                log.debug(f"top-level input property translated: {k} -> {translated_name}")
            # pylint: disable=unsupported-assignment-operation
            struct[translated_name] = result
            property_deps[translated_name] = deps

    return struct