| 1078 | } |
| 1079 | #[pymethod] |
| 1080 | fn writerow(&self, row: PyObjectRef, vm: &VirtualMachine) -> PyResult { |
| 1081 | let mut state = self.state.lock(); |
| 1082 | let WriteState { buffer, writer } = &mut *state; |
| 1083 | |
| 1084 | let mut buffer_offset = 0; |
| 1085 | |
| 1086 | macro_rules! handle_res { |
| 1087 | ($x:expr) => {{ |
| 1088 | let (res, n_written) = $x; |
| 1089 | buffer_offset += n_written; |
| 1090 | match res { |
| 1091 | csv_core::WriteResult::InputEmpty => break, |
| 1092 | csv_core::WriteResult::OutputFull => resize_buf(buffer), |
| 1093 | } |
| 1094 | }}; |
| 1095 | } |
| 1096 | |
| 1097 | let row = ArgIterable::try_from_object(vm, row.clone()).map_err(|_e| { |
| 1098 | new_csv_error(vm, format!("\'{}\' object is not iterable", row.class())) |
| 1099 | })?; |
| 1100 | let mut first_flag = true; |
| 1101 | for field in row.iter(vm)? { |
| 1102 | let field: PyObjectRef = field?; |
| 1103 | let stringified; |
| 1104 | let data: &[u8] = match_class!(match field { |
| 1105 | ref s @ PyStr => s.as_bytes(), |
| 1106 | crate::builtins::PyNone => b"", |
| 1107 | ref obj => { |
| 1108 | stringified = obj.str(vm)?; |
| 1109 | stringified.as_bytes() |
| 1110 | } |
| 1111 | }); |
| 1112 | let mut input_offset = 0; |
| 1113 | if first_flag { |
| 1114 | first_flag = false; |
| 1115 | } else { |
| 1116 | loop { |
| 1117 | handle_res!(writer.delimiter(&mut buffer[buffer_offset..])); |
| 1118 | } |
| 1119 | } |
| 1120 | |
| 1121 | loop { |
| 1122 | let (res, n_read, n_written) = |
| 1123 | writer.field(&data[input_offset..], &mut buffer[buffer_offset..]); |
| 1124 | input_offset += n_read; |
| 1125 | handle_res!((res, n_written)); |
| 1126 | } |
| 1127 | } |
| 1128 | |
| 1129 | loop { |
| 1130 | handle_res!(writer.terminator(&mut buffer[buffer_offset..])); |
| 1131 | } |
| 1132 | let s = core::str::from_utf8(&buffer[..buffer_offset]) |
| 1133 | .map_err(|_| vm.new_unicode_decode_error("csv not utf8"))?; |
| 1134 | |
| 1135 | self.write.call((s,), vm) |
| 1136 | } |
| 1137 | |