Generated by Cython 3.1.6

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

Raw output: csv_reader.cpp

+001: """Cython wrapper for reading CSV/TSV files."""
  __pyx_t_2 = __Pyx_PyDict_NewPresized(4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 1, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_get_csv_schema_line_65, __pyx_mstate_global->__pyx_kp_u_Extract_schema_information_from) < (0)) __PYX_ERR(0, 1, __pyx_L1_error)
  if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_read_csv_line_158, __pyx_mstate_global->__pyx_kp_u_Read_CSV_data_into_columnar_for) < (0)) __PYX_ERR(0, 1, __pyx_L1_error)
  if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_detect_csv_dialect_line_325, __pyx_mstate_global->__pyx_kp_u_Auto_detect_CSV_dialect_delimit) < (0)) __PYX_ERR(0, 1, __pyx_L1_error)
  if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_kp_u_read_tsv_line_382, __pyx_mstate_global->__pyx_kp_u_Read_TSV_tab_separated_values_d) < (0)) __PYX_ERR(0, 1, __pyx_L1_error)
  if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_test, __pyx_t_2) < (0)) __PYX_ERR(0, 1, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 002: 
 003: # distutils: language = c++
 004: # cython: language_level=3
 005: # cython: nonecheck=False
 006: # cython: cdivision=True
 007: # cython: boundscheck=False
 008: # cython: wraparound=False
 009: # cython: infer_types=True
 010: 
 011: from libc.stdint cimport uint8_t
 012: from libcpp.string cimport string
 013: from libcpp.vector cimport vector
 014: from libcpp cimport bool as cbool
 015: from cpython.buffer cimport PyBUF_CONTIG_RO, PyObject_GetBuffer, PyBuffer_Release, Py_buffer
 016: 
 017: 
 018: # C++ declarations from csv_parser.hpp
 019: cdef extern from "csv_parser.hpp":
 020:     cdef enum CsvType:
 021:         Null "CsvType::Null"
 022:         Boolean "CsvType::Boolean"
 023:         Integer "CsvType::Integer"
 024:         Double "CsvType::Double"
 025:         String "CsvType::String"
 026: 
 027:     cdef cppclass CsvColumnSchema:
 028:         string name
 029:         CsvType type
 030:         cbool nullable
 031: 
 032:     cdef cppclass CsvColumn:
 033:         vector[long long] int_values
 034:         vector[double] double_values
 035:         vector[string] string_values
 036:         vector[uint8_t] boolean_values
 037:         vector[uint8_t] null_mask
 038:         string type
 039:         cbool success
 040: 
 041:     cdef cppclass CsvTable:
 042:         vector[CsvColumn] columns
 043:         vector[string] column_names
 044:         size_t num_rows
 045:         cbool success
 046: 
 047:     cdef cppclass CsvDialect:
 048:         char delimiter
 049:         char quote_char
 050:         char escape_char
 051:         cbool double_quote
 052:         cbool has_header
 053: 
 054:     vector[CsvColumnSchema] GetCsvSchema(const uint8_t* data, size_t size,
 055:                                          const CsvDialect& dialect, size_t sample_size)
 056: 
 057:     CsvTable ReadCsv(const uint8_t* data, size_t size, const CsvDialect& dialect)
 058: 
 059:     CsvTable ReadCsv(const uint8_t* data, size_t size, const CsvDialect& dialect,
 060:                      const vector[string]& column_names)
 061: 
 062:     CsvDialect DetectCsvDialect(const uint8_t* data, size_t size, size_t sample_size)
 063: 
 064: 
+065: def get_csv_schema(data, delimiter=',', quote_char='"', sample_size=100, has_header=True):
/* Python wrapper */
static PyObject *__pyx_pw_4rugo_3csv_1get_csv_schema(PyObject *__pyx_self, 
#if CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
); /*proto*/
PyDoc_STRVAR(__pyx_doc_4rugo_3csv_get_csv_schema, "\n    Extract schema information from CSV data.\n    \n    Parameters\n    ----------\n    data : bytes or memoryview\n        The CSV data to analyze\n    delimiter : str, default ','\n        Field delimiter character (use '\\t' for TSV)\n    quote_char : str, default '\"'\n        Quote character for fields\n    sample_size : int, default 100\n        Number of rows to sample for type inference\n    has_header : bool, default True\n        Whether the first line contains column names\n    \n    Returns\n    -------\n    list of dict\n        List of column schemas with keys: name, type, nullable\n        \n    Examples\n    --------\n    >>> data = b'name,age,salary\\nAlice,30,50000\\nBob,25,45000'\n    >>> schema = get_csv_schema(data)\n    >>> for col in schema:\n    ...     print(f\"{col['name']}: {col['type']}\")\n    name: string\n    age: int64\n    salary: int64\n    ");
static PyMethodDef __pyx_mdef_4rugo_3csv_1get_csv_schema = {"get_csv_schema", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_4rugo_3csv_1get_csv_schema, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_4rugo_3csv_get_csv_schema};
static PyObject *__pyx_pw_4rugo_3csv_1get_csv_schema(PyObject *__pyx_self, 
#if CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
) {
  PyObject *__pyx_v_data = 0;
  PyObject *__pyx_v_delimiter = 0;
  PyObject *__pyx_v_quote_char = 0;
  PyObject *__pyx_v_sample_size = 0;
  PyObject *__pyx_v_has_header = 0;
  #if !CYTHON_METH_FASTCALL
  CYTHON_UNUSED Py_ssize_t __pyx_nargs;
  #endif
  CYTHON_UNUSED PyObject *const *__pyx_kwvalues;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("get_csv_schema (wrapper)", 0);
  #if !CYTHON_METH_FASTCALL
  #if CYTHON_ASSUME_SAFE_SIZE
  __pyx_nargs = PyTuple_GET_SIZE(__pyx_args);
  #else
  __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL;
  #endif
  #endif
  __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs);
  {
    PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_data,&__pyx_mstate_global->__pyx_n_u_delimiter,&__pyx_mstate_global->__pyx_n_u_quote_char,&__pyx_mstate_global->__pyx_n_u_sample_size,&__pyx_mstate_global->__pyx_n_u_has_header,0};
  PyObject* values[5] = {0,0,0,0,0};
    const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0;
    if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 65, __pyx_L3_error)
    if (__pyx_kwds_len > 0) {
      switch (__pyx_nargs) {
        case  5:
        values[4] = __Pyx_ArgRef_FASTCALL(__pyx_args, 4);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[4])) __PYX_ERR(0, 65, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  4:
        values[3] = __Pyx_ArgRef_FASTCALL(__pyx_args, 3);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[3])) __PYX_ERR(0, 65, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  3:
        values[2] = __Pyx_ArgRef_FASTCALL(__pyx_args, 2);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[2])) __PYX_ERR(0, 65, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  2:
        values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 65, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  1:
        values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 65, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      const Py_ssize_t kwd_pos_args = __pyx_nargs;
      if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "get_csv_schema", 0) < (0)) __PYX_ERR(0, 65, __pyx_L3_error)
      if (!values[1]) values[1] = __Pyx_NewRef(((PyObject *)((PyObject*)__pyx_mstate_global->__pyx_kp_u_)));
      if (!values[2]) values[2] = __Pyx_NewRef(((PyObject *)((PyObject*)__pyx_mstate_global->__pyx_kp_u__2)));
      if (!values[3]) values[3] = __Pyx_NewRef(((PyObject *)((PyObject*)__pyx_mstate_global->__pyx_int_100)));
      if (!values[4]) values[4] = __Pyx_NewRef(((PyObject *)((PyObject*)Py_True)));
      for (Py_ssize_t i = __pyx_nargs; i < 1; i++) {
        if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("get_csv_schema", 0, 1, 5, i); __PYX_ERR(0, 65, __pyx_L3_error) }
      }
    } else {
      switch (__pyx_nargs) {
        case  5:
        values[4] = __Pyx_ArgRef_FASTCALL(__pyx_args, 4);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[4])) __PYX_ERR(0, 65, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  4:
        values[3] = __Pyx_ArgRef_FASTCALL(__pyx_args, 3);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[3])) __PYX_ERR(0, 65, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  3:
        values[2] = __Pyx_ArgRef_FASTCALL(__pyx_args, 2);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[2])) __PYX_ERR(0, 65, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  2:
        values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 65, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  1:
        values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 65, __pyx_L3_error)
        break;
        default: goto __pyx_L5_argtuple_error;
      }
      if (!values[1]) values[1] = __Pyx_NewRef(((PyObject *)((PyObject*)__pyx_mstate_global->__pyx_kp_u_)));
      if (!values[2]) values[2] = __Pyx_NewRef(((PyObject *)((PyObject*)__pyx_mstate_global->__pyx_kp_u__2)));
      if (!values[3]) values[3] = __Pyx_NewRef(((PyObject *)((PyObject*)__pyx_mstate_global->__pyx_int_100)));
      if (!values[4]) values[4] = __Pyx_NewRef(((PyObject *)((PyObject*)Py_True)));
    }
    __pyx_v_data = values[0];
    __pyx_v_delimiter = values[1];
    __pyx_v_quote_char = values[2];
    __pyx_v_sample_size = values[3];
    __pyx_v_has_header = values[4];
  }
  goto __pyx_L6_skip;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("get_csv_schema", 0, 1, 5, __pyx_nargs); __PYX_ERR(0, 65, __pyx_L3_error)
  __pyx_L6_skip:;
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L3_error:;
  for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
    Py_XDECREF(values[__pyx_temp]);
  }
  __Pyx_AddTraceback("rugo.csv.get_csv_schema", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_4rugo_3csv_get_csv_schema(__pyx_self, __pyx_v_data, __pyx_v_delimiter, __pyx_v_quote_char, __pyx_v_sample_size, __pyx_v_has_header);

  /* function exit code */
  for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
    Py_XDECREF(values[__pyx_temp]);
  }
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_4rugo_3csv_get_csv_schema(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_data, PyObject *__pyx_v_delimiter, PyObject *__pyx_v_quote_char, PyObject *__pyx_v_sample_size, PyObject *__pyx_v_has_header) {
  uint8_t const *__pyx_v_data_ptr;
  size_t __pyx_v_data_size;
  PyObject *__pyx_v_data_bytes = 0;
  Py_buffer __pyx_v_view;
  bool __pyx_v_have_view;
  CsvDialect __pyx_v_dialect;
  std::vector<CsvColumnSchema>  __pyx_v_schema;
  PyObject *__pyx_v_result = NULL;
  size_t __pyx_v_i;
  int __pyx_v_type_val;
  PyObject *__pyx_v_type_str = NULL;
  PyObject *__pyx_r = NULL;
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_6);
  __Pyx_XDECREF(__pyx_t_7);
  __Pyx_XDECREF(__pyx_t_8);
  __Pyx_XDECREF(__pyx_t_9);
  __Pyx_AddTraceback("rugo.csv.get_csv_schema", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XDECREF(__pyx_v_data_bytes);
  __Pyx_XDECREF(__pyx_v_result);
  __Pyx_XDECREF(__pyx_v_type_str);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_4rugo_3csv_1get_csv_schema, 0, __pyx_mstate_global->__pyx_n_u_get_csv_schema, NULL, __pyx_mstate_global->__pyx_n_u_rugo_csv, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[0])); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 65, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_2, __pyx_mstate_global->__pyx_tuple[0]);
  if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_get_csv_schema, __pyx_t_2) < (0)) __PYX_ERR(0, 65, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* … */
  __pyx_mstate_global->__pyx_tuple[0] = PyTuple_Pack(4, ((PyObject*)__pyx_mstate_global->__pyx_kp_u_), ((PyObject*)__pyx_mstate_global->__pyx_kp_u__2), ((PyObject*)__pyx_mstate_global->__pyx_int_100), ((PyObject*)Py_True)); if (unlikely(!__pyx_mstate_global->__pyx_tuple[0])) __PYX_ERR(0, 65, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_mstate_global->__pyx_tuple[0]);
  __Pyx_GIVEREF(__pyx_mstate_global->__pyx_tuple[0]);
 066:     """
 067:     Extract schema information from CSV data.
 068: 
 069:     Parameters
 070:     ----------
 071:     data : bytes or memoryview
 072:         The CSV data to analyze
 073:     delimiter : str, default ','
 074:         Field delimiter character (use '\\t' for TSV)
 075:     quote_char : str, default '"'
 076:         Quote character for fields
 077:     sample_size : int, default 100
 078:         Number of rows to sample for type inference
 079:     has_header : bool, default True
 080:         Whether the first line contains column names
 081: 
 082:     Returns
 083:     -------
 084:     list of dict
 085:         List of column schemas with keys: name, type, nullable
 086: 
 087:     Examples
 088:     --------
 089:     >>> data = b'name,age,salary\\nAlice,30,50000\\nBob,25,45000'
 090:     >>> schema = get_csv_schema(data)
 091:     >>> for col in schema:
 092:     ...     print(f"{col['name']}: {col['type']}")
 093:     name: string
 094:     age: int64
 095:     salary: int64
 096:     """
 097:     cdef const uint8_t* data_ptr
 098:     cdef size_t data_size
 099:     cdef bytes data_bytes
 100:     cdef Py_buffer view
+101:     cdef cbool have_view = False
  __pyx_v_have_view = 0;
 102: 
 103:     # Handle different input types
+104:     if isinstance(data, memoryview):
  __pyx_t_1 = PyMemoryView_Check(__pyx_v_data); 
  if (__pyx_t_1) {
/* … */
    goto __pyx_L3;
  }
+105:         PyObject_GetBuffer(data.obj, &view, PyBUF_CONTIG_RO)
    __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_data, __pyx_mstate_global->__pyx_n_u_obj); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 105, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __pyx_t_3 = PyObject_GetBuffer(__pyx_t_2, (&__pyx_v_view), PyBUF_CONTIG_RO); if (unlikely(__pyx_t_3 == ((int)-1))) __PYX_ERR(0, 105, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+106:         data_ptr = <const uint8_t*>view.buf
    __pyx_v_data_ptr = ((uint8_t const *)__pyx_v_view.buf);
+107:         data_size = view.len
    __pyx_t_4 = __pyx_v_view.len;
    __pyx_v_data_size = __pyx_t_4;
+108:         have_view = True
    __pyx_v_have_view = 1;
+109:     elif isinstance(data, bytes):
  __pyx_t_1 = PyBytes_Check(__pyx_v_data); 
  if (likely(__pyx_t_1)) {
/* … */
    goto __pyx_L3;
  }
+110:         data_bytes = data
    __pyx_t_2 = __pyx_v_data;
    __Pyx_INCREF(__pyx_t_2);
    if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None) || __Pyx_RaiseUnexpectedTypeError("bytes", __pyx_t_2))) __PYX_ERR(0, 110, __pyx_L1_error)
    __pyx_v_data_bytes = ((PyObject*)__pyx_t_2);
    __pyx_t_2 = 0;
