def to_proto(
        self, out: v2.device_pb2.DeviceSpecification | None = None
    ) -> v2.device_pb2.DeviceSpecification:
        """Serializes the GridDevice to a DeviceSpecification.

        Args:
            out: Optional DeviceSpecification to be populated. Fields are populated in-place.

        Returns:
            The populated DeviceSpecification if out is specified, or the newly created
            DeviceSpecification.
        """
        qubits = self._metadata.qubit_set
        unordered_pairs = [tuple(pair_set) for pair_set in self._metadata.qubit_pairs]
        pairs = sorted((q0, q1) if q0 <= q1 else (q1, q0) for q0, q1 in unordered_pairs)
        gateset = self._metadata.gateset
        gate_durations = self._metadata.gate_durations

        if out is None:
            out = v2.device_pb2.DeviceSpecification()

        # If fields are already filled (i.e. as part of the old DeviceSpecification format), leave
        # them as is. Fields populated in the new format do not conflict with how they were
        # populated in the old format.
        # TODO(#5050) remove empty checks below once deprecated fields in DeviceSpecification are
        # removed.

        if not out.valid_qubits:
            known_devices.populate_qubits_in_device_proto(qubits, out)
        if not out.valid_targets:
            known_devices.populate_qubit_pairs_in_device_proto(pairs, out)
        _serialize_gateset_and_gate_durations(
            out, gateset, {} if gate_durations is None else gate_durations
        )
        _validate_device_specification(out)

        return out
Serializes the GridDevice to a DeviceSpecification.

        Args:
            out: Optional DeviceSpecification to be populated. Fields are populated in-place.

        Returns:
            The populated DeviceSpecification if out is specified, or the newly created
            DeviceSpecification.
        
cirq-google/cirq_google/devices/grid_device.py