dotscope 0.6.0

A high-performance, cross-platform framework for analyzing and reverse engineering .NET PE executables
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
//! ClassLayoutBuilder for creating type layout specifications.
//!
//! This module provides [`crate::metadata::tables::classlayout::ClassLayoutBuilder`] for creating ClassLayout table entries
//! with a fluent API. Class layouts define memory layout characteristics for types,
//! including field alignment boundaries, explicit type sizes, and packing behavior
//! for P/Invoke interop, performance optimization, and platform compatibility.

use crate::{
    cilassembly::{ChangeRefRc, CilAssembly},
    metadata::{
        tables::{ClassLayoutRaw, TableDataOwned, TableId},
        token::Token,
    },
    Error, Result,
};

/// Builder for creating ClassLayout metadata entries.
///
/// `ClassLayoutBuilder` provides a fluent API for creating ClassLayout table entries
/// with validation and automatic table management. Class layouts define type-level
/// memory layout characteristics including field alignment boundaries, explicit type
/// sizes, and packing behavior for performance optimization and interoperability scenarios.
///
/// # Class Layout Model
///
/// .NET class layout follows a structured pattern:
/// - **Parent Type**: The type definition that this layout applies to
/// - **Packing Size**: Field alignment boundary (must be 0 or power of 2)
/// - **Class Size**: Explicit type size override (0 for automatic sizing)
/// - **Layout Control**: Precise control over type memory characteristics
///
/// # Layout Types and Scenarios
///
/// Class layouts are essential for various memory management scenarios:
/// - **P/Invoke Interop**: Matching native C/C++ struct sizes and alignment
/// - **Performance Critical Types**: Cache-line alignment and SIMD optimization
/// - **Memory Mapping**: Direct memory-mapped structures with fixed sizes
/// - **Platform Compatibility**: Consistent layouts across different architectures
/// - **Legacy Compatibility**: Matching existing binary format specifications
/// - **COM Interop**: Implementing COM interface memory layout requirements
///
/// # Packing Size Specifications
///
/// Packing size controls field alignment boundaries:
/// - **0**: Default packing (typically 8 bytes, platform-dependent)
/// - **1**: Byte alignment (no padding between fields)
/// - **2**: 2-byte alignment (short/char alignment)
/// - **4**: 4-byte alignment (int/float alignment)
/// - **8**: 8-byte alignment (long/double alignment)
/// - **16**: 16-byte alignment (SIMD/SSE alignment)
/// - **32**: 32-byte alignment (AVX alignment)
/// - **64**: 64-byte alignment (cache line alignment)
/// - **128**: 128-byte alignment (maximum allowed)
///
/// # Class Size Specifications
///
/// Class size provides explicit type size control:
/// - **0**: Automatic size calculation based on fields
/// - **Non-zero**: Explicit type size override in bytes
/// - **Minimum**: Must accommodate all fields within the type
/// - **Maximum**: Cannot exceed 256MB (0x10000000 bytes)
/// - **Alignment**: Should respect packing size alignment
///
/// # Examples
///
/// ```rust,no_run
/// # use dotscope::prelude::*;
/// # use dotscope::metadata::tables::ClassLayoutBuilder;
/// # use std::path::Path;
/// # let view = CilAssemblyView::from_path(Path::new("test.dll"))?;
/// let mut assembly = CilAssembly::new(view);
///
/// // Create layout for a P/Invoke structure with byte packing
/// let struct_type_rid = 1; // TypeDef RID 1
///
/// let packed_layout = ClassLayoutBuilder::new()
///     .parent(struct_type_rid)
///     .packing_size(1) // Byte packing (no padding)
///     .class_size(0)   // Automatic size
///     .build(&mut assembly)?;
///
/// // Create layout for a performance-critical type with cache-line alignment
/// let perf_type_rid = 2; // TypeDef RID 2
///
/// let aligned_layout = ClassLayoutBuilder::new()
///     .parent(perf_type_rid)
///     .packing_size(64) // Cache line alignment
///     .class_size(128)  // Fixed 128-byte size
///     .build(&mut assembly)?;
///
/// // Create layout for SIMD-optimized mathematics structure
/// let simd_type_rid = 3; // TypeDef RID 3
///
/// let simd_layout = ClassLayoutBuilder::new()
///     .parent(simd_type_rid)
///     .packing_size(16) // SSE/SIMD alignment
///     .class_size(64)   // Fixed 64-byte size for 4x float4
///     .build(&mut assembly)?;
///
/// // Create layout for exact native structure matching
/// let native_type_rid = 4; // TypeDef RID 4
///
/// let native_layout = ClassLayoutBuilder::new()
///     .parent(native_type_rid)
///     .packing_size(4)  // 32-bit alignment
///     .class_size(24)   // Exact size to match native struct
///     .build(&mut assembly)?;
/// # Ok::<(), dotscope::Error>(())
/// ```
pub struct ClassLayoutBuilder {
    packing_size: Option<u16>,
    class_size: Option<u32>,
    parent: Option<u32>,
}

