class_docstr: A column object, with only the methods and properties required by the
  interchange protocol defined.
  
  A column can contain one or more chunks. Each chunk can contain up to three
  buffers - a data buffer, a mask buffer (depending on null representation),
  and an offsets buffer (if variable-size binary; e.g., variable-length
  strings).
  
  Note: this Column object can only be produced by ``__dataframe__``, so
        doesn't need its own version or ``__column__`` protocol.
class_docstr_tok: ["A","column","object",",","with","only","the","methods","and","properties","required","by","the","interchange","protocol","defined",".","A","column","can","contain","one","or","more","chunks",".","Each","chunk","can","contain","up","to","three","buffers","-","a","data","buffer",",","a","mask","buffer","(","depending","on","null","representation",")",",","and","an","offsets","buffer","(","if","variable-size","binary",";","e.g.",",","variable-length","strings",")",".","Note",":","this","Column","object","can","only","be","produced","by","``","__dataframe__","``",",","so","does","n't","need","its","own","version","or","``","__column__","``","protocol","."]
docstr: See `self.dtype` for details.
code: def _dtype_from_cudfdtype(self, dtype) -> ProtoDtype:
      """
      See `self.dtype` for details.
      """
      # Note: 'c' (complex) not handled yet (not in array spec v1).
      #       'b', 'B' (bytes), 'S', 'a', (old-style string) 'V' (void)
      #       not handled datetime and timedelta both map to datetime
      #       (is timedelta handled?)
      _np_kinds = {
          "i": _DtypeKind.INT,
          "u": _DtypeKind.UINT,
          "f": _DtypeKind.FLOAT,
          "b": _DtypeKind.BOOL,
          "U": _DtypeKind.STRING,
          "M": _DtypeKind.DATETIME,
          "m": _DtypeKind.DATETIME,
      }
      kind = _np_kinds.get(dtype.kind, None)
      if kind is None:
          # Not a NumPy/CuPy dtype. Check if it's a categorical maybe
          if isinstance(dtype, cudf.CategoricalDtype):
              kind = _DtypeKind.CATEGORICAL
              # Codes and categories' dtypes are different.
              # We use codes' dtype as these are stored in the buffer.
              codes = cast(
                  cudf.core.column.CategoricalColumn, self._col
              ).codes
              dtype = codes.dtype
          else:
              raise ValueError(
                  f"Data type {dtype} not supported by exchange protocol"
              )
  
      if kind not in _SUPPORTED_KINDS:
          raise NotImplementedError(
              f"Data type {dtype} not handled yet"
          )
  
      bitwidth = dtype.itemsize * 8
      format_str = dtype.str
      endianness = (
          dtype.byteorder if kind != _DtypeKind.CATEGORICAL else "="
      )
      return (kind, bitwidth, format_str, endianness)
  
imports: import enum
  from collections import abc
  from typing import Any, Dict, Iterable, Mapping, Optional, Sequence, Tuple, cast
  import cupy
  import numpy
  from numba.cuda import as_cuda_array
  import rmm
  import cudf
  from cudf.core.buffer import Buffer, as_buffer
  from cudf.core.column import as_column, build_categorical_column, build_column
label_desc: Use image node_id 5 for calling the _CuDFColumn obj's underlying member method code with example usage: obj._dtype_from_cudfdtype(dtype) and returns: kind,  bitwidth,  format_str,  endianness