+111:         data_ptr = <const uint8_t*><char*>data_bytes
    if (unlikely(__pyx_v_data_bytes == Py_None)) {
      PyErr_SetString(PyExc_TypeError, "expected bytes, NoneType found");
      __PYX_ERR(0, 111, __pyx_L1_error)
    }
    __pyx_t_5 = __Pyx_PyBytes_AsWritableString(__pyx_v_data_bytes); if (unlikely((!__pyx_t_5) && PyErr_Occurred())) __PYX_ERR(0, 111, __pyx_L1_error)
    __pyx_v_data_ptr = ((uint8_t const *)((char *)__pyx_t_5));
+112:         data_size = len(data_bytes)
    if (unlikely(__pyx_v_data_bytes == Py_None)) {
      PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()");
      __PYX_ERR(0, 112, __pyx_L1_error)
    }
    __pyx_t_4 = __Pyx_PyBytes_GET_SIZE(__pyx_v_data_bytes); if (unlikely(__pyx_t_4 == ((Py_ssize_t)-1))) __PYX_ERR(0, 112, __pyx_L1_error)
    __pyx_v_data_size = __pyx_t_4;
 113:     else:
+114:         raise TypeError(f"Expected bytes or memoryview, got {type(data)}")
  /*else*/ {
    __pyx_t_6 = NULL;
    __Pyx_INCREF(__pyx_builtin_TypeError);
    __pyx_t_7 = __pyx_builtin_TypeError; 
    __pyx_t_8 = __Pyx_PyObject_FormatSimple(((PyObject *)Py_TYPE(__pyx_v_data)), __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 114, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_8);
    __pyx_t_9 = __Pyx_PyUnicode_Concat(__pyx_mstate_global->__pyx_kp_u_Expected_bytes_or_memoryview_got, __pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 114, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_9);
    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
    __pyx_t_10 = 1;
    {
      PyObject *__pyx_callargs[2] = {__pyx_t_6, __pyx_t_9};
      __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_7, __pyx_callargs+__pyx_t_10, (2-__pyx_t_10) | (__pyx_t_10*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET));
      __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
      __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
      if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 114, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_2);
    }
    __Pyx_Raise(__pyx_t_2, 0, 0, 0);
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __PYX_ERR(0, 114, __pyx_L1_error)
  }
  __pyx_L3:;
 115: 
 116:     # Setup dialect
 117:     cdef CsvDialect dialect
+118:     dialect.delimiter = ord(delimiter[0]) if delimiter else ord(',')
  __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_v_delimiter); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 118, __pyx_L1_error)
  if (__pyx_t_1) {
    __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_delimiter, 0, long, 1, __Pyx_PyLong_From_long, 0, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 118, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __pyx_t_12 = __Pyx_PyObject_Ord(__pyx_t_2); if (unlikely(__pyx_t_12 == ((long)(long)(Py_UCS4)-1))) __PYX_ERR(0, 118, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __pyx_t_11 = __pyx_t_12;
  } else {
    __pyx_t_11 = 44;
  }
  __pyx_v_dialect.delimiter = __pyx_t_11;
+119:     dialect.quote_char = ord(quote_char[0]) if quote_char else ord('"')
  __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_v_quote_char); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 119, __pyx_L1_error)
  if (__pyx_t_1) {
    __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_quote_char, 0, long, 1, __Pyx_PyLong_From_long, 0, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 119, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __pyx_t_12 = __Pyx_PyObject_Ord(__pyx_t_2); if (unlikely(__pyx_t_12 == ((long)(long)(Py_UCS4)-1))) __PYX_ERR(0, 119, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __pyx_t_11 = __pyx_t_12;
  } else {
    __pyx_t_11 = 34;
  }
  __pyx_v_dialect.quote_char = __pyx_t_11;
+120:     dialect.escape_char = ord('\\')
  __pyx_v_dialect.escape_char = 92;
+121:     dialect.double_quote = True
  __pyx_v_dialect.double_quote = 1;
+122:     dialect.has_header = has_header
  __pyx_t_13 = __Pyx_PyObject_IsTrue(__pyx_v_has_header); if (unlikely((__pyx_t_13 == ((bool)-1)) && PyErr_Occurred())) __PYX_ERR(0, 122, __pyx_L1_error)
  __pyx_v_dialect.has_header = __pyx_t_13;
 123: 
 124:     # Get schema
+125:     cdef vector[CsvColumnSchema] schema = GetCsvSchema(data_ptr, data_size, dialect, sample_size)
  __pyx_t_10 = __Pyx_PyLong_As_size_t(__pyx_v_sample_size); if (unlikely((__pyx_t_10 == (size_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 125, __pyx_L1_error)
  __pyx_v_schema = GetCsvSchema(__pyx_v_data_ptr, __pyx_v_data_size, __pyx_v_dialect, __pyx_t_10);
 126: 
+127:     if have_view:
  __pyx_t_1 = (__pyx_v_have_view != 0);
  if (__pyx_t_1) {
/* … */
  }
+128:         PyBuffer_Release(&view)
    PyBuffer_Release((&__pyx_v_view));
 129: 
 130:     # Convert to Python
+131:     result = []
  __pyx_t_2 = PyList_New(0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 131, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_v_result = ((PyObject*)__pyx_t_2);
  __pyx_t_2 = 0;
 132:     cdef size_t i
 133:     cdef int type_val
 134: 
+135:     for i in range(schema.size()):
  __pyx_t_14 = __pyx_v_schema.size();
  __pyx_t_15 = __pyx_t_14;
  for (__pyx_t_10 = 0; __pyx_t_10 < __pyx_t_15; __pyx_t_10+=1) {
    __pyx_v_i = __pyx_t_10;
+136:         type_val = <int>schema[i].type
    __pyx_v_type_val = ((int)(__pyx_v_schema[__pyx_v_i]).type);
 137: 
+138:         if type_val == <int>CsvType.Integer:
    __pyx_t_1 = (__pyx_v_type_val == ((int)CsvType::Integer));
    if (__pyx_t_1) {
/* … */
      goto __pyx_L7;
    }
+139:             type_str = "int64"
      __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_int64);
      __Pyx_XDECREF_SET(__pyx_v_type_str, __pyx_mstate_global->__pyx_n_u_int64);
+140:         elif type_val == <int>CsvType.Double:
    __pyx_t_1 = (__pyx_v_type_val == ((int)CsvType::Double));
    if (__pyx_t_1) {
/* … */
      goto __pyx_L7;
    }
+141:             type_str = "double"
      __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_double);
      __Pyx_XDECREF_SET(__pyx_v_type_str, __pyx_mstate_global->__pyx_n_u_double);
+142:         elif type_val == <int>CsvType.Boolean:
    __pyx_t_1 = (__pyx_v_type_val == ((int)CsvType::Boolean));
    if (__pyx_t_1) {
/* … */
      goto __pyx_L7;
    }
+143:             type_str = "boolean"
      __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_boolean);
      __Pyx_XDECREF_SET(__pyx_v_type_str, __pyx_mstate_global->__pyx_n_u_boolean);
+144:         elif type_val == <int>CsvType.String:
    __pyx_t_1 = (__pyx_v_type_val == ((int)CsvType::String));
    if (__pyx_t_1) {
/* … */
      goto __pyx_L7;
    }
+145:             type_str = "string"
      __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_string);
      __Pyx_XDECREF_SET(__pyx_v_type_str, __pyx_mstate_global->__pyx_n_u_string);
 146:         else:
+147:             type_str = "string"
    /*else*/ {
      __Pyx_INCREF(__pyx_mstate_global->__pyx_n_u_string);
      __Pyx_XDECREF_SET(__pyx_v_type_str, __pyx_mstate_global->__pyx_n_u_string);
    }
    __pyx_L7:;
 148: 
+149:         result.append({
    __pyx_t_16 = __Pyx_PyList_Append(__pyx_v_result, __pyx_t_2); if (unlikely(__pyx_t_16 == ((int)-1))) __PYX_ERR(0, 149, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  }
+150:             'name': schema[i].name.decode('utf-8'),
    __pyx_t_2 = __Pyx_PyDict_NewPresized(3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 150, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __pyx_t_7 = __Pyx_decode_cpp_string((__pyx_v_schema[__pyx_v_i]).name, 0, PY_SSIZE_T_MAX, NULL, NULL, PyUnicode_DecodeUTF8); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 150, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_7);
    if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_name, __pyx_t_7) < (0)) __PYX_ERR(0, 150, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+151:             'type': type_str,
    if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_type, __pyx_v_type_str) < (0)) __PYX_ERR(0, 150, __pyx_L1_error)
+152:             'nullable': schema[i].nullable
    __pyx_t_7 = __Pyx_PyBool_FromLong((__pyx_v_schema[__pyx_v_i]).nullable); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 152, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_7);
    if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_nullable, __pyx_t_7) < (0)) __PYX_ERR(0, 150, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
 153:         })
 154: 
+155:     return result
  __Pyx_XDECREF(__pyx_r);
  __Pyx_INCREF(__pyx_v_result);
  __pyx_r = __pyx_v_result;
  goto __pyx_L0;
 156: 
 157: 