impl Default for ClassLayoutBuilder {
    fn default() -> Self {
        Self::new()
    }
}

impl ClassLayoutBuilder {
    /// Creates a new ClassLayoutBuilder.
    ///
    /// # Returns
    ///
    /// A new [`crate::metadata::tables::classlayout::ClassLayoutBuilder`] instance ready for configuration.
    #[must_use]
    pub fn new() -> Self {
        Self {
            packing_size: None,
            class_size: None,
            parent: None,
        }
    }

    /// Sets the field alignment boundary (packing size).
    ///
    /// The packing size controls the alignment boundary for fields within the type,
    /// affecting both field placement and overall type size. This directly impacts
    /// memory layout, performance characteristics, and interoperability requirements.
    ///
    /// Packing size constraints:
    /// - **Must be 0 or a power of 2**: 0, 1, 2, 4, 8, 16, 32, 64, 128
    /// - **0 means default**: Platform-dependent default alignment (typically 8 bytes)
    /// - **Maximum value**: 128 bytes (larger values are not supported)
    /// - **Performance impact**: Smaller values reduce memory usage but may hurt performance
    /// - **Interop requirement**: Must match native structure alignment expectations
    ///
    /// Common packing scenarios:
    /// - **1**: Tight packing for network protocols and file formats
    /// - **4**: Standard 32-bit platform alignment
    /// - **8**: Standard 64-bit platform alignment and double precision
    /// - **16**: SIMD/SSE optimization alignment
    /// - **32**: AVX optimization alignment
    /// - **64**: Cache line alignment for performance-critical structures
    ///
    /// # Arguments
    ///
    /// * `packing` - The field alignment boundary in bytes (0 or power of 2, max 128)
    ///
    /// # Returns
    ///
    /// Self for method chaining.
    #[must_use]
    pub fn packing_size(mut self, packing: u16) -> Self {
        self.packing_size = Some(packing);
        self
    }

    /// Sets the explicit type size override.
    ///
    /// The class size provides explicit control over the total size of the type,
    /// overriding automatic size calculation based on field layout. This is essential
    /// for exact native structure matching and performance optimization scenarios.
    ///
    /// Class size considerations:
    /// - **0 means automatic**: Let the runtime calculate size based on fields
    /// - **Non-zero override**: Explicit size specification in bytes
    /// - **Minimum requirement**: Must accommodate all fields and their alignment
    /// - **Maximum limit**: Cannot exceed 256MB (0x10000000 bytes)
    /// - **Alignment respect**: Should be aligned to packing size boundary
    /// - **Padding inclusion**: Size includes any trailing padding needed
    ///
    /// Size specification scenarios:
    /// - **Native matching**: Exact size to match C/C++ structures
    /// - **Performance tuning**: Specific sizes for cache optimization
    /// - **Memory mapping**: Fixed sizes for memory-mapped data structures
    /// - **Protocol compliance**: Exact sizes for network and file protocols
    /// - **Legacy compatibility**: Maintaining compatibility with existing layouts
    ///
    /// # Arguments
    ///
    /// * `size` - The explicit type size in bytes (0 for automatic, max 256MB)
    ///
    /// # Returns
    ///
    /// Self for method chaining.
    #[must_use]
    pub fn class_size(mut self, size: u32) -> Self {
        self.class_size = Some(size);
        self
    }

