Skip to content

Commit 6ac1266

Browse files
committed
fix windows fileio
1 parent 083dafb commit 6ac1266

4 files changed

Lines changed: 125 additions & 27 deletions

File tree

crates/common/src/crt_fd.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,21 @@ pub fn close(fd: Owned) -> io::Result<()> {
334334
}
335335

336336
pub fn ftruncate(fd: Borrowed<'_>, len: Offset) -> io::Result<()> {
337-
cvt(unsafe { suppress_iph!(c::ftruncate(fd.as_raw(), len)) })?;
337+
let ret = unsafe { suppress_iph!(c::ftruncate(fd.as_raw(), len)) };
338+
// On Windows, _chsize_s returns 0 on success, or a positive error code (errno value) on failure.
339+
// On other platforms, ftruncate returns 0 on success, or -1 on failure with errno set.
340+
#[cfg(windows)]
341+
{
342+
if ret != 0 {
343+
// _chsize_s returns errno directly, convert to Windows error code
344+
let winerror = crate::os::errno_to_winerror(ret);
345+
return Err(io::Error::from_raw_os_error(winerror));
346+
}
347+
}
348+
#[cfg(not(windows))]
349+
{
350+
cvt(ret)?;
351+
}
338352
Ok(())
339353
}
340354

crates/derive-impl/src/pystructseq.rs