+158: def read_csv(data, columns=None, delimiter=',', quote_char='"', has_header=True):
/* Python wrapper */
static PyObject *__pyx_pw_4rugo_3csv_3read_csv(PyObject *__pyx_self, 
#if CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
); /*proto*/
PyDoc_STRVAR(__pyx_doc_4rugo_3csv_2read_csv, "\n    Read CSV data into columnar format.\n    \n    Parameters\n    ----------\n    data : bytes or memoryview\n        The CSV data to read\n    columns : list of str, optional\n        List of column names to read. If None, reads all columns.\n    delimiter : str, default ','\n        Field delimiter character (use '\\t' for TSV)\n    quote_char : str, default '\"'\n        Quote character for fields\n    has_header : bool, default True\n        Whether the first line contains column names\n    \n    Returns\n    -------\n    dict\n        Dictionary with keys:\n        - success: bool - Whether reading succeeded\n        - num_rows: int - Number of rows read\n        - column_names: list of str - Column names\n        - columns: list of list - Column data (one list per column)\n        \n    Examples\n    --------\n    >>> data = b'name,age,salary\\nAlice,30,50000\\nBob,25,45000'\n    >>> result = read_csv(data)\n    >>> print(result['column_names'])\n    ['name', 'age', 'salary']\n    >>> print(result['columns'][0])  # name column\n    ['Alice', 'Bob']\n    \n    >>> # Read with projection\n    >>> result = read_csv(data, columns=['name', 'salary'])\n    >>> print(result['column_names'])\n    ['name', 'salary']\n    ");
static PyMethodDef __pyx_mdef_4rugo_3csv_3read_csv = {"read_csv", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_4rugo_3csv_3read_csv, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_4rugo_3csv_2read_csv};
static PyObject *__pyx_pw_4rugo_3csv_3read_csv(PyObject *__pyx_self, 
#if CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
) {
  PyObject *__pyx_v_data = 0;
  PyObject *__pyx_v_columns = 0;
  PyObject *__pyx_v_delimiter = 0;
  PyObject *__pyx_v_quote_char = 0;
  PyObject *__pyx_v_has_header = 0;
  #if !CYTHON_METH_FASTCALL
  CYTHON_UNUSED Py_ssize_t __pyx_nargs;
  #endif
  CYTHON_UNUSED PyObject *const *__pyx_kwvalues;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("read_csv (wrapper)", 0);
  #if !CYTHON_METH_FASTCALL
  #if CYTHON_ASSUME_SAFE_SIZE
  __pyx_nargs = PyTuple_GET_SIZE(__pyx_args);
  #else
  __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL;
  #endif
  #endif
  __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs);
  {
    PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_data,&__pyx_mstate_global->__pyx_n_u_columns,&__pyx_mstate_global->__pyx_n_u_delimiter,&__pyx_mstate_global->__pyx_n_u_quote_char,&__pyx_mstate_global->__pyx_n_u_has_header,0};
  PyObject* values[5] = {0,0,0,0,0};
    const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0;
    if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 158, __pyx_L3_error)
    if (__pyx_kwds_len > 0) {
      switch (__pyx_nargs) {
        case  5:
        values[4] = __Pyx_ArgRef_FASTCALL(__pyx_args, 4);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[4])) __PYX_ERR(0, 158, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  4:
        values[3] = __Pyx_ArgRef_FASTCALL(__pyx_args, 3);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[3])) __PYX_ERR(0, 158, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  3:
        values[2] = __Pyx_ArgRef_FASTCALL(__pyx_args, 2);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[2])) __PYX_ERR(0, 158, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  2:
        values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 158, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  1:
        values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 158, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      const Py_ssize_t kwd_pos_args = __pyx_nargs;
      if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "read_csv", 0) < (0)) __PYX_ERR(0, 158, __pyx_L3_error)
      if (!values[1]) values[1] = __Pyx_NewRef(((PyObject *)Py_None));
      if (!values[2]) values[2] = __Pyx_NewRef(((PyObject *)((PyObject*)__pyx_mstate_global->__pyx_kp_u_)));
      if (!values[3]) values[3] = __Pyx_NewRef(((PyObject *)((PyObject*)__pyx_mstate_global->__pyx_kp_u__2)));
      if (!values[4]) values[4] = __Pyx_NewRef(((PyObject *)((PyObject*)Py_True)));
      for (Py_ssize_t i = __pyx_nargs; i < 1; i++) {
        if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("read_csv", 0, 1, 5, i); __PYX_ERR(0, 158, __pyx_L3_error) }
      }
    } else {
      switch (__pyx_nargs) {
        case  5:
        values[4] = __Pyx_ArgRef_FASTCALL(__pyx_args, 4);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[4])) __PYX_ERR(0, 158, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  4:
        values[3] = __Pyx_ArgRef_FASTCALL(__pyx_args, 3);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[3])) __PYX_ERR(0, 158, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  3:
        values[2] = __Pyx_ArgRef_FASTCALL(__pyx_args, 2);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[2])) __PYX_ERR(0, 158, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  2:
        values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 158, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  1:
        values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 158, __pyx_L3_error)
        break;
        default: goto __pyx_L5_argtuple_error;
      }
      if (!values[1]) values[1] = __Pyx_NewRef(((PyObject *)Py_None));
      if (!values[2]) values[2] = __Pyx_NewRef(((PyObject *)((PyObject*)__pyx_mstate_global->__pyx_kp_u_)));
      if (!values[3]) values[3] = __Pyx_NewRef(((PyObject *)((PyObject*)__pyx_mstate_global->__pyx_kp_u__2)));
      if (!values[4]) values[4] = __Pyx_NewRef(((PyObject *)((PyObject*)Py_True)));
    }
    __pyx_v_data = values[0];
    __pyx_v_columns = values[1];
    __pyx_v_delimiter = values[2];
    __pyx_v_quote_char = values[3];
    __pyx_v_has_header = values[4];
  }
  goto __pyx_L6_skip;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("read_csv", 0, 1, 5, __pyx_nargs); __PYX_ERR(0, 158, __pyx_L3_error)
  __pyx_L6_skip:;
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L3_error:;
  for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
    Py_XDECREF(values[__pyx_temp]);
  }
  __Pyx_AddTraceback("rugo.csv.read_csv", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_4rugo_3csv_2read_csv(__pyx_self, __pyx_v_data, __pyx_v_columns, __pyx_v_delimiter, __pyx_v_quote_char, __pyx_v_has_header);

  /* function exit code */
  for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
    Py_XDECREF(values[__pyx_temp]);
  }
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_4rugo_3csv_2read_csv(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_data, PyObject *__pyx_v_columns, PyObject *__pyx_v_delimiter, PyObject *__pyx_v_quote_char, PyObject *__pyx_v_has_header) {
  uint8_t const *__pyx_v_data_ptr;
  size_t __pyx_v_data_size;
  PyObject *__pyx_v_data_bytes = 0;
  Py_buffer __pyx_v_view;
  bool __pyx_v_have_view;
  CsvDialect __pyx_v_dialect;
  std::vector<std::string>  __pyx_v_column_names_cpp;
  PyObject *__pyx_v_col = NULL;
  CsvTable __pyx_v_table;
  PyObject *__pyx_v_result = NULL;
  size_t __pyx_v_i;
  size_t __pyx_v_j;
  PyObject *__pyx_v_col_type = NULL;
  std::vector<PY_LONG_LONG> ::size_type __pyx_v_n;
  std::vector<uint8_t> ::size_type __pyx_v_nm;
  PyObject *__pyx_v_col_data = NULL;
  PyObject *__pyx_r = NULL;
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_6);
  __Pyx_XDECREF(__pyx_t_7);
  __Pyx_XDECREF(__pyx_t_8);
  __Pyx_XDECREF(__pyx_t_9);
  __Pyx_AddTraceback("rugo.csv.read_csv", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XDECREF(__pyx_v_data_bytes);
  __Pyx_XDECREF(__pyx_v_col);
  __Pyx_XDECREF(__pyx_v_result);
  __Pyx_XDECREF(__pyx_v_col_type);
  __Pyx_XDECREF(__pyx_v_col_data);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_4rugo_3csv_3read_csv, 0, __pyx_mstate_global->__pyx_n_u_read_csv, NULL, __pyx_mstate_global->__pyx_n_u_rugo_csv, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[1])); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 158, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_2, __pyx_mstate_global->__pyx_tuple[1]);
  if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_read_csv, __pyx_t_2) < (0)) __PYX_ERR(0, 158, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* … */
  __pyx_mstate_global->__pyx_tuple[1] = PyTuple_Pack(4, Py_None, ((PyObject*)__pyx_mstate_global->__pyx_kp_u_), ((PyObject*)__pyx_mstate_global->__pyx_kp_u__2), ((PyObject*)Py_True)); if (unlikely(!__pyx_mstate_global->__pyx_tuple[1])) __PYX_ERR(0, 158, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_mstate_global->__pyx_tuple[1]);
  __Pyx_GIVEREF(__pyx_mstate_global->__pyx_tuple[1]);
 159:     """
 160:     Read CSV data into columnar format.
 161: 
 162:     Parameters
 163:     ----------
 164:     data : bytes or memoryview
 165:         The CSV data to read
 166:     columns : list of str, optional
 167:         List of column names to read. If None, reads all columns.
 168:     delimiter : str, default ','
 169:         Field delimiter character (use '\\t' for TSV)
 170:     quote_char : str, default '"'
 171:         Quote character for fields
 172:     has_header : bool, default True
 173:         Whether the first line contains column names
 174: 
 175:     Returns
 176:     -------
 177:     dict
 178:         Dictionary with keys:
 179:         - success: bool - Whether reading succeeded
 180:         - num_rows: int - Number of rows read
 181:         - column_names: list of str - Column names
 182:         - columns: list of list - Column data (one list per column)
 183: 
 184:     Examples
 185:     --------
 186:     >>> data = b'name,age,salary\\nAlice,30,50000\\nBob,25,45000'
 187:     >>> result = read_csv(data)
 188:     >>> print(result['column_names'])
 189:     ['name', 'age', 'salary']
 190:     >>> print(result['columns'][0])  # name column
 191:     ['Alice', 'Bob']
 192: 
 193:     >>> # Read with projection
 194:     >>> result = read_csv(data, columns=['name', 'salary'])
 195:     >>> print(result['column_names'])
 196:     ['name', 'salary']
 197:     """
 198:     cdef const uint8_t* data_ptr
 199:     cdef size_t data_size
 200:     cdef bytes data_bytes
 201:     cdef Py_buffer view
+202:     cdef cbool have_view = False
  __pyx_v_have_view = 0;
 203: 
 204:     # Handle different input types
+205:     if isinstance(data, memoryview):
  __pyx_t_1 = PyMemoryView_Check(__pyx_v_data); 
  if (__pyx_t_1) {
/* … */
    goto __pyx_L3;
  }
+206:         PyObject_GetBuffer(data.obj, &view, PyBUF_CONTIG_RO)
    __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_data, __pyx_mstate_global->__pyx_n_u_obj); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 206, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __pyx_t_3 = PyObject_GetBuffer(__pyx_t_2, (&__pyx_v_view), PyBUF_CONTIG_RO); if (unlikely(__pyx_t_3 == ((int)-1))) __PYX_ERR(0, 206, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+207:         data_ptr = <const uint8_t*>view.buf
    __pyx_v_data_ptr = ((uint8_t const *)__pyx_v_view.buf);
+208:         data_size = view.len
    __pyx_t_4 = __pyx_v_view.len;
    __pyx_v_data_size = __pyx_t_4;
+209:         have_view = True
    __pyx_v_have_view = 1;
+210:     elif isinstance(data, bytes):
  __pyx_t_1 = PyBytes_Check(__pyx_v_data); 
  if (likely(__pyx_t_1)) {
/* … */
    goto __pyx_L3;
  }
+211:         data_bytes = data
    __pyx_t_2 = __pyx_v_data;
    __Pyx_INCREF(__pyx_t_2);
    if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None) || __Pyx_RaiseUnexpectedTypeError("bytes", __pyx_t_2))) __PYX_ERR(0, 211, __pyx_L1_error)
    __pyx_v_data_bytes = ((PyObject*)__pyx_t_2);
    __pyx_t_2 = 0;
+212:         data_ptr = <const uint8_t*><char*>data_bytes
    if (unlikely(__pyx_v_data_bytes == Py_None)) {
      PyErr_SetString(PyExc_TypeError, "expected bytes, NoneType found");
      __PYX_ERR(0, 212, __pyx_L1_error)
    }
    __pyx_t_5 = __Pyx_PyBytes_AsWritableString(__pyx_v_data_bytes); if (unlikely((!__pyx_t_5) && PyErr_Occurred())) __PYX_ERR(0, 212, __pyx_L1_error)
    __pyx_v_data_ptr = ((uint8_t const *)((char *)__pyx_t_5));