    /// Sets the parent type that this layout applies to.
    ///
    /// The parent must be a valid TypeDef row index or placeholder that references a type definition
    /// in the current assembly. This establishes which type will have this layout
    /// specification applied to control its memory characteristics.
    ///
    /// Parent type requirements:
    /// - **Valid Row Index**: Must be a valid TypeDef row index or placeholder
    /// - **Existing Type**: Must reference a type that has been defined
    /// - **Layout Compatible**: Type must support explicit layout specification
    /// - **Single Layout**: Each type can have at most one ClassLayout entry
    /// - **Class or Struct**: Only applies to classes and value types, not interfaces
    ///
    /// Type categories that can have layout:
    /// - **Value Types**: Structs with explicit memory layout control
    /// - **Reference Types**: Classes with specific layout requirements
    /// - **P/Invoke Types**: Types used in native interop scenarios
    /// - **Performance Types**: Types optimized for specific performance characteristics
    /// - **Protocol Types**: Types matching external data format specifications
    ///
    /// # Arguments
    ///
    /// * `parent` - A TypeDef row index or placeholder pointing to the type receiving this layout
    ///
    /// # Returns
    ///
    /// Self for method chaining.
    #[must_use]
    pub fn parent(mut self, parent: u32) -> Self {
        self.parent = Some(parent);
        self
    }

    /// Builds the class layout and adds it to the assembly.
    ///
    /// This method validates all required fields are set, verifies the constraints
    /// are met, creates the raw class layout structure, and adds it to the
    /// ClassLayout table with proper token generation and validation.
    ///
    /// # Arguments
    ///
    /// * `assembly` - The CilAssembly for managing the assembly
    ///
    /// # Returns
    ///
    /// A [`crate::metadata::token::Token`] representing the newly created class layout, or an error if
    /// validation fails or required fields are missing.
    ///
    /// # Errors
    ///
    /// - Returns error if packing_size is not set
    /// - Returns error if class_size is not set
    /// - Returns error if parent is not set
    /// - Returns error if packing_size is not 0 or a power of 2
    /// - Returns error if packing_size exceeds 128 bytes
    /// - Returns error if class_size exceeds 256MB limit
    /// - Returns error if table operations fail
    pub fn build(self, assembly: &mut CilAssembly) -> Result<ChangeRefRc> {
        const MAX_CLASS_SIZE: u32 = 0x1000_0000; // 256MB

        let packing_size = self
            .packing_size
            .ok_or_else(|| Error::ModificationInvalid("Packing size is required".to_string()))?;

        let class_size = self
            .class_size
            .ok_or_else(|| Error::ModificationInvalid("Class size is required".to_string()))?;

        let parent = self
            .parent
            .ok_or_else(|| Error::ModificationInvalid("Parent type is required".to_string()))?;

        if packing_size != 0 && (packing_size & (packing_size - 1)) != 0 {
            return Err(Error::ModificationInvalid(format!(
                "Packing size must be 0 or a power of 2, got {packing_size}"
            )));
        }

        if packing_size > 128 {
            return Err(Error::ModificationInvalid(format!(
                "Packing size cannot exceed 128 bytes, got {packing_size}"
            )));
        }

        if class_size > MAX_CLASS_SIZE {
            return Err(Error::ModificationInvalid(format!(
                "Class size cannot exceed 256MB (0x{MAX_CLASS_SIZE:X}), got {class_size}"
            )));
        }

        let rid = assembly.next_rid(TableId::ClassLayout)?;

        let token = Token::from_parts(TableId::ClassLayout, rid);

        let class_layout_raw = ClassLayoutRaw {
            rid,
            token,
            offset: 0, // Will be set during binary generation
            packing_size,
            class_size,
            parent,
        };

        assembly.table_row_add(
            TableId::ClassLayout,
            TableDataOwned::ClassLayout(class_layout_raw),
        )
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        cilassembly::{ChangeRefKind, CilAssembly},
        metadata::cilassemblyview::CilAssemblyView,
    };
    use std::path::PathBuf;

    #[test]
    fn test_class_layout_builder_basic() {
        let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/samples/WindowsBase.dll");
        if let Ok(view) = CilAssemblyView::from_path(&path) {
            let mut assembly = CilAssembly::new(view);

            // Create a basic class layout
            let type_rid = 1; // TypeDef RID 1

            let layout_ref = ClassLayoutBuilder::new()
                .parent(type_rid)
                .packing_size(4)
                .class_size(0)
                .build(&mut assembly)
                .unwrap();

            // Verify ref is created correctly
            assert_eq!(
                layout_ref.kind(),
                ChangeRefKind::TableRow(TableId::ClassLayout)
            );
        }
    }