Lines changed: 100 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ enum FieldKind {
2222
struct ParsedField {
2323
ident: Ident,
2424
kind: FieldKind,
25+
/// Optional cfg attributes for conditional compilation
26+
cfg_attrs: Vec<syn::Attribute>,
2527
}
2628

2729
/// Parsed field info from struct
@@ -31,27 +33,24 @@ struct FieldInfo {
3133
}
3234

3335
impl FieldInfo {
34-
fn named_fields(&self) -> Vec<Ident> {
36+
fn named_fields(&self) -> Vec<&ParsedField> {
3537
self.fields
3638
.iter()
3739
.filter(|f| f.kind == FieldKind::Named)
38-
.map(|f| f.ident.clone())
3940
.collect()
4041
}
4142

42-
fn visible_fields(&self) -> Vec<Ident> {
43+
fn visible_fields(&self) -> Vec<&ParsedField> {
4344
self.fields
4445
.iter()
4546
.filter(|f| f.kind != FieldKind::Skipped)
46-
.map(|f| f.ident.clone())
4747
.collect()
4848
}
4949

50-
fn skipped_fields(&self) -> Vec<Ident> {
50+
fn skipped_fields(&self) -> Vec<&ParsedField> {
5151
self.fields
5252
.iter()
5353
.filter(|f| f.kind == FieldKind::Skipped)
54-
.map(|f| f.ident.clone())
5554
.collect()
5655
}
5756

@@ -82,8 +81,15 @@ fn parse_fields(input: &mut DeriveInput) -> Result<FieldInfo> {
8281
let mut skip = false;
8382
let mut unnamed = false;
8483
let mut attrs_to_remove = Vec::new();
84+
let mut cfg_attrs = Vec::new();
8585

8686
for (i, attr) in field.attrs.iter().enumerate() {
87+
// Collect cfg attributes for conditional compilation
88+
if attr.path().is_ident("cfg") {
89+
cfg_attrs.push(attr.clone());
90+
continue;
91+
}
92+
8793
if !attr.path().is_ident("pystruct_sequence") {
8894
continue;
8995
}
@@ -135,7 +141,11 @@ fn parse_fields(input: &mut DeriveInput) -> Result<FieldInfo> {
135141
FieldKind::Named
136142
};
137143

138-
parsed_fields.push(ParsedField { ident, kind });
144+
parsed_fields.push(ParsedField {
145+
ident,
146+
kind,
147+
cfg_attrs,
148+
});
139149
}
140150

141151
Ok(FieldInfo {
@@ -194,18 +204,91 @@ pub(crate) fn impl_pystruct_sequence_data(
194204
let skipped_fields = field_info.skipped_fields();
195205
let n_unnamed_fields = field_info.n_unnamed_fields();
196206

197-
// Generate field index constants for visible fields
207+
// Generate field index constants for visible fields (with cfg guards)
198208
let field_indices: Vec<_> = visible_fields
199209
.iter()
200210
.enumerate()
201211
.map(|(i, field)| {
202-
let const_name = format_ident!("{}_INDEX", field.to_string().to_uppercase());
212+
let const_name = format_ident!("{}_INDEX", field.ident.to_string().to_uppercase());
213+
let cfg_attrs = &field.cfg_attrs;
203214
quote! {
215+
#(#cfg_attrs)*
204216
pub const #const_name: usize = #i;
205217
}
206218
})
207219
.collect();
208220

221+
// Generate field name entries with cfg guards for named fields
222+
let named_field_names: Vec<_> = named_fields
223+
.iter()
224+
.map(|f| {
225+
let ident = &f.ident;
226+
let cfg_attrs = &f.cfg_attrs;
227+
if cfg_attrs.is_empty() {
228+
quote! { stringify!(#ident), }
229+
} else {
230+
quote! {
231+
#(#cfg_attrs)*
232+
{ stringify!(#ident) },
233+
}
234+
}
235+
})
236+
.collect();
237+
238+
// Generate field name entries with cfg guards for skipped fields
239+
let skipped_field_names: Vec<_> = skipped_fields
240+
.iter()
241+
.map(|f| {
242+
let ident = &f.ident;
243+
let cfg_attrs = &f.cfg_attrs;
244+
if cfg_attrs.is_empty() {
245+
quote! { stringify!(#ident), }
246+
} else {
247+
quote! {
248+
#(#cfg_attrs)*
249+
{ stringify!(#ident) },
250+
}
251+
}
252+
})
253+
.collect();
254+
255+
// Generate into_tuple items with cfg guards
256+
let visible_tuple_items: Vec<_> = visible_fields
257+
.iter()
258+
.map(|f| {
259+
let ident = &f.ident;
260+
let cfg_attrs = &f.cfg_attrs;
261+
if cfg_attrs.is_empty() {
262+
quote! {
263+
::rustpython_vm::convert::ToPyObject::to_pyobject(self.#ident, vm),
264+
}
265+
} else {
266+
quote! {
267+
#(#cfg_attrs)*
268+
{ ::rustpython_vm::convert::ToPyObject::to_pyobject(self.#ident, vm) },
269+
}
270+
}
271+
})
272+
.collect();
273+
274+
let skipped_tuple_items: Vec<_> = skipped_fields
275+
.iter()
276+
.map(|f| {
277+
let ident = &f.ident;
278+
let cfg_attrs = &f.cfg_attrs;
279+
if cfg_attrs.is_empty() {
280+
quote! {
281+
::rustpython_vm::convert::ToPyObject::to_pyobject(self.#ident, vm),
282+
}
283+
} else {
284+
quote! {
285+
#(#cfg_attrs)*
286+
{ ::rustpython_vm::convert::ToPyObject::to_pyobject(self.#ident, vm) },
287+
}
288+
}
289+
})
290+
.collect();
291+
209292
// Generate TryFromObject impl only when try_from_object=true
210293
let try_from_object_impl = if try_from_object {
211294
let n_required = visible_fields.len();
@@ -233,15 +316,17 @@ pub(crate) fn impl_pystruct_sequence_data(
233316

234317
// Generate try_from_elements trait override only when try_from_object=true
235318
let try_from_elements_trait_override = if try_from_object {
319+
let visible_field_idents: Vec<_> = visible_fields.iter().map(|f| &f.ident).collect();
320+
let skipped_field_idents: Vec<_> = skipped_fields.iter().map(|f| &f.ident).collect();
236321
quote! {
237322
fn try_from_elements(
238323
elements: Vec<::rustpython_vm::PyObjectRef>,
239324
vm: &::rustpython_vm::VirtualMachine,
240325
) -> ::rustpython_vm::PyResult<Self> {
241326
let mut iter = elements.into_iter();
242327
Ok(Self {
243-
#(#visible_fields: iter.next().unwrap().clone().try_into_value(vm)?,)*
244-
#(#skipped_fields: match iter.next() {
328+
#(#visible_field_idents: iter.next().unwrap().clone().try_into_value(vm)?,)*
329+
#(#skipped_field_idents: match iter.next() {
245330
Some(v) => v.clone().try_into_value(vm)?,
246331
None => vm.ctx.none(),
247332
},)*
@@ -259,20 +344,14 @@ pub(crate) fn impl_pystruct_sequence_data(
259344

260345
// PyStructSequenceData trait impl
261346
impl ::rustpython_vm::types::PyStructSequenceData for #data_ident {
262-
const REQUIRED_FIELD_NAMES: &'static [&'static str] = &[#(stringify!(#named_fields),)*];
263-
const OPTIONAL_FIELD_NAMES: &'static [&'static str] = &[#(stringify!(#skipped_fields),)*];
347+
const REQUIRED_FIELD_NAMES: &'static [&'static str] = &[#(#named_field_names)*];
348+
const OPTIONAL_FIELD_NAMES: &'static [&'static str] = &[#(#skipped_field_names)*];
264349
const UNNAMED_FIELDS_LEN: usize = #n_unnamed_fields;
265350

266351
fn into_tuple(self, vm: &::rustpython_vm::VirtualMachine) -> ::rustpython_vm::builtins::PyTuple {
267352
let items = vec![
268-
#(::rustpython_vm::convert::ToPyObject::to_pyobject(
269-
self.#visible_fields,
270-
vm,
271-
),)*
272-
#(::rustpython_vm::convert::ToPyObject::to_pyobject(
273-
self.#skipped_fields,
274-
vm,
275-
),)*
353+
#(#visible_tuple_items)*
354+
#(#skipped_tuple_items)*
276355
];
277356
::rustpython_vm::builtins::PyTuple::new_unchecked(items.into_boxed_slice())
278357
}

crates/vm/src/stdlib/io.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4657,7 +4657,7 @@ mod fileio {
46574657
closefd: AtomicCell::new(true),
46584658
mode: AtomicCell::new(Mode::empty()),
46594659
seekable: AtomicCell::new(None),
4660-
blksize: AtomicCell::new(0),
4660+
blksize: AtomicCell::new(8 * 1024), // DEFAULT_BUFFER_SIZE
46614661
}
46624662
}
46634663
}

crates/vm/src/stdlib/os.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -894,9 +894,11 @@ pub(super) mod _os {
894894
#[pystruct_sequence(skip)]
895895
pub st_ctime_ns: i128,
896896
// Unix-specific attributes
897+
#[cfg(not(windows))]
897898
#[pyarg(any, default)]
898899
#[pystruct_sequence(skip)]
899900
pub st_blksize: i64,
901+
#[cfg(not(windows))]
900902
#[pyarg(any, default)]
901903
#[pystruct_sequence(skip)]
902904
pub st_blocks: i64,
@@ -952,11 +954,12 @@ pub(super) mod _os {
952954
#[cfg(not(windows))]
953955
let st_ino = stat.st_ino;
954956

955-
#[cfg(any(unix, target_os = "wasi"))]
957+
#[cfg(not(windows))]
956958
#[allow(clippy::useless_conversion)] // needed for 32-bit platforms
957-
let (st_blksize, st_blocks) = (i64::from(stat.st_blksize), i64::from(stat.st_blocks));
958-
#[cfg(windows)]
959-
let (st_blksize, st_blocks) = (0i64, 0i64);
959+
let st_blksize = i64::from(stat.st_blksize);
960+
#[cfg(not(windows))]
961+
#[allow(clippy::useless_conversion)] // needed for 32-bit platforms
962+
let st_blocks = i64::from(stat.st_blocks);
960963

961964
Self {
962965
st_mode: vm.ctx.new_pyref(stat.st_mode),
@@ -975,7 +978,9 @@ pub(super) mod _os {
975978
st_atime_ns: to_ns(atime),
976979
st_mtime_ns: to_ns(mtime),
977980
st_ctime_ns: to_ns(ctime),
981+
#[cfg(not(windows))]
978982
st_blksize,
983+
#[cfg(not(windows))]
979984
st_blocks,
980985
st_reparse_tag,
981986
st_file_attributes,

0 commit comments

Comments
 (0)