+213:         data_size = len(data_bytes)
    if (unlikely(__pyx_v_data_bytes == Py_None)) {
      PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()");
      __PYX_ERR(0, 213, __pyx_L1_error)
    }
    __pyx_t_4 = __Pyx_PyBytes_GET_SIZE(__pyx_v_data_bytes); if (unlikely(__pyx_t_4 == ((Py_ssize_t)-1))) __PYX_ERR(0, 213, __pyx_L1_error)
    __pyx_v_data_size = __pyx_t_4;
 214:     else:
+215:         raise TypeError(f"Expected bytes or memoryview, got {type(data)}")
  /*else*/ {
    __pyx_t_6 = NULL;
    __Pyx_INCREF(__pyx_builtin_TypeError);
    __pyx_t_7 = __pyx_builtin_TypeError; 
    __pyx_t_8 = __Pyx_PyObject_FormatSimple(((PyObject *)Py_TYPE(__pyx_v_data)), __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 215, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_8);
    __pyx_t_9 = __Pyx_PyUnicode_Concat(__pyx_mstate_global->__pyx_kp_u_Expected_bytes_or_memoryview_got, __pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 215, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_9);
    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
    __pyx_t_10 = 1;
    {
      PyObject *__pyx_callargs[2] = {__pyx_t_6, __pyx_t_9};
      __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_7, __pyx_callargs+__pyx_t_10, (2-__pyx_t_10) | (__pyx_t_10*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET));
      __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
      __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
      if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 215, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_2);
    }
    __Pyx_Raise(__pyx_t_2, 0, 0, 0);
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __PYX_ERR(0, 215, __pyx_L1_error)
  }
  __pyx_L3:;
 216: 
 217:     # Setup dialect
 218:     cdef CsvDialect dialect
+219:     dialect.delimiter = ord(delimiter[0]) if delimiter else ord(',')
  __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_v_delimiter); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 219, __pyx_L1_error)
  if (__pyx_t_1) {
    __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_delimiter, 0, long, 1, __Pyx_PyLong_From_long, 0, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 219, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __pyx_t_12 = __Pyx_PyObject_Ord(__pyx_t_2); if (unlikely(__pyx_t_12 == ((long)(long)(Py_UCS4)-1))) __PYX_ERR(0, 219, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __pyx_t_11 = __pyx_t_12;
  } else {
    __pyx_t_11 = 44;
  }
  __pyx_v_dialect.delimiter = __pyx_t_11;
+220:     dialect.quote_char = ord(quote_char[0]) if quote_char else ord('"')
  __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_v_quote_char); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 220, __pyx_L1_error)
  if (__pyx_t_1) {
    __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_quote_char, 0, long, 1, __Pyx_PyLong_From_long, 0, 0, 0, 1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 220, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __pyx_t_12 = __Pyx_PyObject_Ord(__pyx_t_2); if (unlikely(__pyx_t_12 == ((long)(long)(Py_UCS4)-1))) __PYX_ERR(0, 220, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __pyx_t_11 = __pyx_t_12;
  } else {
    __pyx_t_11 = 34;
  }
  __pyx_v_dialect.quote_char = __pyx_t_11;
+221:     dialect.escape_char = ord('\\')
  __pyx_v_dialect.escape_char = 92;
+222:     dialect.double_quote = True
  __pyx_v_dialect.double_quote = 1;
+223:     dialect.has_header = has_header
  __pyx_t_13 = __Pyx_PyObject_IsTrue(__pyx_v_has_header); if (unlikely((__pyx_t_13 == ((bool)-1)) && PyErr_Occurred())) __PYX_ERR(0, 223, __pyx_L1_error)
  __pyx_v_dialect.has_header = __pyx_t_13;
 224: 
 225:     # Convert column names to C++ vector
 226:     cdef vector[string] column_names_cpp
+227:     if columns is not None:
  __pyx_t_1 = (__pyx_v_columns != Py_None);
  if (__pyx_t_1) {
/* … */
  }
+228:         for col in columns:
    if (likely(PyList_CheckExact(__pyx_v_columns)) || PyTuple_CheckExact(__pyx_v_columns)) {
      __pyx_t_2 = __pyx_v_columns; __Pyx_INCREF(__pyx_t_2);
      __pyx_t_4 = 0;
      __pyx_t_14 = NULL;
    } else {
      __pyx_t_4 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_v_columns); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 228, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_2);
      __pyx_t_14 = (CYTHON_COMPILING_IN_LIMITED_API) ? PyIter_Next : __Pyx_PyObject_GetIterNextFunc(__pyx_t_2); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 228, __pyx_L1_error)
    }
    for (;;) {
      if (likely(!__pyx_t_14)) {
        if (likely(PyList_CheckExact(__pyx_t_2))) {
          {
            Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_t_2);
            #if !CYTHON_ASSUME_SAFE_SIZE
            if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 228, __pyx_L1_error)
            #endif
            if (__pyx_t_4 >= __pyx_temp) break;
          }
          __pyx_t_7 = __Pyx_PyList_GetItemRef(__pyx_t_2, __pyx_t_4);
          ++__pyx_t_4;
        } else {
          {
            Py_ssize_t __pyx_temp = __Pyx_PyTuple_GET_SIZE(__pyx_t_2);
            #if !CYTHON_ASSUME_SAFE_SIZE
            if (unlikely((__pyx_temp < 0))) __PYX_ERR(0, 228, __pyx_L1_error)
            #endif
            if (__pyx_t_4 >= __pyx_temp) break;
          }
          #if CYTHON_ASSUME_SAFE_MACROS && !CYTHON_AVOID_BORROWED_REFS
          __pyx_t_7 = __Pyx_NewRef(PyTuple_GET_ITEM(__pyx_t_2, __pyx_t_4));
          #else
          __pyx_t_7 = __Pyx_PySequence_ITEM(__pyx_t_2, __pyx_t_4);
          #endif
          ++__pyx_t_4;
        }
        if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 228, __pyx_L1_error)
      } else {
        __pyx_t_7 = __pyx_t_14(__pyx_t_2);
        if (unlikely(!__pyx_t_7)) {
          PyObject* exc_type = PyErr_Occurred();
          if (exc_type) {
            if (unlikely(!__Pyx_PyErr_GivenExceptionMatches(exc_type, PyExc_StopIteration))) __PYX_ERR(0, 228, __pyx_L1_error)
            PyErr_Clear();
          }
          break;
        }
      }
      __Pyx_GOTREF(__pyx_t_7);
      __Pyx_XDECREF_SET(__pyx_v_col, __pyx_t_7);
      __pyx_t_7 = 0;
/* … */
    }
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+229:             column_names_cpp.push_back(col.encode('utf-8'))
      __pyx_t_9 = __pyx_v_col;
      __Pyx_INCREF(__pyx_t_9);
      __pyx_t_10 = 0;
      {
        PyObject *__pyx_callargs[2] = {__pyx_t_9, __pyx_mstate_global->__pyx_kp_u_utf_8};
        __pyx_t_7 = __Pyx_PyObject_FastCallMethod(__pyx_mstate_global->__pyx_n_u_encode, __pyx_callargs+__pyx_t_10, (2-__pyx_t_10) | (1*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET));
        __Pyx_XDECREF(__pyx_t_9); __pyx_t_9 = 0;
        if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 229, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_7);
      }
      __pyx_t_15 = __pyx_convert_string_from_py_6libcpp_6string_std__in_string(__pyx_t_7); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 229, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
      try {
        __pyx_v_column_names_cpp.push_back(__pyx_t_15);
      } catch(...) {
        __Pyx_CppExn2PyErr();
        __PYX_ERR(0, 229, __pyx_L1_error)
      }
 230: 
 231:     # Read CSV
 232:     cdef CsvTable table
+233:     if columns is None:
  __pyx_t_1 = (__pyx_v_columns == Py_None);
  if (__pyx_t_1) {
/* … */
    goto __pyx_L8;
  }
+234:         table = ReadCsv(data_ptr, data_size, dialect)
    __pyx_v_table = ReadCsv(__pyx_v_data_ptr, __pyx_v_data_size, __pyx_v_dialect);
 235:     else:
+236:         table = ReadCsv(data_ptr, data_size, dialect, column_names_cpp)
  /*else*/ {
    __pyx_v_table = ReadCsv(__pyx_v_data_ptr, __pyx_v_data_size, __pyx_v_dialect, __pyx_v_column_names_cpp);
  }
  __pyx_L8:;
 237: 
+238:     if have_view:
  __pyx_t_1 = (__pyx_v_have_view != 0);
  if (__pyx_t_1) {
/* … */
  }
+239:         PyBuffer_Release(&view)
    PyBuffer_Release((&__pyx_v_view));
 240: 
 241:     # Convert to Python
 242:     result = {
+243:         'success': table.success,
  __pyx_t_2 = __Pyx_PyDict_NewPresized(4); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 243, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_7 = __Pyx_PyBool_FromLong(__pyx_v_table.success); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 243, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_7);
  if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_success, __pyx_t_7) < (0)) __PYX_ERR(0, 243, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+244:         'num_rows': table.num_rows,
  __pyx_t_7 = __Pyx_PyLong_FromSize_t(__pyx_v_table.num_rows); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 244, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_7);
  if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_num_rows, __pyx_t_7) < (0)) __PYX_ERR(0, 243, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+245:         'column_names': [],
  __pyx_t_7 = PyList_New(0); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 245, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_7);
  if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_column_names, __pyx_t_7) < (0)) __PYX_ERR(0, 243, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+246:         'columns': []
  __pyx_t_7 = PyList_New(0); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 246, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_7);
  if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_columns, __pyx_t_7) < (0)) __PYX_ERR(0, 243, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
  __pyx_v_result = ((PyObject*)__pyx_t_2);
  __pyx_t_2 = 0;
 247:     }
 248: 
 249:     cdef size_t i, j
 250: 
 251:     # Column names
+252:     for i in range(table.column_names.size()):
  __pyx_t_16 = __pyx_v_table.column_names.size();
  __pyx_t_17 = __pyx_t_16;
  for (__pyx_t_10 = 0; __pyx_t_10 < __pyx_t_17; __pyx_t_10+=1) {
    __pyx_v_i = __pyx_t_10;
+253:         result['column_names'].append(table.column_names[i].decode('utf-8'))
    __pyx_t_2 = __Pyx_PyDict_GetItem(__pyx_v_result, __pyx_mstate_global->__pyx_n_u_column_names); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 253, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __pyx_t_7 = __Pyx_decode_cpp_string((__pyx_v_table.column_names[__pyx_v_i]), 0, PY_SSIZE_T_MAX, NULL, NULL, PyUnicode_DecodeUTF8); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 253, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_7);
    __pyx_t_18 = __Pyx_PyObject_Append(__pyx_t_2, __pyx_t_7); if (unlikely(__pyx_t_18 == ((int)-1))) __PYX_ERR(0, 253, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
  }
 254: 
 255:     # Column data
+256:     for i in range(table.columns.size()):
  __pyx_t_19 = __pyx_v_table.columns.size();
  __pyx_t_20 = __pyx_t_19;
  for (__pyx_t_10 = 0; __pyx_t_10 < __pyx_t_20; __pyx_t_10+=1) {
    __pyx_v_i = __pyx_t_10;
+257:         col_type = table.columns[i].type.decode('utf-8')
    __pyx_t_7 = __Pyx_decode_cpp_string((__pyx_v_table.columns[__pyx_v_i]).type, 0, PY_SSIZE_T_MAX, NULL, NULL, PyUnicode_DecodeUTF8); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 257, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_7);
    __Pyx_XDECREF_SET(__pyx_v_col_type, __pyx_t_7);
    __pyx_t_7 = 0;
 258:         # Pre-allocate list for faster assignment and fewer resizes
+259:         if col_type == "int64":
    __pyx_t_1 = (__Pyx_PyUnicode_Equals(__pyx_v_col_type, __pyx_mstate_global->__pyx_n_u_int64, Py_EQ)); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 259, __pyx_L1_error)
    if (__pyx_t_1) {
/* … */
      goto __pyx_L14;
    }