    #[test]
    fn test_class_layout_builder_different_packings() {
        let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/samples/WindowsBase.dll");
        if let Ok(view) = CilAssemblyView::from_path(&path) {
            let mut assembly = CilAssembly::new(view);

            // Test various valid packing sizes (powers of 2)
            let type1_rid = 1; // TypeDef RID 1
            let type2_rid = 2; // TypeDef RID 2
            let type3_rid = 3; // TypeDef RID 3
            let type4_rid = 4; // TypeDef RID 4

            // Packing 1 (byte packing)
            let layout1_ref = ClassLayoutBuilder::new()
                .parent(type1_rid)
                .packing_size(1)
                .class_size(0)
                .build(&mut assembly)
                .unwrap();

            // Packing 8 (standard 64-bit alignment)
            let layout2_ref = ClassLayoutBuilder::new()
                .parent(type2_rid)
                .packing_size(8)
                .class_size(0)
                .build(&mut assembly)
                .unwrap();

            // Packing 16 (SIMD alignment)
            let layout3_ref = ClassLayoutBuilder::new()
                .parent(type3_rid)
                .packing_size(16)
                .class_size(0)
                .build(&mut assembly)
                .unwrap();

            // Packing 64 (cache line alignment)
            let layout4_ref = ClassLayoutBuilder::new()
                .parent(type4_rid)
                .packing_size(64)
                .class_size(0)
                .build(&mut assembly)
                .unwrap();

            // All should succeed with ClassLayout table kind
            assert_eq!(
                layout1_ref.kind(),
                ChangeRefKind::TableRow(TableId::ClassLayout)
            );
            assert_eq!(
                layout2_ref.kind(),
                ChangeRefKind::TableRow(TableId::ClassLayout)
            );
            assert_eq!(
                layout3_ref.kind(),
                ChangeRefKind::TableRow(TableId::ClassLayout)
            );
            assert_eq!(
                layout4_ref.kind(),
                ChangeRefKind::TableRow(TableId::ClassLayout)
            );

            // All should be different references
            assert!(!std::sync::Arc::ptr_eq(&layout1_ref, &layout2_ref));
            assert!(!std::sync::Arc::ptr_eq(&layout1_ref, &layout3_ref));
            assert!(!std::sync::Arc::ptr_eq(&layout1_ref, &layout4_ref));
        }
    }

    #[test]
    fn test_class_layout_builder_default_packing() {
        let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/samples/WindowsBase.dll");
        if let Ok(view) = CilAssemblyView::from_path(&path) {
            let mut assembly = CilAssembly::new(view);

            let type_rid = 1; // TypeDef RID 1

            // Packing 0 (default alignment)
            let layout_ref = ClassLayoutBuilder::new()
                .parent(type_rid)
                .packing_size(0) // Default packing
                .class_size(0) // Automatic size
                .build(&mut assembly)
                .unwrap();

            // Should succeed
            assert_eq!(
                layout_ref.kind(),
                ChangeRefKind::TableRow(TableId::ClassLayout)
            );
        }
    }

    #[test]
    fn test_class_layout_builder_explicit_sizes() {
        let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/samples/WindowsBase.dll");
        if let Ok(view) = CilAssemblyView::from_path(&path) {
            let mut assembly = CilAssembly::new(view);

            // Test various explicit sizes
            let type1_rid = 1; // TypeDef RID 1
            let type2_rid = 2; // TypeDef RID 2
            let type3_rid = 3; // TypeDef RID 3

            // Small structure (16 bytes)
            let layout1_ref = ClassLayoutBuilder::new()
                .parent(type1_rid)
                .packing_size(4)
                .class_size(16)
                .build(&mut assembly)
                .unwrap();

            // Medium structure (256 bytes)
            let layout2_ref = ClassLayoutBuilder::new()
                .parent(type2_rid)
                .packing_size(8)
                .class_size(256)
                .build(&mut assembly)
                .unwrap();

            // Large structure (64KB)
            let layout3_ref = ClassLayoutBuilder::new()
                .parent(type3_rid)
                .packing_size(16)
                .class_size(65536)
                .build(&mut assembly)
                .unwrap();

            // All should succeed
            assert_eq!(
                layout1_ref.kind(),
                ChangeRefKind::TableRow(TableId::ClassLayout)
            );
            assert_eq!(
                layout2_ref.kind(),
                ChangeRefKind::TableRow(TableId::ClassLayout)
            );
            assert_eq!(
                layout3_ref.kind(),
                ChangeRefKind::TableRow(TableId::ClassLayout)
            );
        }
    }