+260:             n = table.columns[i].int_values.size()
      __pyx_v_n = (__pyx_v_table.columns[__pyx_v_i]).int_values.size();
+261:             nm = table.columns[i].null_mask.size()
      __pyx_v_nm = (__pyx_v_table.columns[__pyx_v_i]).null_mask.size();
+262:             col_data = [None] * n
      __pyx_t_7 = PyList_New(1 * (__pyx_v_n)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 262, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_7);
      { Py_ssize_t __pyx_temp;
        for (__pyx_temp=0; __pyx_temp < __pyx_v_n; __pyx_temp++) {
          __Pyx_INCREF(Py_None);
          __Pyx_GIVEREF(Py_None);
          if (__Pyx_PyList_SET_ITEM(__pyx_t_7, __pyx_temp, Py_None) != (0)) __PYX_ERR(0, 262, __pyx_L1_error);
        }
      }
      __Pyx_XDECREF_SET(__pyx_v_col_data, ((PyObject*)__pyx_t_7));
      __pyx_t_7 = 0;
+263:             for j in range(n):
      __pyx_t_21 = __pyx_v_n;
      __pyx_t_22 = __pyx_t_21;
      for (__pyx_t_23 = 0; __pyx_t_23 < __pyx_t_22; __pyx_t_23+=1) {
        __pyx_v_j = __pyx_t_23;
+264:                 if nm == n:
        __pyx_t_1 = (__pyx_v_nm == __pyx_v_n);
        if (__pyx_t_1) {
/* … */
          goto __pyx_L17;
        }
+265:                     if table.columns[i].null_mask[j]:
          __pyx_t_1 = (((__pyx_v_table.columns[__pyx_v_i]).null_mask[__pyx_v_j]) != 0);
          if (__pyx_t_1) {
/* … */
            goto __pyx_L18;
          }
+266:                         col_data[j] = None
            if (unlikely((__Pyx_SetItemInt(__pyx_v_col_data, __pyx_v_j, Py_None, size_t, 0, __Pyx_PyLong_FromSize_t, 1, 0, 0, 1) < 0))) __PYX_ERR(0, 266, __pyx_L1_error)
 267:                     else:
+268:                         col_data[j] = table.columns[i].int_values[j]
          /*else*/ {
            __pyx_t_7 = __Pyx_PyLong_From_PY_LONG_LONG(((__pyx_v_table.columns[__pyx_v_i]).int_values[__pyx_v_j])); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 268, __pyx_L1_error)
            __Pyx_GOTREF(__pyx_t_7);
            if (unlikely((__Pyx_SetItemInt(__pyx_v_col_data, __pyx_v_j, __pyx_t_7, size_t, 0, __Pyx_PyLong_FromSize_t, 1, 0, 0, 1) < 0))) __PYX_ERR(0, 268, __pyx_L1_error)
            __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
          }
          __pyx_L18:;
 269:                 else:
+270:                     if j < nm and table.columns[i].null_mask[j]:
        /*else*/ {
          __pyx_t_24 = (__pyx_v_j < __pyx_v_nm);
          if (__pyx_t_24) {
          } else {
            __pyx_t_1 = __pyx_t_24;
            goto __pyx_L20_bool_binop_done;
          }
          __pyx_t_24 = (((__pyx_v_table.columns[__pyx_v_i]).null_mask[__pyx_v_j]) != 0);
          __pyx_t_1 = __pyx_t_24;
          __pyx_L20_bool_binop_done:;
          if (__pyx_t_1) {
/* … */
            goto __pyx_L19;
          }
+271:                         col_data[j] = None
            if (unlikely((__Pyx_SetItemInt(__pyx_v_col_data, __pyx_v_j, Py_None, size_t, 0, __Pyx_PyLong_FromSize_t, 1, 0, 0, 1) < 0))) __PYX_ERR(0, 271, __pyx_L1_error)
 272:                     else:
+273:                         col_data[j] = table.columns[i].int_values[j]
          /*else*/ {
            __pyx_t_7 = __Pyx_PyLong_From_PY_LONG_LONG(((__pyx_v_table.columns[__pyx_v_i]).int_values[__pyx_v_j])); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 273, __pyx_L1_error)
            __Pyx_GOTREF(__pyx_t_7);
            if (unlikely((__Pyx_SetItemInt(__pyx_v_col_data, __pyx_v_j, __pyx_t_7, size_t, 0, __Pyx_PyLong_FromSize_t, 1, 0, 0, 1) < 0))) __PYX_ERR(0, 273, __pyx_L1_error)
            __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
          }
          __pyx_L19:;
        }
        __pyx_L17:;
      }
+274:         elif col_type == "double":
    __pyx_t_1 = (__Pyx_PyUnicode_Equals(__pyx_v_col_type, __pyx_mstate_global->__pyx_n_u_double, Py_EQ)); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 274, __pyx_L1_error)
    if (__pyx_t_1) {
/* … */
      goto __pyx_L14;
    }
+275:             n = table.columns[i].double_values.size()
      __pyx_v_n = (__pyx_v_table.columns[__pyx_v_i]).double_values.size();
+276:             nm = table.columns[i].null_mask.size()
      __pyx_v_nm = (__pyx_v_table.columns[__pyx_v_i]).null_mask.size();
+277:             col_data = [None] * n
      __pyx_t_7 = PyList_New(1 * (__pyx_v_n)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 277, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_7);
      { Py_ssize_t __pyx_temp;
        for (__pyx_temp=0; __pyx_temp < __pyx_v_n; __pyx_temp++) {
          __Pyx_INCREF(Py_None);
          __Pyx_GIVEREF(Py_None);
          if (__Pyx_PyList_SET_ITEM(__pyx_t_7, __pyx_temp, Py_None) != (0)) __PYX_ERR(0, 277, __pyx_L1_error);
        }
      }
      __Pyx_XDECREF_SET(__pyx_v_col_data, ((PyObject*)__pyx_t_7));
      __pyx_t_7 = 0;
+278:             for j in range(n):
      __pyx_t_21 = __pyx_v_n;
      __pyx_t_22 = __pyx_t_21;
      for (__pyx_t_23 = 0; __pyx_t_23 < __pyx_t_22; __pyx_t_23+=1) {
        __pyx_v_j = __pyx_t_23;
+279:                 if nm == n:
        __pyx_t_1 = (__pyx_v_nm == __pyx_v_n);
        if (__pyx_t_1) {
/* … */
          goto __pyx_L24;
        }
+280:                     if table.columns[i].null_mask[j]:
          __pyx_t_1 = (((__pyx_v_table.columns[__pyx_v_i]).null_mask[__pyx_v_j]) != 0);
          if (__pyx_t_1) {
/* … */
            goto __pyx_L25;
          }
+281:                         col_data[j] = None
            if (unlikely((__Pyx_SetItemInt(__pyx_v_col_data, __pyx_v_j, Py_None, size_t, 0, __Pyx_PyLong_FromSize_t, 1, 0, 0, 1) < 0))) __PYX_ERR(0, 281, __pyx_L1_error)
 282:                     else:
+283:                         col_data[j] = table.columns[i].double_values[j]
          /*else*/ {
            __pyx_t_7 = PyFloat_FromDouble(((__pyx_v_table.columns[__pyx_v_i]).double_values[__pyx_v_j])); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 283, __pyx_L1_error)
            __Pyx_GOTREF(__pyx_t_7);
            if (unlikely((__Pyx_SetItemInt(__pyx_v_col_data, __pyx_v_j, __pyx_t_7, size_t, 0, __Pyx_PyLong_FromSize_t, 1, 0, 0, 1) < 0))) __PYX_ERR(0, 283, __pyx_L1_error)
            __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
          }
          __pyx_L25:;
 284:                 else:
+285:                     if j < nm and table.columns[i].null_mask[j]:
        /*else*/ {
          __pyx_t_24 = (__pyx_v_j < __pyx_v_nm);
          if (__pyx_t_24) {
          } else {
            __pyx_t_1 = __pyx_t_24;
            goto __pyx_L27_bool_binop_done;
          }
          __pyx_t_24 = (((__pyx_v_table.columns[__pyx_v_i]).null_mask[__pyx_v_j]) != 0);
          __pyx_t_1 = __pyx_t_24;
          __pyx_L27_bool_binop_done:;
          if (__pyx_t_1) {
/* … */
            goto __pyx_L26;
          }
+286:                         col_data[j] = None
            if (unlikely((__Pyx_SetItemInt(__pyx_v_col_data, __pyx_v_j, Py_None, size_t, 0, __Pyx_PyLong_FromSize_t, 1, 0, 0, 1) < 0))) __PYX_ERR(0, 286, __pyx_L1_error)
 287:                     else:
+288:                         col_data[j] = table.columns[i].double_values[j]
          /*else*/ {
            __pyx_t_7 = PyFloat_FromDouble(((__pyx_v_table.columns[__pyx_v_i]).double_values[__pyx_v_j])); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 288, __pyx_L1_error)
            __Pyx_GOTREF(__pyx_t_7);
            if (unlikely((__Pyx_SetItemInt(__pyx_v_col_data, __pyx_v_j, __pyx_t_7, size_t, 0, __Pyx_PyLong_FromSize_t, 1, 0, 0, 1) < 0))) __PYX_ERR(0, 288, __pyx_L1_error)
            __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
          }
          __pyx_L26:;
        }
        __pyx_L24:;
      }
+289:         elif col_type == "boolean":
    __pyx_t_1 = (__Pyx_PyUnicode_Equals(__pyx_v_col_type, __pyx_mstate_global->__pyx_n_u_boolean, Py_EQ)); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 289, __pyx_L1_error)
    if (__pyx_t_1) {
/* … */
      goto __pyx_L14;
    }
+290:             n = table.columns[i].boolean_values.size()
      __pyx_v_n = (__pyx_v_table.columns[__pyx_v_i]).boolean_values.size();
+291:             nm = table.columns[i].null_mask.size()
      __pyx_v_nm = (__pyx_v_table.columns[__pyx_v_i]).null_mask.size();
+292:             col_data = [None] * n
      __pyx_t_7 = PyList_New(1 * (__pyx_v_n)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 292, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_7);
      { Py_ssize_t __pyx_temp;
        for (__pyx_temp=0; __pyx_temp < __pyx_v_n; __pyx_temp++) {
          __Pyx_INCREF(Py_None);
          __Pyx_GIVEREF(Py_None);
          if (__Pyx_PyList_SET_ITEM(__pyx_t_7, __pyx_temp, Py_None) != (0)) __PYX_ERR(0, 292, __pyx_L1_error);
        }
      }
      __Pyx_XDECREF_SET(__pyx_v_col_data, ((PyObject*)__pyx_t_7));
      __pyx_t_7 = 0;
+293:             for j in range(n):
      __pyx_t_21 = __pyx_v_n;
      __pyx_t_22 = __pyx_t_21;
      for (__pyx_t_23 = 0; __pyx_t_23 < __pyx_t_22; __pyx_t_23+=1) {
        __pyx_v_j = __pyx_t_23;
+294:                 if nm == n:
        __pyx_t_1 = (__pyx_v_nm == __pyx_v_n);
        if (__pyx_t_1) {
/* … */
          goto __pyx_L31;
        }
+295:                     if table.columns[i].null_mask[j]:
          __pyx_t_1 = (((__pyx_v_table.columns[__pyx_v_i]).null_mask[__pyx_v_j]) != 0);
          if (__pyx_t_1) {
/* … */
            goto __pyx_L32;
          }
+296:                         col_data[j] = None
            if (unlikely((__Pyx_SetItemInt(__pyx_v_col_data, __pyx_v_j, Py_None, size_t, 0, __Pyx_PyLong_FromSize_t, 1, 0, 0, 1) < 0))) __PYX_ERR(0, 296, __pyx_L1_error)
 297:                     else:
+298:                         col_data[j] = bool(table.columns[i].boolean_values[j])
          /*else*/ {
            __pyx_t_7 = __Pyx_PyLong_From_uint8_t(((__pyx_v_table.columns[__pyx_v_i]).boolean_values[__pyx_v_j])); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 298, __pyx_L1_error)
            __Pyx_GOTREF(__pyx_t_7);
            __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_7); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 298, __pyx_L1_error)
            __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
            __pyx_t_7 = __Pyx_PyBool_FromLong((!(!__pyx_t_1))); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 298, __pyx_L1_error)
            __Pyx_GOTREF(__pyx_t_7);
            if (unlikely((__Pyx_SetItemInt(__pyx_v_col_data, __pyx_v_j, __pyx_t_7, size_t, 0, __Pyx_PyLong_FromSize_t, 1, 0, 0, 1) < 0))) __PYX_ERR(0, 298, __pyx_L1_error)
            __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
          }
          __pyx_L32:;
 299:                 else:
+300:                     if j < nm and table.columns[i].null_mask[j]:
        /*else*/ {
          __pyx_t_24 = (__pyx_v_j < __pyx_v_nm);
          if (__pyx_t_24) {
          } else {
            __pyx_t_1 = __pyx_t_24;
            goto __pyx_L34_bool_binop_done;
          }
          __pyx_t_24 = (((__pyx_v_table.columns[__pyx_v_i]).null_mask[__pyx_v_j]) != 0);
          __pyx_t_1 = __pyx_t_24;
          __pyx_L34_bool_binop_done:;
          if (__pyx_t_1) {
/* … */
            goto __pyx_L33;
          }
+301:                         col_data[j] = None
            if (unlikely((__Pyx_SetItemInt(__pyx_v_col_data, __pyx_v_j, Py_None, size_t, 0, __Pyx_PyLong_FromSize_t, 1, 0, 0, 1) < 0))) __PYX_ERR(0, 301, __pyx_L1_error)
 302:                     else:
+303:                         col_data[j] = bool(table.columns[i].boolean_values[j])
          /*else*/ {
            __pyx_t_7 = __Pyx_PyLong_From_uint8_t(((__pyx_v_table.columns[__pyx_v_i]).boolean_values[__pyx_v_j])); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 303, __pyx_L1_error)
            __Pyx_GOTREF(__pyx_t_7);
            __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_7); if (unlikely((__pyx_t_1 < 0))) __PYX_ERR(0, 303, __pyx_L1_error)
            __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
            __pyx_t_7 = __Pyx_PyBool_FromLong((!(!__pyx_t_1))); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 303, __pyx_L1_error)
            __Pyx_GOTREF(__pyx_t_7);
            if (unlikely((__Pyx_SetItemInt(__pyx_v_col_data, __pyx_v_j, __pyx_t_7, size_t, 0, __Pyx_PyLong_FromSize_t, 1, 0, 0, 1) < 0))) __PYX_ERR(0, 303, __pyx_L1_error)
            __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
          }
          __pyx_L33:;
        }
        __pyx_L31:;
      }
 304:         else:  # string
+305:             n = table.columns[i].string_values.size()
    /*else*/ {
      __pyx_v_n = (__pyx_v_table.columns[__pyx_v_i]).string_values.size();
+306:             nm = table.columns[i].null_mask.size()
      __pyx_v_nm = (__pyx_v_table.columns[__pyx_v_i]).null_mask.size();
+307:             col_data = [None] * n
      __pyx_t_7 = PyList_New(1 * (__pyx_v_n)); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 307, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_7);
      { Py_ssize_t __pyx_temp;
        for (__pyx_temp=0; __pyx_temp < __pyx_v_n; __pyx_temp++) {
          __Pyx_INCREF(Py_None);
          __Pyx_GIVEREF(Py_None);
          if (__Pyx_PyList_SET_ITEM(__pyx_t_7, __pyx_temp, Py_None) != (0)) __PYX_ERR(0, 307, __pyx_L1_error);
        }
      }
      __Pyx_XDECREF_SET(__pyx_v_col_data, ((PyObject*)__pyx_t_7));
      __pyx_t_7 = 0;
+308:             for j in range(n):
      __pyx_t_21 = __pyx_v_n;
      __pyx_t_22 = __pyx_t_21;
      for (__pyx_t_23 = 0; __pyx_t_23 < __pyx_t_22; __pyx_t_23+=1) {
        __pyx_v_j = __pyx_t_23;
+309:                 if nm == n:
        __pyx_t_1 = (__pyx_v_nm == __pyx_v_n);
        if (__pyx_t_1) {
/* … */
          goto __pyx_L38;
        }
+310:                     if table.columns[i].null_mask[j]:
          __pyx_t_1 = (((__pyx_v_table.columns[__pyx_v_i]).null_mask[__pyx_v_j]) != 0);
          if (__pyx_t_1) {
/* … */
            goto __pyx_L39;
          }
+311:                         col_data[j] = None
            if (unlikely((__Pyx_SetItemInt(__pyx_v_col_data, __pyx_v_j, Py_None, size_t, 0, __Pyx_PyLong_FromSize_t, 1, 0, 0, 1) < 0))) __PYX_ERR(0, 311, __pyx_L1_error)
 312:                     else:
+313:                         col_data[j] = table.columns[i].string_values[j].decode('utf-8')
          /*else*/ {
            __pyx_t_7 = __Pyx_decode_cpp_string(((__pyx_v_table.columns[__pyx_v_i]).string_values[__pyx_v_j]), 0, PY_SSIZE_T_MAX, NULL, NULL, PyUnicode_DecodeUTF8); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 313, __pyx_L1_error)
            __Pyx_GOTREF(__pyx_t_7);
            if (unlikely((__Pyx_SetItemInt(__pyx_v_col_data, __pyx_v_j, __pyx_t_7, size_t, 0, __Pyx_PyLong_FromSize_t, 1, 0, 0, 1) < 0))) __PYX_ERR(0, 313, __pyx_L1_error)
            __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
          }
          __pyx_L39:;
 314:                 else:
+315:                     if j < nm and table.columns[i].null_mask[j]:
        /*else*/ {
          __pyx_t_24 = (__pyx_v_j < __pyx_v_nm);
          if (__pyx_t_24) {
          } else {
            __pyx_t_1 = __pyx_t_24;
            goto __pyx_L41_bool_binop_done;
          }
          __pyx_t_24 = (((__pyx_v_table.columns[__pyx_v_i]).null_mask[__pyx_v_j]) != 0);
          __pyx_t_1 = __pyx_t_24;
          __pyx_L41_bool_binop_done:;
          if (__pyx_t_1) {
/* … */
            goto __pyx_L40;
          }
+316:                         col_data[j] = None
            if (unlikely((__Pyx_SetItemInt(__pyx_v_col_data, __pyx_v_j, Py_None, size_t, 0, __Pyx_PyLong_FromSize_t, 1, 0, 0, 1) < 0))) __PYX_ERR(0, 316, __pyx_L1_error)
 317:                     else:
+318:                         col_data[j] = table.columns[i].string_values[j].decode('utf-8')
          /*else*/ {
            __pyx_t_7 = __Pyx_decode_cpp_string(((__pyx_v_table.columns[__pyx_v_i]).string_values[__pyx_v_j]), 0, PY_SSIZE_T_MAX, NULL, NULL, PyUnicode_DecodeUTF8); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 318, __pyx_L1_error)
            __Pyx_GOTREF(__pyx_t_7);
            if (unlikely((__Pyx_SetItemInt(__pyx_v_col_data, __pyx_v_j, __pyx_t_7, size_t, 0, __Pyx_PyLong_FromSize_t, 1, 0, 0, 1) < 0))) __PYX_ERR(0, 318, __pyx_L1_error)
            __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
          }
          __pyx_L40:;
        }
        __pyx_L38:;
      }
    }
    __pyx_L14:;
 319: 
+320:         result['columns'].append(col_data)
    __pyx_t_7 = __Pyx_PyDict_GetItem(__pyx_v_result, __pyx_mstate_global->__pyx_n_u_columns); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 320, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_7);
    __pyx_t_18 = __Pyx_PyObject_Append(__pyx_t_7, __pyx_v_col_data); if (unlikely(__pyx_t_18 == ((int)-1))) __PYX_ERR(0, 320, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
  }
 321: 
+322:     return result
  __Pyx_XDECREF(__pyx_r);
  __Pyx_INCREF(__pyx_v_result);
  __pyx_r = __pyx_v_result;
  goto __pyx_L0;
 323: 
 324: 