    #[test]
    fn test_class_layout_builder_missing_packing_size() {
        let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/samples/WindowsBase.dll");
        if let Ok(view) = CilAssemblyView::from_path(&path) {
            let mut assembly = CilAssembly::new(view);

            let type_rid = 1; // TypeDef RID 1

            let result = ClassLayoutBuilder::new()
                .parent(type_rid)
                .class_size(16)
                // Missing packing_size
                .build(&mut assembly);

            // Should fail because packing size is required
            assert!(result.is_err());
        }
    }

    #[test]
    fn test_class_layout_builder_missing_class_size() {
        let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/samples/WindowsBase.dll");
        if let Ok(view) = CilAssemblyView::from_path(&path) {
            let mut assembly = CilAssembly::new(view);

            let type_rid = 1; // TypeDef RID 1

            let result = ClassLayoutBuilder::new()
                .parent(type_rid)
                .packing_size(4)
                // Missing class_size
                .build(&mut assembly);

            // Should fail because class size is required
            assert!(result.is_err());
        }
    }

    #[test]
    fn test_class_layout_builder_missing_parent() {
        let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/samples/WindowsBase.dll");
        if let Ok(view) = CilAssemblyView::from_path(&path) {
            let mut assembly = CilAssembly::new(view);

            let result = ClassLayoutBuilder::new()
                .packing_size(4)
                .class_size(16)
                // Missing parent
                .build(&mut assembly);

            // Should fail because parent is required
            assert!(result.is_err());
        }
    }

    #[test]
    fn test_class_layout_builder_invalid_packing_size() {
        let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/samples/WindowsBase.dll");
        if let Ok(view) = CilAssemblyView::from_path(&path) {
            let mut assembly = CilAssembly::new(view);

            let type_rid = 1; // TypeDef RID 1

            // Test non-power-of-2 packing size
            let result = ClassLayoutBuilder::new()
                .parent(type_rid)
                .packing_size(3) // Not a power of 2
                .class_size(16)
                .build(&mut assembly);

            // Should fail because packing size is not a power of 2
            assert!(result.is_err());
        }
    }

    #[test]
    fn test_class_layout_builder_excessive_packing_size() {
        let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/samples/WindowsBase.dll");
        if let Ok(view) = CilAssemblyView::from_path(&path) {
            let mut assembly = CilAssembly::new(view);

            let type_rid = 1; // TypeDef RID 1

            let result = ClassLayoutBuilder::new()
                .parent(type_rid)
                .packing_size(256) // Exceeds maximum of 128
                .class_size(16)
                .build(&mut assembly);

            // Should fail because packing size exceeds maximum
            assert!(result.is_err());
        }
    }

    #[test]
    fn test_class_layout_builder_excessive_class_size() {
        let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/samples/WindowsBase.dll");
        if let Ok(view) = CilAssemblyView::from_path(&path) {
            let mut assembly = CilAssembly::new(view);

            let type_rid = 1; // TypeDef RID 1

            let result = ClassLayoutBuilder::new()
                .parent(type_rid)
                .packing_size(4)
                .class_size(0x20000000) // Exceeds 256MB limit
                .build(&mut assembly);

            // Should fail because class size exceeds maximum
            assert!(result.is_err());
        }
    }

    #[test]
    fn test_class_layout_builder_maximum_valid_values() {
        let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/samples/WindowsBase.dll");
        if let Ok(view) = CilAssemblyView::from_path(&path) {
            let mut assembly = CilAssembly::new(view);

            let type_rid = 1; // TypeDef RID 1

            // Test maximum valid values
            let layout_ref = ClassLayoutBuilder::new()
                .parent(type_rid)
                .packing_size(128) // Maximum packing size
                .class_size(0x10000000 - 1) // Just under 256MB limit
                .build(&mut assembly)
                .unwrap();

            // Should succeed
            assert_eq!(
                layout_ref.kind(),
                ChangeRefKind::TableRow(TableId::ClassLayout)
            );
        }
    }

    #[test]
    fn test_class_layout_builder_all_valid_packing_sizes() {
        let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/samples/WindowsBase.dll");
        if let Ok(view) = CilAssemblyView::from_path(&path) {
            let mut assembly = CilAssembly::new(view);

            // Test all valid packing sizes (powers of 2 from 0 to 128)
            let valid_packings = [0, 1, 2, 4, 8, 16, 32, 64, 128];

            for (i, &packing) in valid_packings.iter().enumerate() {
                let type_rid = 1 + i as u32; // Different TypeDef RID for each

                let layout_ref = ClassLayoutBuilder::new()
                    .parent(type_rid)
                    .packing_size(packing)
                    .class_size(16)
                    .build(&mut assembly)
                    .unwrap();

                // All should succeed
                assert_eq!(
                    layout_ref.kind(),
                    ChangeRefKind::TableRow(TableId::ClassLayout)
                );
            }
        }
    }

    #[test]
    fn test_class_layout_builder_realistic_scenarios() {
        let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/samples/WindowsBase.dll");
        if let Ok(view) = CilAssemblyView::from_path(&path) {
            let mut assembly = CilAssembly::new(view);

            // P/Invoke struct with byte packing
            let pinvoke_type_rid = 1; // TypeDef RID 1
            let pinvoke_layout_ref = ClassLayoutBuilder::new()
                .parent(pinvoke_type_rid)
                .packing_size(1) // Byte packing for exact native matching
                .class_size(32) // Fixed size to match native struct
                .build(&mut assembly)
                .unwrap();

            // Performance-critical type with cache line alignment
            let perf_type_rid = 2; // TypeDef RID 2
            let perf_layout_ref = ClassLayoutBuilder::new()
                .parent(perf_type_rid)
                .packing_size(64) // Cache line alignment
                .class_size(128) // Two cache lines
                .build(&mut assembly)
                .unwrap();

            // SIMD mathematics structure
            let simd_type_rid = 3; // TypeDef RID 3
            let simd_layout_ref = ClassLayoutBuilder::new()
                .parent(simd_type_rid)
                .packing_size(16) // SSE/SIMD alignment
                .class_size(64) // 4x float4 vectors
                .build(&mut assembly)
                .unwrap();

            // Standard managed type with default layout
            let managed_type_rid = 4; // TypeDef RID 4
            let managed_layout_ref = ClassLayoutBuilder::new()
                .parent(managed_type_rid)
                .packing_size(0) // Default runtime alignment
                .class_size(0) // Automatic size calculation
                .build(&mut assembly)
                .unwrap();

            // All should succeed
            assert_eq!(
                pinvoke_layout_ref.kind(),
                ChangeRefKind::TableRow(TableId::ClassLayout)
            );
            assert_eq!(
                perf_layout_ref.kind(),
                ChangeRefKind::TableRow(TableId::ClassLayout)
            );
            assert_eq!(
                simd_layout_ref.kind(),
                ChangeRefKind::TableRow(TableId::ClassLayout)
            );
            assert_eq!(
                managed_layout_ref.kind(),
                ChangeRefKind::TableRow(TableId::ClassLayout)
            );

            // All should be different references
            assert!(!std::sync::Arc::ptr_eq(
                &pinvoke_layout_ref,
                &perf_layout_ref
            ));
            assert!(!std::sync::Arc::ptr_eq(
                &pinvoke_layout_ref,
                &simd_layout_ref
            ));
            assert!(!std::sync::Arc::ptr_eq(
                &pinvoke_layout_ref,
                &managed_layout_ref
            ));
            assert!(!std::sync::Arc::ptr_eq(&perf_layout_ref, &simd_layout_ref));
            assert!(!std::sync::Arc::ptr_eq(
                &perf_layout_ref,
                &managed_layout_ref
            ));
            assert!(!std::sync::Arc::ptr_eq(
                &simd_layout_ref,
                &managed_layout_ref
            ));
        }
    }
}