+325: def detect_csv_dialect(data, sample_size=100):
/* Python wrapper */
static PyObject *__pyx_pw_4rugo_3csv_5detect_csv_dialect(PyObject *__pyx_self, 
#if CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
); /*proto*/
PyDoc_STRVAR(__pyx_doc_4rugo_3csv_4detect_csv_dialect, "\n    Auto-detect CSV dialect (delimiter, quote character).\n    \n    Parameters\n    ----------\n    data : bytes or memoryview\n        The CSV data to analyze\n    sample_size : int, default 100\n        Number of rows to sample for detection\n    \n    Returns\n    -------\n    dict\n        Dictionary with detected dialect parameters:\n        - delimiter: str - Detected delimiter character\n        - quote_char: str - Quote character\n        \n    Examples\n    --------\n    >>> data = b'name\\tage\\tsalary\\nAlice\\t30\\t50000'\n    >>> dialect = detect_csv_dialect(data)\n    >>> print(dialect['delimiter'])\n    '\t'\n    ");
static PyMethodDef __pyx_mdef_4rugo_3csv_5detect_csv_dialect = {"detect_csv_dialect", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_4rugo_3csv_5detect_csv_dialect, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_4rugo_3csv_4detect_csv_dialect};
static PyObject *__pyx_pw_4rugo_3csv_5detect_csv_dialect(PyObject *__pyx_self, 
#if CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
) {
  PyObject *__pyx_v_data = 0;
  PyObject *__pyx_v_sample_size = 0;
  #if !CYTHON_METH_FASTCALL
  CYTHON_UNUSED Py_ssize_t __pyx_nargs;
  #endif
  CYTHON_UNUSED PyObject *const *__pyx_kwvalues;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("detect_csv_dialect (wrapper)", 0);
  #if !CYTHON_METH_FASTCALL
  #if CYTHON_ASSUME_SAFE_SIZE
  __pyx_nargs = PyTuple_GET_SIZE(__pyx_args);
  #else
  __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL;
  #endif
  #endif
  __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs);
  {
    PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_data,&__pyx_mstate_global->__pyx_n_u_sample_size,0};
  PyObject* values[2] = {0,0};
    const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0;
    if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 325, __pyx_L3_error)
    if (__pyx_kwds_len > 0) {
      switch (__pyx_nargs) {
        case  2:
        values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 325, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  1:
        values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 325, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      const Py_ssize_t kwd_pos_args = __pyx_nargs;
      if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "detect_csv_dialect", 0) < (0)) __PYX_ERR(0, 325, __pyx_L3_error)
      if (!values[1]) values[1] = __Pyx_NewRef(((PyObject *)((PyObject*)__pyx_mstate_global->__pyx_int_100)));
      for (Py_ssize_t i = __pyx_nargs; i < 1; i++) {
        if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("detect_csv_dialect", 0, 1, 2, i); __PYX_ERR(0, 325, __pyx_L3_error) }
      }
    } else {
      switch (__pyx_nargs) {
        case  2:
        values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 325, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  1:
        values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 325, __pyx_L3_error)
        break;
        default: goto __pyx_L5_argtuple_error;
      }
      if (!values[1]) values[1] = __Pyx_NewRef(((PyObject *)((PyObject*)__pyx_mstate_global->__pyx_int_100)));
    }
    __pyx_v_data = values[0];
    __pyx_v_sample_size = values[1];
  }
  goto __pyx_L6_skip;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("detect_csv_dialect", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 325, __pyx_L3_error)
  __pyx_L6_skip:;
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L3_error:;
  for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
    Py_XDECREF(values[__pyx_temp]);
  }
  __Pyx_AddTraceback("rugo.csv.detect_csv_dialect", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_4rugo_3csv_4detect_csv_dialect(__pyx_self, __pyx_v_data, __pyx_v_sample_size);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
    Py_XDECREF(values[__pyx_temp]);
  }
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_4rugo_3csv_4detect_csv_dialect(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_data, PyObject *__pyx_v_sample_size) {
  uint8_t const *__pyx_v_data_ptr;
  size_t __pyx_v_data_size;
  PyObject *__pyx_v_data_bytes = 0;
  Py_buffer __pyx_v_view;
  bool __pyx_v_have_view;
  CsvDialect __pyx_v_dialect;
  PyObject *__pyx_r = NULL;
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_6);
  __Pyx_XDECREF(__pyx_t_7);
  __Pyx_XDECREF(__pyx_t_8);
  __Pyx_XDECREF(__pyx_t_9);
  __Pyx_AddTraceback("rugo.csv.detect_csv_dialect", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XDECREF(__pyx_v_data_bytes);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_4rugo_3csv_5detect_csv_dialect, 0, __pyx_mstate_global->__pyx_n_u_detect_csv_dialect, NULL, __pyx_mstate_global->__pyx_n_u_rugo_csv, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[2])); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 325, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_2, __pyx_mstate_global->__pyx_tuple[2]);
  if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_detect_csv_dialect, __pyx_t_2) < (0)) __PYX_ERR(0, 325, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
/* … */
  __pyx_mstate_global->__pyx_tuple[2] = PyTuple_Pack(1, ((PyObject*)__pyx_mstate_global->__pyx_int_100)); if (unlikely(!__pyx_mstate_global->__pyx_tuple[2])) __PYX_ERR(0, 325, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_mstate_global->__pyx_tuple[2]);
  __Pyx_GIVEREF(__pyx_mstate_global->__pyx_tuple[2]);
 326:     """
 327:     Auto-detect CSV dialect (delimiter, quote character).
 328: 
 329:     Parameters
 330:     ----------
 331:     data : bytes or memoryview
 332:         The CSV data to analyze
 333:     sample_size : int, default 100
 334:         Number of rows to sample for detection
 335: 
 336:     Returns
 337:     -------
 338:     dict
 339:         Dictionary with detected dialect parameters:
 340:         - delimiter: str - Detected delimiter character
 341:         - quote_char: str - Quote character
 342: 
 343:     Examples
 344:     --------
 345:     >>> data = b'name\\tage\\tsalary\\nAlice\\t30\\t50000'
 346:     >>> dialect = detect_csv_dialect(data)
 347:     >>> print(dialect['delimiter'])
 348:     '\t'
 349:     """
 350:     cdef const uint8_t* data_ptr
 351:     cdef size_t data_size
 352:     cdef bytes data_bytes
 353:     cdef Py_buffer view
+354:     cdef cbool have_view = False
  __pyx_v_have_view = 0;
 355: 
 356:     # Handle different input types
+357:     if isinstance(data, memoryview):
  __pyx_t_1 = PyMemoryView_Check(__pyx_v_data); 
  if (__pyx_t_1) {
/* … */
    goto __pyx_L3;
  }
+358:         PyObject_GetBuffer(data.obj, &view, PyBUF_CONTIG_RO)
    __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_data, __pyx_mstate_global->__pyx_n_u_obj); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 358, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __pyx_t_3 = PyObject_GetBuffer(__pyx_t_2, (&__pyx_v_view), PyBUF_CONTIG_RO); if (unlikely(__pyx_t_3 == ((int)-1))) __PYX_ERR(0, 358, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
+359:         data_ptr = <const uint8_t*>view.buf
    __pyx_v_data_ptr = ((uint8_t const *)__pyx_v_view.buf);
+360:         data_size = view.len
    __pyx_t_4 = __pyx_v_view.len;
    __pyx_v_data_size = __pyx_t_4;
+361:         have_view = True
    __pyx_v_have_view = 1;
+362:     elif isinstance(data, bytes):
  __pyx_t_1 = PyBytes_Check(__pyx_v_data); 
  if (likely(__pyx_t_1)) {
/* … */
    goto __pyx_L3;
  }
+363:         data_bytes = data
    __pyx_t_2 = __pyx_v_data;
    __Pyx_INCREF(__pyx_t_2);
    if (!(likely(PyBytes_CheckExact(__pyx_t_2))||((__pyx_t_2) == Py_None) || __Pyx_RaiseUnexpectedTypeError("bytes", __pyx_t_2))) __PYX_ERR(0, 363, __pyx_L1_error)
    __pyx_v_data_bytes = ((PyObject*)__pyx_t_2);
    __pyx_t_2 = 0;
+364:         data_ptr = <const uint8_t*><char*>data_bytes
    if (unlikely(__pyx_v_data_bytes == Py_None)) {
      PyErr_SetString(PyExc_TypeError, "expected bytes, NoneType found");
      __PYX_ERR(0, 364, __pyx_L1_error)
    }
    __pyx_t_5 = __Pyx_PyBytes_AsWritableString(__pyx_v_data_bytes); if (unlikely((!__pyx_t_5) && PyErr_Occurred())) __PYX_ERR(0, 364, __pyx_L1_error)
    __pyx_v_data_ptr = ((uint8_t const *)((char *)__pyx_t_5));
+365:         data_size = len(data_bytes)
    if (unlikely(__pyx_v_data_bytes == Py_None)) {
      PyErr_SetString(PyExc_TypeError, "object of type 'NoneType' has no len()");
      __PYX_ERR(0, 365, __pyx_L1_error)
    }
    __pyx_t_4 = __Pyx_PyBytes_GET_SIZE(__pyx_v_data_bytes); if (unlikely(__pyx_t_4 == ((Py_ssize_t)-1))) __PYX_ERR(0, 365, __pyx_L1_error)
    __pyx_v_data_size = __pyx_t_4;
 366:     else:
+367:         raise TypeError(f"Expected bytes or memoryview, got {type(data)}")
  /*else*/ {
    __pyx_t_6 = NULL;
    __Pyx_INCREF(__pyx_builtin_TypeError);
    __pyx_t_7 = __pyx_builtin_TypeError; 
    __pyx_t_8 = __Pyx_PyObject_FormatSimple(((PyObject *)Py_TYPE(__pyx_v_data)), __pyx_mstate_global->__pyx_empty_unicode); if (unlikely(!__pyx_t_8)) __PYX_ERR(0, 367, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_8);
    __pyx_t_9 = __Pyx_PyUnicode_Concat(__pyx_mstate_global->__pyx_kp_u_Expected_bytes_or_memoryview_got, __pyx_t_8); if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 367, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_9);
    __Pyx_DECREF(__pyx_t_8); __pyx_t_8 = 0;
    __pyx_t_10 = 1;
    {
      PyObject *__pyx_callargs[2] = {__pyx_t_6, __pyx_t_9};
      __pyx_t_2 = __Pyx_PyObject_FastCall(__pyx_t_7, __pyx_callargs+__pyx_t_10, (2-__pyx_t_10) | (__pyx_t_10*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET));
      __Pyx_XDECREF(__pyx_t_6); __pyx_t_6 = 0;
      __Pyx_DECREF(__pyx_t_9); __pyx_t_9 = 0;
      __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
      if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 367, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_2);
    }
    __Pyx_Raise(__pyx_t_2, 0, 0, 0);
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __PYX_ERR(0, 367, __pyx_L1_error)
  }
  __pyx_L3:;
 368: 
 369:     # Detect dialect
+370:     cdef CsvDialect dialect = DetectCsvDialect(data_ptr, data_size, sample_size)
  __pyx_t_10 = __Pyx_PyLong_As_size_t(__pyx_v_sample_size); if (unlikely((__pyx_t_10 == (size_t)-1) && PyErr_Occurred())) __PYX_ERR(0, 370, __pyx_L1_error)
  __pyx_v_dialect = DetectCsvDialect(__pyx_v_data_ptr, __pyx_v_data_size, __pyx_t_10);
 371: 
+372:     if have_view:
  __pyx_t_1 = (__pyx_v_have_view != 0);
  if (__pyx_t_1) {
/* … */
  }
+373:         PyBuffer_Release(&view)
    PyBuffer_Release((&__pyx_v_view));
 374: 
+375:     return {
  __Pyx_XDECREF(__pyx_r);
+376:         'delimiter': chr(dialect.delimiter),
  __pyx_t_2 = __Pyx_PyDict_NewPresized(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 376, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_7 = PyUnicode_FromOrdinal(__pyx_v_dialect.delimiter); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 376, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_7);
  if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_delimiter, __pyx_t_7) < (0)) __PYX_ERR(0, 376, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
+377:         'quote_char': chr(dialect.quote_char)
  __pyx_t_7 = PyUnicode_FromOrdinal(__pyx_v_dialect.quote_char); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 377, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_7);
  if (PyDict_SetItem(__pyx_t_2, __pyx_mstate_global->__pyx_n_u_quote_char, __pyx_t_7) < (0)) __PYX_ERR(0, 376, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0;
  __pyx_r = __pyx_t_2;
  __pyx_t_2 = 0;
  goto __pyx_L0;
 378:     }
 379: 
 380: 
 381: # Convenience function for TSV
+382: def read_tsv(data, columns=None):
/* Python wrapper */
static PyObject *__pyx_pw_4rugo_3csv_7read_tsv(PyObject *__pyx_self, 
#if CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
); /*proto*/
PyDoc_STRVAR(__pyx_doc_4rugo_3csv_6read_tsv, "\n    Read TSV (tab-separated values) data.\n    \n    This is a convenience wrapper around read_csv with delimiter='\\t'.\n    \n    Parameters\n    ----------\n    data : bytes or memoryview\n        The TSV data to read\n    columns : list of str, optional\n        List of column names to read. If None, reads all columns.\n    \n    Returns\n    -------\n    dict\n        Same as read_csv()\n        \n    Examples\n    --------\n    >>> data = b'name\\tage\\tsalary\\nAlice\\t30\\t50000'\n    >>> result = read_tsv(data)\n    >>> print(result['column_names'])\n    ['name', 'age', 'salary']\n    ");
static PyMethodDef __pyx_mdef_4rugo_3csv_7read_tsv = {"read_tsv", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_4rugo_3csv_7read_tsv, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_4rugo_3csv_6read_tsv};
static PyObject *__pyx_pw_4rugo_3csv_7read_tsv(PyObject *__pyx_self, 
#if CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
) {
  PyObject *__pyx_v_data = 0;
  PyObject *__pyx_v_columns = 0;
  #if !CYTHON_METH_FASTCALL
  CYTHON_UNUSED Py_ssize_t __pyx_nargs;
  #endif
  CYTHON_UNUSED PyObject *const *__pyx_kwvalues;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("read_tsv (wrapper)", 0);
  #if !CYTHON_METH_FASTCALL
  #if CYTHON_ASSUME_SAFE_SIZE
  __pyx_nargs = PyTuple_GET_SIZE(__pyx_args);
  #else
  __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL;
  #endif
  #endif
  __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs);
  {
    PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_data,&__pyx_mstate_global->__pyx_n_u_columns,0};
  PyObject* values[2] = {0,0};
    const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0;
    if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 382, __pyx_L3_error)
    if (__pyx_kwds_len > 0) {
      switch (__pyx_nargs) {
        case  2:
        values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 382, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  1:
        values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 382, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      const Py_ssize_t kwd_pos_args = __pyx_nargs;
      if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "read_tsv", 0) < (0)) __PYX_ERR(0, 382, __pyx_L3_error)
      if (!values[1]) values[1] = __Pyx_NewRef(((PyObject *)Py_None));
      for (Py_ssize_t i = __pyx_nargs; i < 1; i++) {
        if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("read_tsv", 0, 1, 2, i); __PYX_ERR(0, 382, __pyx_L3_error) }
      }
    } else {
      switch (__pyx_nargs) {
        case  2:
        values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 382, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  1:
        values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 382, __pyx_L3_error)
        break;
        default: goto __pyx_L5_argtuple_error;
      }
      if (!values[1]) values[1] = __Pyx_NewRef(((PyObject *)Py_None));
    }
    __pyx_v_data = values[0];
    __pyx_v_columns = values[1];
  }
  goto __pyx_L6_skip;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("read_tsv", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 382, __pyx_L3_error)
  __pyx_L6_skip:;
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L3_error:;
  for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
    Py_XDECREF(values[__pyx_temp]);
  }
  __Pyx_AddTraceback("rugo.csv.read_tsv", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_4rugo_3csv_6read_tsv(__pyx_self, __pyx_v_data, __pyx_v_columns);

  /* function exit code */
  for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
    Py_XDECREF(values[__pyx_temp]);
  }
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_4rugo_3csv_6read_tsv(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_data, PyObject *__pyx_v_columns) {
  PyObject *__pyx_r = NULL;
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_5);
  __Pyx_AddTraceback("rugo.csv.read_tsv", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_4rugo_3csv_7read_tsv, 0, __pyx_mstate_global->__pyx_n_u_read_tsv, NULL, __pyx_mstate_global->__pyx_n_u_rugo_csv, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[3])); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 382, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_2, __pyx_mstate_global->__pyx_tuple[3]);
  if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_read_tsv, __pyx_t_2) < (0)) __PYX_ERR(0, 382, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 383:     """
 384:     Read TSV (tab-separated values) data.
 385: 
 386:     This is a convenience wrapper around read_csv with delimiter='\\t'.
 387: 
 388:     Parameters
 389:     ----------
 390:     data : bytes or memoryview
 391:         The TSV data to read
 392:     columns : list of str, optional
 393:         List of column names to read. If None, reads all columns.
 394: 
 395:     Returns
 396:     -------
 397:     dict
 398:         Same as read_csv()
 399: 
 400:     Examples
 401:     --------
 402:     >>> data = b'name\\tage\\tsalary\\nAlice\\t30\\t50000'
 403:     >>> result = read_tsv(data)
 404:     >>> print(result['column_names'])
 405:     ['name', 'age', 'salary']
 406:     """
+407:     return read_csv(data, columns=columns, delimiter='\t')
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_2 = NULL;
  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_read_csv); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 407, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_4 = 1;
  #if CYTHON_UNPACK_METHODS
  if (unlikely(PyMethod_Check(__pyx_t_3))) {
    __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3);
    assert(__pyx_t_2);
    PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_3);
    __Pyx_INCREF(__pyx_t_2);
    __Pyx_INCREF(__pyx__function);
    __Pyx_DECREF_SET(__pyx_t_3, __pyx__function);
    __pyx_t_4 = 0;
  }
  #endif
  {
    PyObject *__pyx_callargs[2 + ((CYTHON_VECTORCALL) ? 2 : 0)] = {__pyx_t_2, __pyx_v_data};
    __pyx_t_5 = __Pyx_MakeVectorcallBuilderKwds(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 407, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_5);
    if (__Pyx_VectorcallBuilder_AddArg(__pyx_mstate_global->__pyx_n_u_columns, __pyx_v_columns, __pyx_t_5, __pyx_callargs+2, 0) < (0)) __PYX_ERR(0, 407, __pyx_L1_error)
    if (__Pyx_VectorcallBuilder_AddArg(__pyx_mstate_global->__pyx_n_u_delimiter, __pyx_mstate_global->__pyx_kp_u__3, __pyx_t_5, __pyx_callargs+2, 1) < (0)) __PYX_ERR(0, 407, __pyx_L1_error)
    __pyx_t_1 = __Pyx_Object_Vectorcall_CallFromBuilder(__pyx_t_3, __pyx_callargs+__pyx_t_4, (2-__pyx_t_4) | (__pyx_t_4*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET), __pyx_t_5);
    __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 407, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_1);
  }
  __pyx_r = __pyx_t_1;
  __pyx_t_1 = 0;
  goto __pyx_L0;
 408: 
 409: 
+410: def get_tsv_schema(data, sample_size=100):
/* Python wrapper */
static PyObject *__pyx_pw_4rugo_3csv_9get_tsv_schema(PyObject *__pyx_self, 
#if CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
); /*proto*/
PyDoc_STRVAR(__pyx_doc_4rugo_3csv_8get_tsv_schema, "\n    Extract schema from TSV data.\n    \n    This is a convenience wrapper around get_csv_schema with delimiter='\\t'.\n    \n    Parameters\n    ----------\n    data : bytes or memoryview\n        The TSV data to analyze\n    sample_size : int, default 100\n        Number of rows to sample for type inference\n    \n    Returns\n    -------\n    list of dict\n        List of column schemas\n    ");
static PyMethodDef __pyx_mdef_4rugo_3csv_9get_tsv_schema = {"get_tsv_schema", (PyCFunction)(void(*)(void))(__Pyx_PyCFunction_FastCallWithKeywords)__pyx_pw_4rugo_3csv_9get_tsv_schema, __Pyx_METH_FASTCALL|METH_KEYWORDS, __pyx_doc_4rugo_3csv_8get_tsv_schema};
static PyObject *__pyx_pw_4rugo_3csv_9get_tsv_schema(PyObject *__pyx_self, 
#if CYTHON_METH_FASTCALL
PyObject *const *__pyx_args, Py_ssize_t __pyx_nargs, PyObject *__pyx_kwds
#else
PyObject *__pyx_args, PyObject *__pyx_kwds
#endif
) {
  PyObject *__pyx_v_data = 0;
  PyObject *__pyx_v_sample_size = 0;
  #if !CYTHON_METH_FASTCALL
  CYTHON_UNUSED Py_ssize_t __pyx_nargs;
  #endif
  CYTHON_UNUSED PyObject *const *__pyx_kwvalues;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("get_tsv_schema (wrapper)", 0);
  #if !CYTHON_METH_FASTCALL
  #if CYTHON_ASSUME_SAFE_SIZE
  __pyx_nargs = PyTuple_GET_SIZE(__pyx_args);
  #else
  __pyx_nargs = PyTuple_Size(__pyx_args); if (unlikely(__pyx_nargs < 0)) return NULL;
  #endif
  #endif
  __pyx_kwvalues = __Pyx_KwValues_FASTCALL(__pyx_args, __pyx_nargs);
  {
    PyObject ** const __pyx_pyargnames[] = {&__pyx_mstate_global->__pyx_n_u_data,&__pyx_mstate_global->__pyx_n_u_sample_size,0};
  PyObject* values[2] = {0,0};
    const Py_ssize_t __pyx_kwds_len = (__pyx_kwds) ? __Pyx_NumKwargs_FASTCALL(__pyx_kwds) : 0;
    if (unlikely(__pyx_kwds_len) < 0) __PYX_ERR(0, 410, __pyx_L3_error)
    if (__pyx_kwds_len > 0) {
      switch (__pyx_nargs) {
        case  2:
        values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 410, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  1:
        values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 410, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      const Py_ssize_t kwd_pos_args = __pyx_nargs;
      if (__Pyx_ParseKeywords(__pyx_kwds, __pyx_kwvalues, __pyx_pyargnames, 0, values, kwd_pos_args, __pyx_kwds_len, "get_tsv_schema", 0) < (0)) __PYX_ERR(0, 410, __pyx_L3_error)
      if (!values[1]) values[1] = __Pyx_NewRef(((PyObject *)((PyObject*)__pyx_mstate_global->__pyx_int_100)));
      for (Py_ssize_t i = __pyx_nargs; i < 1; i++) {
        if (unlikely(!values[i])) { __Pyx_RaiseArgtupleInvalid("get_tsv_schema", 0, 1, 2, i); __PYX_ERR(0, 410, __pyx_L3_error) }
      }
    } else {
      switch (__pyx_nargs) {
        case  2:
        values[1] = __Pyx_ArgRef_FASTCALL(__pyx_args, 1);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[1])) __PYX_ERR(0, 410, __pyx_L3_error)
        CYTHON_FALLTHROUGH;
        case  1:
        values[0] = __Pyx_ArgRef_FASTCALL(__pyx_args, 0);
        if (!CYTHON_ASSUME_SAFE_MACROS && unlikely(!values[0])) __PYX_ERR(0, 410, __pyx_L3_error)
        break;
        default: goto __pyx_L5_argtuple_error;
      }
      if (!values[1]) values[1] = __Pyx_NewRef(((PyObject *)((PyObject*)__pyx_mstate_global->__pyx_int_100)));
    }
    __pyx_v_data = values[0];
    __pyx_v_sample_size = values[1];
  }
  goto __pyx_L6_skip;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("get_tsv_schema", 0, 1, 2, __pyx_nargs); __PYX_ERR(0, 410, __pyx_L3_error)
  __pyx_L6_skip:;
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L3_error:;
  for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
    Py_XDECREF(values[__pyx_temp]);
  }
  __Pyx_AddTraceback("rugo.csv.get_tsv_schema", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  __pyx_r = __pyx_pf_4rugo_3csv_8get_tsv_schema(__pyx_self, __pyx_v_data, __pyx_v_sample_size);
  int __pyx_lineno = 0;
  const char *__pyx_filename = NULL;
  int __pyx_clineno = 0;

  /* function exit code */
  for (Py_ssize_t __pyx_temp=0; __pyx_temp < (Py_ssize_t)(sizeof(values)/sizeof(values[0])); ++__pyx_temp) {
    Py_XDECREF(values[__pyx_temp]);
  }
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_4rugo_3csv_8get_tsv_schema(CYTHON_UNUSED PyObject *__pyx_self, PyObject *__pyx_v_data, PyObject *__pyx_v_sample_size) {
  PyObject *__pyx_r = NULL;
/* … */
  __pyx_t_2 = __Pyx_CyFunction_New(&__pyx_mdef_4rugo_3csv_9get_tsv_schema, 0, __pyx_mstate_global->__pyx_n_u_get_tsv_schema, NULL, __pyx_mstate_global->__pyx_n_u_rugo_csv, __pyx_mstate_global->__pyx_d, ((PyObject *)__pyx_mstate_global->__pyx_codeobj_tab[4])); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 410, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_CyFunction_SetDefaultsTuple(__pyx_t_2, __pyx_mstate_global->__pyx_tuple[2]);
  if (PyDict_SetItem(__pyx_mstate_global->__pyx_d, __pyx_mstate_global->__pyx_n_u_get_tsv_schema, __pyx_t_2) < (0)) __PYX_ERR(0, 410, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 411:     """
 412:     Extract schema from TSV data.
 413: 
 414:     This is a convenience wrapper around get_csv_schema with delimiter='\\t'.
 415: 
 416:     Parameters
 417:     ----------
 418:     data : bytes or memoryview
 419:         The TSV data to analyze
 420:     sample_size : int, default 100
 421:         Number of rows to sample for type inference
 422: 
 423:     Returns
 424:     -------
 425:     list of dict
 426:         List of column schemas
 427:     """
+428:     return get_csv_schema(data, delimiter='\t', sample_size=sample_size)
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_2 = NULL;
  __Pyx_GetModuleGlobalName(__pyx_t_3, __pyx_mstate_global->__pyx_n_u_get_csv_schema); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 428, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_4 = 1;
  #if CYTHON_UNPACK_METHODS
  if (unlikely(PyMethod_Check(__pyx_t_3))) {
    __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3);
    assert(__pyx_t_2);
    PyObject* __pyx__function = PyMethod_GET_FUNCTION(__pyx_t_3);
    __Pyx_INCREF(__pyx_t_2);
    __Pyx_INCREF(__pyx__function);
    __Pyx_DECREF_SET(__pyx_t_3, __pyx__function);
    __pyx_t_4 = 0;
  }
  #endif
  {
    PyObject *__pyx_callargs[2 + ((CYTHON_VECTORCALL) ? 2 : 0)] = {__pyx_t_2, __pyx_v_data};
    __pyx_t_5 = __Pyx_MakeVectorcallBuilderKwds(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 428, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_5);
    if (__Pyx_VectorcallBuilder_AddArg(__pyx_mstate_global->__pyx_n_u_delimiter, __pyx_mstate_global->__pyx_kp_u__3, __pyx_t_5, __pyx_callargs+2, 0) < (0)) __PYX_ERR(0, 428, __pyx_L1_error)
    if (__Pyx_VectorcallBuilder_AddArg(__pyx_mstate_global->__pyx_n_u_sample_size, __pyx_v_sample_size, __pyx_t_5, __pyx_callargs+2, 1) < (0)) __PYX_ERR(0, 428, __pyx_L1_error)
    __pyx_t_1 = __Pyx_Object_Vectorcall_CallFromBuilder(__pyx_t_3, __pyx_callargs+__pyx_t_4, (2-__pyx_t_4) | (__pyx_t_4*__Pyx_PY_VECTORCALL_ARGUMENTS_OFFSET), __pyx_t_5);
    __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 428, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_1);
  }
  __pyx_r = __pyx_t_1;
  __pyx_t_1 = 0;
  goto __pyx_L0;