rtea 0.4.0

Makes writing Tcl extensions in Rust ergonomic.
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
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
use crate::tcl::TclBuf;
use std::ffi::CString;
use std::ffi::c_double;
use std::ffi::c_int;
use std::ffi::c_longlong;
use std::ffi::c_uint;
use std::ffi::c_ulonglong;
use std::ffi::c_void;
use std::os::raw::c_char;

use crate::Object;
use crate::ObjectType;
use crate::RawObject;
use crate::TclObjectType;
use crate::tcl::*;

/// A wrapper around a [Tcl](https://www.tcl.tk) interpreter object.
///
/// This is a wrapper around the Tcl interpreter object that leverages the
/// Stubs interface.  It makes assumptions about the interface (such as
/// stability of function pointers) that are made by the underlying stubs
/// implementation.  However, as a deliberate nod to the importance of the
/// borrow checker and other rust conventions, it obtains the stubs table on
/// each `command` rather than caching the version passed during the call to
/// an initialization routine.  While this sacrifices runtime performance
/// (extra indirection), it fits more with Rust paradigms and should reduce
/// the risk of trying to use the API without an associated interpeter.
#[repr(C)]
#[derive(Debug)]
pub struct Interpreter {
    _legacy_result: *const c_void,
    _legacy_free_proc: *const c_void,
    _error_line: isize,
    stubs: *const Stubs,
}

type CmdProc = fn(interp: &Interpreter, args: Vec<&str>) -> Result<TclStatus, String>;
type ObjCmdProc = fn(interp: &Interpreter, args: Vec<Object>) -> Result<TclStatus, Object>;

const TCL_STUB_MAGIC: u32 = 0xFCA3BACB + size_of::<*const c_void>() as u32;

/// A wrapper for Tcl return status codes.
///
/// This is a simple wrapper around the expected return codes for Tcl
/// commands.  `Ok` and `Error` are the most common ones, but the others have
/// specific meanings under certain conditions (e.g., binding handlers in
/// Tk).  See the appropriate documentation for specific behavior.
#[repr(C)]
#[derive(Debug, PartialEq)]
pub enum TclStatus {
    Ok = 0,
    Error = 1,
    Return = 2,
    Break = 3,
    Continue = 4,
}

impl From<i32> for TclStatus {
    fn from(val: i32) -> Self {
        match val {
            0 => TclStatus::Ok,
            2 => TclStatus::Return,
            3 => TclStatus::Break,
            4 => TclStatus::Continue,
            _ => TclStatus::Error,
        }
    }
}

/// A wrapper for values passed to Tcl's [unload](https://www.tcl.tk/man/tcl/TclCmd/unload.html) function.
#[repr(isize)]
pub enum TclUnloadFlag {
    /// Indicates the interpreter is exiting but that the module's code is
    /// not being unmapped.
    DetachFromInterpreter = 1 << 0,
    /// Indicates the last interpreter is detaching and the module is about
    /// to be unmapped from the process.
    DetachFromProcess = 1 << 1,
}

#[allow(clippy::zero_ptr)] // Tcl sentinel: TCL_STATIC is literally a null pointer
const _TCL_STATIC: *const c_void = 0 as *const c_void;
#[allow(clippy::manual_dangling_ptr)] // Tcl sentinel: TCL_VOLATILE is literally the value 1, not a dangling pointer
const _TCL_VOLATILE: *const c_void = 1 as *const c_void;
const _TCL_DYNAMIC: *const c_void = 3 as *const c_void;

// BEGIN STUBS VTABLE - generated by stubParser.tcl, do not edit by hand
#[repr(C)]
#[allow(non_snake_case)]
#[derive(Debug)]
struct Stubs {
    magic: u32,
    hooks: *const c_void,
    Tcl_PkgProvideEx:
        extern "C" fn(*const Interpreter, *const c_char, *const c_char, *const c_void) -> c_int, // 0
    Tcl_PkgRequireEx: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *const c_char,
        c_int,
        *mut c_void,
    ) -> *const c_char, // 1
    Tcl_Panic: extern "C" fn(*const c_char, *const c_char), // 2
    Tcl_Alloc: extern "C" fn(usize) -> *mut c_void,         // 3
    Tcl_Free: extern "C" fn(*mut c_void),                   // 4
    Tcl_Realloc: extern "C" fn(*mut c_void, usize) -> *mut c_void, // 5
    Tcl_DbCkalloc: extern "C" fn(usize, *const c_char, c_int) -> *mut c_void, // 6
    Tcl_DbCkfree: extern "C" fn(*mut c_void, *const c_char, c_int), // 7
    Tcl_DbCkrealloc: extern "C" fn(*mut c_void, usize, *const c_char, c_int) -> *mut c_void, // 8
    Tcl_CreateFileHandler: extern "C" fn(c_int, c_int, *mut c_void, *mut c_void), // 9
    Tcl_DeleteFileHandler: extern "C" fn(c_int),            // 10
    Tcl_SetTimer: extern "C" fn(*const c_void),             // 11
    Tcl_Sleep: extern "C" fn(c_int),                        // 12
    Tcl_WaitForEvent: extern "C" fn(*const c_void) -> c_int, // 13
    Tcl_AppendAllObjTypes: extern "C" fn(*const Interpreter, *mut RawObject) -> c_int, // 14
    Tcl_AppendStringsToObj: extern "C" fn(*mut RawObject, *mut RawObject), // 15
    Tcl_AppendToObj: extern "C" fn(*mut RawObject, *const c_char, usize), // 16
    Tcl_ConcatObj: extern "C" fn(usize, *mut c_void) -> *mut RawObject, // 17
    Tcl_ConvertToType:
        extern "C" fn(*const Interpreter, *mut RawObject, *const ObjectType) -> c_int, // 18
    Tcl_DbDecrRefCount: extern "C" fn(*mut RawObject, *const c_char, c_int), // 19
    Tcl_DbIncrRefCount: extern "C" fn(*mut RawObject, *const c_char, c_int), // 20
    Tcl_DbIsShared: extern "C" fn(*mut RawObject, *const c_char, c_int) -> c_int, // 21
    _deprecated_22: *const c_void,                          // 22
    Tcl_DbNewByteArrayObj:
        extern "C" fn(*const c_void, usize, *const c_char, c_int) -> *mut RawObject, // 23
    Tcl_DbNewDoubleObj: extern "C" fn(c_double, *const c_char, c_int) -> *mut RawObject, // 24
    Tcl_DbNewListObj: extern "C" fn(usize, *mut c_void, *const c_char, c_int) -> *mut RawObject, // 25
    _deprecated_26: *const c_void, // 26
    Tcl_DbNewObj: extern "C" fn(*const c_char, c_int) -> *mut RawObject, // 27
    Tcl_DbNewStringObj: extern "C" fn(*const c_char, usize, *const c_char, c_int) -> *mut RawObject, // 28
    Tcl_DuplicateObj: extern "C" fn(*mut RawObject) -> *mut RawObject, // 29
    TclFreeObj: extern "C" fn(*mut RawObject),                         // 30
    Tcl_GetBoolean: extern "C" fn(*const Interpreter, *const c_char, *mut c_void) -> c_int, // 31
    Tcl_GetBooleanFromObj: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 32
    Tcl_GetByteArrayFromObj: extern "C" fn(*mut RawObject, *mut c_void) -> *mut c_void, // 33
    Tcl_GetDouble: extern "C" fn(*const Interpreter, *const c_char, *mut c_void) -> c_int, // 34
    Tcl_GetDoubleFromObj: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 35
    _deprecated_36: *const c_void, // 36
    Tcl_GetInt: extern "C" fn(*const Interpreter, *const c_char, *mut c_void) -> c_int, // 37
    Tcl_GetIntFromObj: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 38
    Tcl_GetLongFromObj: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 39
    Tcl_GetObjType: extern "C" fn(*const c_char) -> *const ObjectType, // 40
    TclGetStringFromObj: extern "C" fn(*mut RawObject, *mut c_void) -> *mut c_char, // 41
    Tcl_InvalidateStringRep: extern "C" fn(*mut RawObject),            // 42
    Tcl_ListObjAppendList:
        extern "C" fn(*const Interpreter, *mut RawObject, *mut RawObject) -> c_int, // 43
    Tcl_ListObjAppendElement:
        extern "C" fn(*const Interpreter, *mut RawObject, *mut RawObject) -> c_int, // 44
    TclListObjGetElements:
        extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void, *mut c_void) -> c_int, // 45
    Tcl_ListObjIndex:
        extern "C" fn(*const Interpreter, *mut RawObject, usize, *mut c_void) -> c_int, // 46
    TclListObjLength: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 47
    Tcl_ListObjReplace: extern "C" fn(
        *const Interpreter,
        *mut RawObject,
        usize,
        usize,
        usize,
        *mut c_void,
    ) -> c_int, // 48
    _deprecated_49: *const c_void,                                     // 49
    Tcl_NewByteArrayObj: extern "C" fn(*const c_void, usize) -> *mut RawObject, // 50
    Tcl_NewDoubleObj: extern "C" fn(c_double) -> *mut RawObject,       // 51
    _deprecated_52: *const c_void,                                     // 52
    Tcl_NewListObj: extern "C" fn(usize, *mut c_void) -> *mut RawObject, // 53
    _deprecated_54: *const c_void,                                     // 54
    Tcl_NewObj: extern "C" fn() -> *mut RawObject,                     // 55
    Tcl_NewStringObj: extern "C" fn(*const c_char, usize) -> *mut RawObject, // 56
    _deprecated_57: *const c_void,                                     // 57
    Tcl_SetByteArrayLength: extern "C" fn(*mut RawObject, usize) -> *mut c_void, // 58
    Tcl_SetByteArrayObj: extern "C" fn(*mut RawObject, *const c_void, usize), // 59
    Tcl_SetDoubleObj: extern "C" fn(*mut RawObject, c_double),         // 60
    _deprecated_61: *const c_void,                                     // 61
    Tcl_SetListObj: extern "C" fn(*mut RawObject, usize, *mut c_void), // 62
    _deprecated_63: *const c_void,                                     // 63
    Tcl_SetObjLength: extern "C" fn(*mut RawObject, usize),            // 64
    Tcl_SetStringObj: extern "C" fn(*mut RawObject, *const c_char, usize), // 65
    _deprecated_66: *const c_void,                                     // 66
    _deprecated_67: *const c_void,                                     // 67
    Tcl_AllowExceptions: extern "C" fn(*const Interpreter),            // 68
    Tcl_AppendElement: extern "C" fn(*const Interpreter, *const c_char), // 69
    Tcl_AppendResult: extern "C" fn(*const Interpreter, *const Interpreter), // 70
    Tcl_AsyncCreate: extern "C" fn(*mut c_void, *mut c_void) -> *mut c_void, // 71
    Tcl_AsyncDelete: extern "C" fn(*mut c_void),                       // 72
    Tcl_AsyncInvoke: extern "C" fn(*const Interpreter, c_int) -> c_int, // 73
    Tcl_AsyncMark: extern "C" fn(*mut c_void),                         // 74
    Tcl_AsyncReady: extern "C" fn() -> c_int,                          // 75
    _deprecated_76: *const c_void,                                     // 76
    _deprecated_77: *const c_void,                                     // 77
    Tcl_BadChannelOption: extern "C" fn(*const Interpreter, *const c_char, *const c_char) -> c_int, // 78
    Tcl_CallWhenDeleted: extern "C" fn(*const Interpreter, *mut c_void, *mut c_void), // 79
    Tcl_CancelIdleCall: extern "C" fn(*mut c_void, *mut c_void),                      // 80
    Tcl_Close: extern "C" fn(*const Interpreter, *mut c_void) -> c_int,               // 81
    Tcl_CommandComplete: extern "C" fn(*const c_char) -> c_int,                       // 82
    Tcl_Concat: extern "C" fn(usize, *const c_void) -> *mut c_char,                   // 83
    Tcl_ConvertElement: extern "C" fn(*const c_char, *mut c_char, c_int) -> usize,    // 84
    Tcl_ConvertCountedElement: extern "C" fn(*const c_char, usize, *mut c_char, c_int) -> usize, // 85
    Tcl_CreateAlias: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *const Interpreter,
        *const c_char,
        usize,
        *const c_void,
    ) -> c_int, // 86
    Tcl_CreateAliasObj: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *const Interpreter,
        *const c_char,
        usize,
        *mut c_void,
    ) -> c_int, // 87
    Tcl_CreateChannel:
        extern "C" fn(*const c_void, *const c_char, *mut c_void, c_int) -> *mut c_void, // 88
    Tcl_CreateChannelHandler: extern "C" fn(*mut c_void, c_int, *mut c_void, *mut c_void), // 89
    Tcl_CreateCloseHandler: extern "C" fn(*mut c_void, *mut c_void, *mut c_void),          // 90
    Tcl_CreateCommand: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *mut c_void,
        *mut c_void,
        *mut c_void,
    ) -> *mut c_void, // 91
    Tcl_CreateEventSource: extern "C" fn(*mut c_void, *mut c_void, *mut c_void),           // 92
    Tcl_CreateExitHandler: extern "C" fn(*mut c_void, *mut c_void),                        // 93
    Tcl_CreateInterp: extern "C" fn() -> *const Interpreter,                               // 94
    _deprecated_95: *const c_void,                                                         // 95
    Tcl_CreateObjCommand: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *mut c_void,
        *mut c_void,
        *mut c_void,
    ) -> *mut c_void, // 96
    Tcl_CreateChild: extern "C" fn(*const Interpreter, *const c_char, c_int) -> *const Interpreter, // 97
    Tcl_CreateTimerHandler: extern "C" fn(c_int, *mut c_void, *mut c_void) -> *mut c_void, // 98
    Tcl_CreateTrace:
        extern "C" fn(*const Interpreter, usize, *mut c_void, *mut c_void) -> *mut c_void, // 99
    Tcl_DeleteAssocData: extern "C" fn(*const Interpreter, *const c_char),                 // 100
    Tcl_DeleteChannelHandler: extern "C" fn(*mut c_void, *mut c_void, *mut c_void),        // 101
    Tcl_DeleteCloseHandler: extern "C" fn(*mut c_void, *mut c_void, *mut c_void),          // 102
    Tcl_DeleteCommand: extern "C" fn(*const Interpreter, *const c_char) -> c_int,          // 103
    Tcl_DeleteCommandFromToken: extern "C" fn(*const Interpreter, *mut c_void) -> c_int,   // 104
    Tcl_DeleteEvents: extern "C" fn(*mut c_void, *mut c_void),                             // 105
    Tcl_DeleteEventSource: extern "C" fn(*mut c_void, *mut c_void, *mut c_void),           // 106
    Tcl_DeleteExitHandler: extern "C" fn(*mut c_void, *mut c_void),                        // 107
    Tcl_DeleteHashEntry: extern "C" fn(*mut c_void),                                       // 108
    Tcl_DeleteHashTable: extern "C" fn(*mut c_void),                                       // 109
    Tcl_DeleteInterp: extern "C" fn(*const Interpreter),                                   // 110
    Tcl_DetachPids: extern "C" fn(usize, *mut c_void),                                     // 111
    Tcl_DeleteTimerHandler: extern "C" fn(*mut c_void),                                    // 112
    Tcl_DeleteTrace: extern "C" fn(*const Interpreter, *mut c_void),                       // 113
    Tcl_DontCallWhenDeleted: extern "C" fn(*const Interpreter, *mut c_void, *mut c_void),  // 114
    Tcl_DoOneEvent: extern "C" fn(c_int) -> c_int,                                         // 115
    Tcl_DoWhenIdle: extern "C" fn(*mut c_void, *mut c_void),                               // 116
    Tcl_DStringAppend: extern "C" fn(*mut c_void, *const c_char, usize) -> *mut c_char,    // 117
    Tcl_DStringAppendElement: extern "C" fn(*mut c_void, *const c_char) -> *mut c_char,    // 118
    Tcl_DStringEndSublist: extern "C" fn(*mut c_void),                                     // 119
    Tcl_DStringFree: extern "C" fn(*mut c_void),                                           // 120
    Tcl_DStringGetResult: extern "C" fn(*const Interpreter, *mut c_void),                  // 121
    Tcl_DStringInit: extern "C" fn(*mut c_void),                                           // 122
    Tcl_DStringResult: extern "C" fn(*const Interpreter, *mut c_void),                     // 123
    Tcl_DStringSetLength: extern "C" fn(*mut c_void, usize),                               // 124
    Tcl_DStringStartSublist: extern "C" fn(*mut c_void),                                   // 125
    Tcl_Eof: extern "C" fn(*mut c_void) -> c_int,                                          // 126
    Tcl_ErrnoId: extern "C" fn() -> *const c_char,                                         // 127
    Tcl_ErrnoMsg: extern "C" fn(c_int) -> *const c_char,                                   // 128
    _deprecated_129: *const c_void,                                                        // 129
    Tcl_EvalFile: extern "C" fn(*const Interpreter, *const c_char) -> c_int,               // 130
    _deprecated_131: *const c_void,                                                        // 131
    Tcl_EventuallyFree: extern "C" fn(*mut c_void, *mut c_void),                           // 132
    Tcl_Exit: extern "C" fn(c_int),                                                        // 133
    Tcl_ExposeCommand: extern "C" fn(*const Interpreter, *const c_char, *const c_char) -> c_int, // 134
    Tcl_ExprBoolean: extern "C" fn(*const Interpreter, *const c_char, *mut c_void) -> c_int, // 135
    Tcl_ExprBooleanObj: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 136
    Tcl_ExprDouble: extern "C" fn(*const Interpreter, *const c_char, *mut c_void) -> c_int, // 137
    Tcl_ExprDoubleObj: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 138
    Tcl_ExprLong: extern "C" fn(*const Interpreter, *const c_char, *mut c_void) -> c_int, // 139
    Tcl_ExprLongObj: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 140
    Tcl_ExprObj: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 141
    Tcl_ExprString: extern "C" fn(*const Interpreter, *const c_char) -> c_int,            // 142
    Tcl_Finalize: extern "C" fn(),                                                        // 143
    _deprecated_144: *const c_void,                                                       // 144
    Tcl_FirstHashEntry: extern "C" fn(*mut c_void, *mut c_void) -> *mut c_void,           // 145
    Tcl_Flush: extern "C" fn(*mut c_void) -> c_int,                                       // 146
    _deprecated_147: *const c_void,                                                       // 147
    _deprecated_148: *const c_void,                                                       // 148
    TclGetAliasObj: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *mut c_void,
        *const c_void,
        *mut c_void,
        *mut c_void,
    ) -> c_int, // 149
    Tcl_GetAssocData: extern "C" fn(*const Interpreter, *const c_char, *mut c_void) -> *mut c_void, // 150
    Tcl_GetChannel: extern "C" fn(*const Interpreter, *const c_char, *mut c_void) -> *mut c_void, // 151
    Tcl_GetChannelBufferSize: extern "C" fn(*mut c_void) -> usize, // 152
    Tcl_GetChannelHandle: extern "C" fn(*mut c_void, c_int, *mut c_void) -> c_int, // 153
    Tcl_GetChannelInstanceData: extern "C" fn(*mut c_void) -> *mut c_void, // 154
    Tcl_GetChannelMode: extern "C" fn(*mut c_void) -> c_int,       // 155
    Tcl_GetChannelName: extern "C" fn(*mut c_void) -> *const c_char, // 156
    Tcl_GetChannelOption:
        extern "C" fn(*const Interpreter, *mut c_void, *const c_char, *mut c_void) -> c_int, // 157
    Tcl_GetChannelType: extern "C" fn(*mut c_void) -> *const c_void, // 158
    Tcl_GetCommandInfo: extern "C" fn(*const Interpreter, *const c_char, *mut c_void) -> c_int, // 159
    Tcl_GetCommandName: extern "C" fn(*const Interpreter, *mut c_void) -> *const c_char, // 160
    Tcl_GetErrno: extern "C" fn() -> c_int,                                              // 161
    Tcl_GetHostName: extern "C" fn() -> *const c_char,                                   // 162
    Tcl_GetInterpPath: extern "C" fn(*const Interpreter, *const Interpreter) -> c_int,   // 163
    Tcl_GetParent: extern "C" fn(*const Interpreter) -> *const Interpreter,              // 164
    Tcl_GetNameOfExecutable: extern "C" fn() -> *const c_char,                           // 165
    Tcl_GetObjResult: extern "C" fn(*const Interpreter) -> *mut RawObject,               // 166
    Tcl_GetOpenFile:
        extern "C" fn(*const Interpreter, *const c_char, c_int, c_int, *mut c_void) -> c_int, // 167
    Tcl_GetPathType: extern "C" fn(*const c_char) -> *mut c_void,                        // 168
    Tcl_Gets: extern "C" fn(*mut c_void, *mut c_void) -> usize,                          // 169
    Tcl_GetsObj: extern "C" fn(*mut c_void, *mut RawObject) -> usize,                    // 170
    Tcl_GetServiceMode: extern "C" fn() -> c_int,                                        // 171
    Tcl_GetChild: extern "C" fn(*const Interpreter, *const c_char) -> *const Interpreter, // 172
    Tcl_GetStdChannel: extern "C" fn(c_int) -> *mut c_void,                              // 173
    _deprecated_174: *const c_void,                                                      // 174
    _deprecated_175: *const c_void,                                                      // 175
    Tcl_GetVar2:
        extern "C" fn(*const Interpreter, *const c_char, *const c_char, c_int) -> *const c_char, // 176
    _deprecated_177: *const c_void, // 177
    _deprecated_178: *const c_void, // 178
    Tcl_HideCommand: extern "C" fn(*const Interpreter, *const c_char, *const c_char) -> c_int, // 179
    Tcl_Init: extern "C" fn(*const Interpreter) -> c_int, // 180
    Tcl_InitHashTable: extern "C" fn(*mut c_void, c_int), // 181
    Tcl_InputBlocked: extern "C" fn(*mut c_void) -> c_int, // 182
    Tcl_InputBuffered: extern "C" fn(*mut c_void) -> c_int, // 183
    Tcl_InterpDeleted: extern "C" fn(*const Interpreter) -> c_int, // 184
    Tcl_IsSafe: extern "C" fn(*const Interpreter) -> c_int, // 185
    Tcl_JoinPath: extern "C" fn(usize, *const c_void, *mut c_void) -> *mut c_char, // 186
    Tcl_LinkVar: extern "C" fn(*const Interpreter, *const c_char, *mut c_void, c_int) -> c_int, // 187
    _deprecated_188: *const c_void, // 188
    Tcl_MakeFileChannel: extern "C" fn(*mut c_void, c_int) -> *mut c_void, // 189
    _deprecated_190: *const c_void, // 190
    Tcl_MakeTcpClientChannel: extern "C" fn(*mut c_void) -> *mut c_void, // 191
    Tcl_Merge: extern "C" fn(usize, *const c_void) -> *mut c_char, // 192
    Tcl_NextHashEntry: extern "C" fn(*mut c_void) -> *mut c_void, // 193
    Tcl_NotifyChannel: extern "C" fn(*mut c_void, c_int), // 194
    Tcl_ObjGetVar2:
        extern "C" fn(*const Interpreter, *mut RawObject, *mut RawObject, c_int) -> *mut RawObject, // 195
    Tcl_ObjSetVar2: extern "C" fn(
        *const Interpreter,
        *mut RawObject,
        *mut RawObject,
        *mut RawObject,
        c_int,
    ) -> *mut RawObject, // 196
    Tcl_OpenCommandChannel:
        extern "C" fn(*const Interpreter, usize, *const c_void, c_int) -> *mut c_void, // 197
    Tcl_OpenFileChannel:
        extern "C" fn(*const Interpreter, *const c_char, *const c_char, c_int) -> *mut c_void, // 198
    Tcl_OpenTcpClient: extern "C" fn(
        *const Interpreter,
        c_int,
        *const c_char,
        *const c_char,
        c_int,
        c_int,
    ) -> *mut c_void, // 199
    Tcl_OpenTcpServer: extern "C" fn(
        *const Interpreter,
        c_int,
        *const c_char,
        *mut c_void,
        *mut c_void,
    ) -> *mut c_void, // 200
    Tcl_Preserve: extern "C" fn(*mut c_void), // 201
    Tcl_PrintDouble: extern "C" fn(*const Interpreter, c_double, *mut c_char), // 202
    Tcl_PutEnv: extern "C" fn(*const c_char) -> c_int, // 203
    Tcl_PosixError: extern "C" fn(*const Interpreter) -> *const c_char, // 204
    Tcl_QueueEvent: extern "C" fn(*mut c_void, c_int), // 205
    Tcl_Read: extern "C" fn(*mut c_void, *mut c_char, usize) -> usize, // 206
    Tcl_ReapDetachedProcs: extern "C" fn(),   // 207
    Tcl_RecordAndEval: extern "C" fn(*const Interpreter, *const c_char, c_int) -> c_int, // 208
    Tcl_RecordAndEvalObj: extern "C" fn(*const Interpreter, *mut RawObject, c_int) -> c_int, // 209
    Tcl_RegisterChannel: extern "C" fn(*const Interpreter, *mut c_void), // 210
    Tcl_RegisterObjType: extern "C" fn(*const ObjectType), // 211
    Tcl_RegExpCompile: extern "C" fn(*const Interpreter, *const c_char) -> *mut c_void, // 212
    Tcl_RegExpExec:
        extern "C" fn(*const Interpreter, *mut c_void, *const c_char, *const c_char) -> c_int, // 213
    Tcl_RegExpMatch: extern "C" fn(*const Interpreter, *const c_char, *const c_char) -> c_int, // 214
    Tcl_RegExpRange: extern "C" fn(*mut c_void, usize, *const c_void, *const c_void), // 215
    Tcl_Release: extern "C" fn(*mut c_void),                                          // 216
    Tcl_ResetResult: extern "C" fn(*const Interpreter),                               // 217
    Tcl_ScanElement: extern "C" fn(*const c_char, *mut c_void) -> usize,              // 218
    Tcl_ScanCountedElement: extern "C" fn(*const c_char, usize, *mut c_void) -> usize, // 219
    _deprecated_220: *const c_void,                                                   // 220
    Tcl_ServiceAll: extern "C" fn() -> c_int,                                         // 221
    Tcl_ServiceEvent: extern "C" fn(c_int) -> c_int,                                  // 222
    Tcl_SetAssocData: extern "C" fn(*const Interpreter, *const c_char, *mut c_void, *mut c_void), // 223
    Tcl_SetChannelBufferSize: extern "C" fn(*mut c_void, usize), // 224
    Tcl_SetChannelOption:
        extern "C" fn(*const Interpreter, *mut c_void, *const c_char, *const c_char) -> c_int, // 225
    Tcl_SetCommandInfo: extern "C" fn(*const Interpreter, *const c_char, *const c_void) -> c_int, // 226
    Tcl_SetErrno: extern "C" fn(c_int), // 227
    Tcl_SetErrorCode: extern "C" fn(*const Interpreter, *const Interpreter), // 228
    Tcl_SetMaxBlockTime: extern "C" fn(*const c_void), // 229
    _deprecated_230: *const c_void,     // 230
    Tcl_SetRecursionLimit: extern "C" fn(*const Interpreter, usize) -> usize, // 231
    _deprecated_232: *const c_void,     // 232
    Tcl_SetServiceMode: extern "C" fn(c_int) -> c_int, // 233
    Tcl_SetObjErrorCode: extern "C" fn(*const Interpreter, *mut RawObject), // 234
    Tcl_SetObjResult: extern "C" fn(*const Interpreter, *mut RawObject), // 235
    Tcl_SetStdChannel: extern "C" fn(*mut c_void, c_int), // 236
    _deprecated_237: *const c_void,     // 237
    Tcl_SetVar2: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *const c_char,
        *const c_char,
        c_int,
    ) -> *const c_char, // 238
    Tcl_SignalId: extern "C" fn(c_int) -> *const c_char, // 239
    Tcl_SignalMsg: extern "C" fn(c_int) -> *const c_char, // 240
    Tcl_SourceRCFile: extern "C" fn(*const Interpreter), // 241
    TclSplitList:
        extern "C" fn(*const Interpreter, *const c_char, *mut c_void, *const c_void) -> c_int, // 242
    TclSplitPath: extern "C" fn(*const c_char, *mut c_void, *const c_void), // 243
    _deprecated_244: *const c_void,                                         // 244
    _deprecated_245: *const c_void,                                         // 245
    _deprecated_246: *const c_void,                                         // 246
    _deprecated_247: *const c_void,                                         // 247
    Tcl_TraceVar2: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *const c_char,
        c_int,
        *mut c_void,
        *mut c_void,
    ) -> c_int, // 248
    Tcl_TranslateFileName:
        extern "C" fn(*const Interpreter, *const c_char, *mut c_void) -> *mut c_char, // 249
    Tcl_Ungets: extern "C" fn(*mut c_void, *const c_char, usize, c_int) -> usize, // 250
    Tcl_UnlinkVar: extern "C" fn(*const Interpreter, *const c_char),        // 251
    Tcl_UnregisterChannel: extern "C" fn(*const Interpreter, *mut c_void) -> c_int, // 252
    _deprecated_253: *const c_void,                                         // 253
    Tcl_UnsetVar2: extern "C" fn(*const Interpreter, *const c_char, *const c_char, c_int) -> c_int, // 254
    _deprecated_255: *const c_void, // 255
    Tcl_UntraceVar2: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *const c_char,
        c_int,
        *mut c_void,
        *mut c_void,
    ), // 256
    Tcl_UpdateLinkedVar: extern "C" fn(*const Interpreter, *const c_char), // 257
    _deprecated_258: *const c_void, // 258
    Tcl_UpVar2: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *const c_char,
        *const c_char,
        *const c_char,
        c_int,
    ) -> c_int, // 259
    Tcl_VarEval: extern "C" fn(*const Interpreter, *const Interpreter) -> c_int, // 260
    _deprecated_261: *const c_void, // 261
    Tcl_VarTraceInfo2: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *const c_char,
        c_int,
        *mut c_void,
        *mut c_void,
    ) -> *mut c_void, // 262
    Tcl_Write: extern "C" fn(*mut c_void, *const c_char, usize) -> usize, // 263
    Tcl_WrongNumArgs: extern "C" fn(*const Interpreter, usize, *mut c_void, *const c_char), // 264
    Tcl_DumpActiveMemory: extern "C" fn(*const c_char) -> c_int, // 265
    Tcl_ValidateAllMemory: extern "C" fn(*const c_char, c_int), // 266
    _deprecated_267: *const c_void, // 267
    _deprecated_268: *const c_void, // 268
    Tcl_HashStats: extern "C" fn(*mut c_void) -> *mut c_char, // 269
    Tcl_ParseVar: extern "C" fn(*const Interpreter, *const c_char, *const c_void) -> *const c_char, // 270
    _deprecated_271: *const c_void, // 271
    Tcl_PkgPresentEx: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *const c_char,
        c_int,
        *mut c_void,
    ) -> *const c_char, // 272
    _deprecated_273: *const c_void, // 273
    _deprecated_274: *const c_void, // 274
    _deprecated_275: *const c_void, // 275
    _deprecated_276: *const c_void, // 276
    Tcl_WaitPid: extern "C" fn(*mut c_void, *mut c_void, c_int) -> *mut c_void, // 277
    _deprecated_278: *const c_void, // 278
    Tcl_GetVersion: extern "C" fn(*mut c_void, *mut c_void, *mut c_void, *mut c_void), // 279
    Tcl_InitMemory: extern "C" fn(*const Interpreter), // 280
    Tcl_StackChannel: extern "C" fn(
        *const Interpreter,
        *const c_void,
        *mut c_void,
        c_int,
        *mut c_void,
    ) -> *mut c_void, // 281
    Tcl_UnstackChannel: extern "C" fn(*const Interpreter, *mut c_void) -> c_int, // 282
    Tcl_GetStackedChannel: extern "C" fn(*mut c_void) -> *mut c_void, // 283
    Tcl_SetMainLoop: extern "C" fn(*mut c_void), // 284
    Tcl_GetAliasObj: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *mut c_void,
        *const c_void,
        *mut c_void,
        *mut c_void,
    ) -> c_int, // 285
    Tcl_AppendObjToObj: extern "C" fn(*mut RawObject, *mut RawObject), // 286
    Tcl_CreateEncoding: extern "C" fn(*const c_void) -> *mut c_void, // 287
    Tcl_CreateThreadExitHandler: extern "C" fn(*mut c_void, *mut c_void), // 288
    Tcl_DeleteThreadExitHandler: extern "C" fn(*mut c_void, *mut c_void), // 289
    _deprecated_290: *const c_void, // 290
    Tcl_EvalEx: extern "C" fn(*const Interpreter, *const c_char, usize, c_int) -> c_int, // 291
    Tcl_EvalObjv: extern "C" fn(*const Interpreter, usize, *mut c_void, c_int) -> c_int, // 292
    Tcl_EvalObjEx: extern "C" fn(*const Interpreter, *mut RawObject, c_int) -> c_int, // 293
    Tcl_ExitThread: extern "C" fn(c_int), // 294
    Tcl_ExternalToUtf: extern "C" fn(
        *const Interpreter,
        *mut c_void,
        *const c_char,
        usize,
        c_int,
        *mut c_void,
        *mut c_char,
        usize,
        *mut c_void,
        *mut c_void,
        *mut c_void,
    ) -> c_int, // 295
    Tcl_ExternalToUtfDString:
        extern "C" fn(*mut c_void, *const c_char, usize, *mut c_void) -> *mut c_char, // 296
    Tcl_FinalizeThread: extern "C" fn(), // 297
    Tcl_FinalizeNotifier: extern "C" fn(*mut c_void), // 298
    Tcl_FreeEncoding: extern "C" fn(*mut c_void), // 299
    Tcl_GetCurrentThread: extern "C" fn() -> *mut c_void, // 300
    Tcl_GetEncoding: extern "C" fn(*const Interpreter, *const c_char) -> *mut c_void, // 301
    Tcl_GetEncodingName: extern "C" fn(*mut c_void) -> *const c_char, // 302
    Tcl_GetEncodingNames: extern "C" fn(*const Interpreter), // 303
    Tcl_GetIndexFromObjStruct: extern "C" fn(
        *const Interpreter,
        *mut RawObject,
        *const c_void,
        usize,
        *const c_char,
        c_int,
        *mut c_void,
    ) -> c_int, // 304
    Tcl_GetThreadData: extern "C" fn(*mut c_void, usize) -> *mut c_void, // 305
    Tcl_GetVar2Ex:
        extern "C" fn(*const Interpreter, *const c_char, *const c_char, c_int) -> *mut RawObject, // 306
    Tcl_InitNotifier: extern "C" fn() -> *mut c_void, // 307
    Tcl_MutexLock: extern "C" fn(*mut c_void),        // 308
    Tcl_MutexUnlock: extern "C" fn(*mut c_void),      // 309
    Tcl_ConditionNotify: extern "C" fn(*mut c_void),  // 310
    Tcl_ConditionWait: extern "C" fn(*mut c_void, *mut c_void, *const c_void), // 311
    TclNumUtfChars: extern "C" fn(*const c_char, usize) -> usize, // 312
    Tcl_ReadChars: extern "C" fn(*mut c_void, *mut RawObject, usize, c_int) -> usize, // 313
    _deprecated_314: *const c_void,                   // 314
    _deprecated_315: *const c_void,                   // 315
    Tcl_SetSystemEncoding: extern "C" fn(*const Interpreter, *const c_char) -> c_int, // 316
    Tcl_SetVar2Ex: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *const c_char,
        *mut RawObject,
        c_int,
    ) -> *mut RawObject, // 317
    Tcl_ThreadAlert: extern "C" fn(*mut c_void),      // 318
    Tcl_ThreadQueueEvent: extern "C" fn(*mut c_void, *mut c_void, c_int), // 319
    Tcl_UniCharAtIndex: extern "C" fn(*const c_char, usize) -> c_int, // 320
    Tcl_UniCharToLower: extern "C" fn(c_int) -> c_int, // 321
    Tcl_UniCharToTitle: extern "C" fn(c_int) -> c_int, // 322
    Tcl_UniCharToUpper: extern "C" fn(c_int) -> c_int, // 323
    Tcl_UniCharToUtf: extern "C" fn(c_int, *mut c_char) -> usize, // 324
    TclUtfAtIndex: extern "C" fn(*const c_char, usize) -> *const c_char, // 325
    TclUtfCharComplete: extern "C" fn(*const c_char, usize) -> c_int, // 326
    Tcl_UtfBackslash: extern "C" fn(*const c_char, *mut c_void, *mut c_char) -> usize, // 327
    Tcl_UtfFindFirst: extern "C" fn(*const c_char, c_int) -> *const c_char, // 328
    Tcl_UtfFindLast: extern "C" fn(*const c_char, c_int) -> *const c_char, // 329
    TclUtfNext: extern "C" fn(*const c_char) -> *const c_char, // 330
    TclUtfPrev: extern "C" fn(*const c_char, *const c_char) -> *const c_char, // 331
    Tcl_UtfToExternal: extern "C" fn(
        *const Interpreter,
        *mut c_void,
        *const c_char,
        usize,
        c_int,
        *mut c_void,
        *mut c_char,
        usize,
        *mut c_void,
        *mut c_void,
        *mut c_void,
    ) -> c_int, // 332
    Tcl_UtfToExternalDString:
        extern "C" fn(*mut c_void, *const c_char, usize, *mut c_void) -> *mut c_char, // 333
    Tcl_UtfToLower: extern "C" fn(*mut c_char) -> usize, // 334
    Tcl_UtfToTitle: extern "C" fn(*mut c_char) -> usize, // 335
    Tcl_UtfToChar16: extern "C" fn(*const c_char, *mut c_void) -> usize, // 336
    Tcl_UtfToUpper: extern "C" fn(*mut c_char) -> usize, // 337
    Tcl_WriteChars: extern "C" fn(*mut c_void, *const c_char, usize) -> usize, // 338
    Tcl_WriteObj: extern "C" fn(*mut c_void, *mut RawObject) -> usize, // 339
    Tcl_GetString: extern "C" fn(*mut RawObject) -> *mut c_char, // 340
    _deprecated_341: *const c_void,                   // 341
    _deprecated_342: *const c_void,                   // 342
    Tcl_AlertNotifier: extern "C" fn(*mut c_void),    // 343
    Tcl_ServiceModeHook: extern "C" fn(c_int),        // 344
    Tcl_UniCharIsAlnum: extern "C" fn(c_int) -> c_int, // 345
    Tcl_UniCharIsAlpha: extern "C" fn(c_int) -> c_int, // 346
    Tcl_UniCharIsDigit: extern "C" fn(c_int) -> c_int, // 347
    Tcl_UniCharIsLower: extern "C" fn(c_int) -> c_int, // 348
    Tcl_UniCharIsSpace: extern "C" fn(c_int) -> c_int, // 349
    Tcl_UniCharIsUpper: extern "C" fn(c_int) -> c_int, // 350
    Tcl_UniCharIsWordChar: extern "C" fn(c_int) -> c_int, // 351
    Tcl_Char16Len: extern "C" fn(*const c_void) -> usize, // 352
    _deprecated_353: *const c_void,                   // 353
    Tcl_Char16ToUtfDString: extern "C" fn(*const c_void, usize, *mut c_void) -> *mut c_char, // 354
    Tcl_UtfToChar16DString: extern "C" fn(*const c_char, usize, *mut c_void) -> *mut c_void, // 355
    Tcl_GetRegExpFromObj: extern "C" fn(*const Interpreter, *mut RawObject, c_int) -> *mut c_void, // 356
    _deprecated_357: *const c_void,            // 357
    Tcl_FreeParse: extern "C" fn(*mut c_void), // 358
    Tcl_LogCommandInfo: extern "C" fn(*const Interpreter, *const c_char, *const c_char, usize), // 359
    Tcl_ParseBraces: extern "C" fn(
        *const Interpreter,
        *const c_char,
        usize,
        *mut c_void,
        c_int,
        *const c_void,
    ) -> c_int, // 360
    Tcl_ParseCommand:
        extern "C" fn(*const Interpreter, *const c_char, usize, c_int, *mut c_void) -> c_int, // 361
    Tcl_ParseExpr: extern "C" fn(*const Interpreter, *const c_char, usize, *mut c_void) -> c_int, // 362
    Tcl_ParseQuotedString: extern "C" fn(
        *const Interpreter,
        *const c_char,
        usize,
        *mut c_void,
        c_int,
        *const c_void,
    ) -> c_int, // 363
    Tcl_ParseVarName:
        extern "C" fn(*const Interpreter, *const c_char, usize, *mut c_void, c_int) -> c_int, // 364
    Tcl_GetCwd: extern "C" fn(*const Interpreter, *mut c_void) -> *mut c_char, // 365
    Tcl_Chdir: extern "C" fn(*const c_char) -> c_int,                          // 366
    Tcl_Access: extern "C" fn(*const c_char, c_int) -> c_int,                  // 367
    Tcl_Stat: extern "C" fn(*const c_char, *mut c_void) -> c_int,              // 368
    TclUtfNcmp: extern "C" fn(*const c_char, *const c_char, *mut c_void) -> c_int, // 369
    TclUtfNcasecmp: extern "C" fn(*const c_char, *const c_char, *mut c_void) -> c_int, // 370
    Tcl_StringCaseMatch: extern "C" fn(*const c_char, *const c_char, c_int) -> c_int, // 371
    Tcl_UniCharIsControl: extern "C" fn(c_int) -> c_int,                       // 372
    Tcl_UniCharIsGraph: extern "C" fn(c_int) -> c_int,                         // 373
    Tcl_UniCharIsPrint: extern "C" fn(c_int) -> c_int,                         // 374
    Tcl_UniCharIsPunct: extern "C" fn(c_int) -> c_int,                         // 375
    Tcl_RegExpExecObj: extern "C" fn(
        *const Interpreter,
        *mut c_void,
        *mut RawObject,
        usize,
        usize,
        c_int,
    ) -> c_int, // 376
    Tcl_RegExpGetInfo: extern "C" fn(*mut c_void, *mut c_void),                // 377
    Tcl_NewUnicodeObj: extern "C" fn(*const c_void, usize) -> *mut RawObject,  // 378
    Tcl_SetUnicodeObj: extern "C" fn(*mut RawObject, *const c_void, usize),    // 379
    TclGetCharLength: extern "C" fn(*mut RawObject) -> usize,                  // 380
    TclGetUniChar: extern "C" fn(*mut RawObject, usize) -> c_int,              // 381
    _deprecated_382: *const c_void,                                            // 382
    TclGetRange: extern "C" fn(*mut RawObject, usize, usize) -> *mut RawObject, // 383
    Tcl_AppendUnicodeToObj: extern "C" fn(*mut RawObject, *const c_void, usize), // 384
    Tcl_RegExpMatchObj: extern "C" fn(*const Interpreter, *mut RawObject, *mut RawObject) -> c_int, // 385
    Tcl_SetNotifier: extern "C" fn(*const c_void), // 386
    Tcl_GetAllocMutex: extern "C" fn() -> *mut c_void, // 387
    Tcl_GetChannelNames: extern "C" fn(*const Interpreter) -> c_int, // 388
    Tcl_GetChannelNamesEx: extern "C" fn(*const Interpreter, *const c_char) -> c_int, // 389
    Tcl_ProcObjCmd: extern "C" fn(*mut c_void, *const Interpreter, usize, *mut c_void) -> c_int, // 390
    Tcl_ConditionFinalize: extern "C" fn(*mut c_void), // 391
    Tcl_MutexFinalize: extern "C" fn(*mut c_void),     // 392
    Tcl_CreateThread: extern "C" fn(*mut c_void, *mut c_void, *mut c_void, usize, c_int) -> c_int, // 393
    Tcl_ReadRaw: extern "C" fn(*mut c_void, *mut c_char, usize) -> usize, // 394
    Tcl_WriteRaw: extern "C" fn(*mut c_void, *const c_char, usize) -> usize, // 395
    Tcl_GetTopChannel: extern "C" fn(*mut c_void) -> *mut c_void,         // 396
    Tcl_ChannelBuffered: extern "C" fn(*mut c_void) -> c_int,             // 397
    Tcl_ChannelName: extern "C" fn(*const c_void) -> *const c_char,       // 398
    Tcl_ChannelVersion: extern "C" fn(*const c_void) -> *mut c_void,      // 399
    Tcl_ChannelBlockModeProc: extern "C" fn(*const c_void) -> *mut c_void, // 400
    _deprecated_401: *const c_void,                                       // 401
    Tcl_ChannelClose2Proc: extern "C" fn(*const c_void) -> *mut c_void,   // 402
    Tcl_ChannelInputProc: extern "C" fn(*const c_void) -> *mut c_void,    // 403
    Tcl_ChannelOutputProc: extern "C" fn(*const c_void) -> *mut c_void,   // 404
    _deprecated_405: *const c_void,                                       // 405
    Tcl_ChannelSetOptionProc: extern "C" fn(*const c_void) -> *mut c_void, // 406
    Tcl_ChannelGetOptionProc: extern "C" fn(*const c_void) -> *mut c_void, // 407
    Tcl_ChannelWatchProc: extern "C" fn(*const c_void) -> *mut c_void,    // 408
    Tcl_ChannelGetHandleProc: extern "C" fn(*const c_void) -> *mut c_void, // 409
    Tcl_ChannelFlushProc: extern "C" fn(*const c_void) -> *mut c_void,    // 410
    Tcl_ChannelHandlerProc: extern "C" fn(*const c_void) -> *mut c_void,  // 411
    Tcl_JoinThread: extern "C" fn(*mut c_void, *mut c_void) -> c_int,     // 412
    Tcl_IsChannelShared: extern "C" fn(*mut c_void) -> c_int,             // 413
    Tcl_IsChannelRegistered: extern "C" fn(*const Interpreter, *mut c_void) -> c_int, // 414
    Tcl_CutChannel: extern "C" fn(*mut c_void),                           // 415
    Tcl_SpliceChannel: extern "C" fn(*mut c_void),                        // 416
    Tcl_ClearChannelHandlers: extern "C" fn(*mut c_void),                 // 417
    Tcl_IsChannelExisting: extern "C" fn(*const c_char) -> c_int,         // 418
    _deprecated_419: *const c_void,                                       // 419
    _deprecated_420: *const c_void,                                       // 420
    _deprecated_421: *const c_void,                                       // 421
    Tcl_CreateHashEntry: extern "C" fn(*mut c_void, *const c_void, *mut c_void) -> *mut c_void, // 422
    Tcl_InitCustomHashTable: extern "C" fn(*mut c_void, c_int, *const c_void), // 423
    Tcl_InitObjHashTable: extern "C" fn(*mut c_void),                          // 424
    Tcl_CommandTraceInfo: extern "C" fn(
        *const Interpreter,
        *const c_char,
        c_int,
        *mut c_void,
        *mut c_void,
    ) -> *mut c_void, // 425
    Tcl_TraceCommand:
        extern "C" fn(*const Interpreter, *const c_char, c_int, *mut c_void, *mut c_void) -> c_int, // 426
    Tcl_UntraceCommand:
        extern "C" fn(*const Interpreter, *const c_char, c_int, *mut c_void, *mut c_void), // 427
    Tcl_AttemptAlloc: extern "C" fn(usize) -> *mut c_void, // 428
    Tcl_AttemptDbCkalloc: extern "C" fn(usize, *const c_char, c_int) -> *mut c_void, // 429
    Tcl_AttemptRealloc: extern "C" fn(*mut c_void, usize) -> *mut c_void, // 430
    Tcl_AttemptDbCkrealloc: extern "C" fn(*mut c_void, usize, *const c_char, c_int) -> *mut c_void, // 431
    Tcl_AttemptSetObjLength: extern "C" fn(*mut RawObject, usize) -> c_int, // 432
    Tcl_GetChannelThread: extern "C" fn(*mut c_void) -> *mut c_void,        // 433
    TclGetUnicodeFromObj: extern "C" fn(*mut RawObject, *mut c_void) -> *mut c_void, // 434
    _deprecated_435: *const c_void,                                         // 435
    _deprecated_436: *const c_void,                                         // 436
    Tcl_SubstObj: extern "C" fn(*const Interpreter, *mut RawObject, c_int) -> *mut RawObject, // 437
    Tcl_DetachChannel: extern "C" fn(*const Interpreter, *mut c_void) -> c_int, // 438
    Tcl_IsStandardChannel: extern "C" fn(*mut c_void) -> c_int,             // 439
    Tcl_FSCopyFile: extern "C" fn(*mut RawObject, *mut RawObject) -> c_int, // 440
    Tcl_FSCopyDirectory: extern "C" fn(*mut RawObject, *mut RawObject, *mut c_void) -> c_int, // 441
    Tcl_FSCreateDirectory: extern "C" fn(*mut RawObject) -> c_int,          // 442
    Tcl_FSDeleteFile: extern "C" fn(*mut RawObject) -> c_int,               // 443
    Tcl_FSLoadFile: extern "C" fn(
        *const Interpreter,
        *mut RawObject,
        *const c_char,
        *const c_char,
        *mut c_void,
        *mut c_void,
        *mut c_void,
        *mut c_void,
    ) -> c_int, // 444
    Tcl_FSMatchInDirectory: extern "C" fn(
        *const Interpreter,
        *mut RawObject,
        *mut RawObject,
        *const c_char,
        *mut c_void,
    ) -> c_int, // 445
    Tcl_FSLink: extern "C" fn(*mut RawObject, *mut RawObject, c_int) -> *mut RawObject, // 446
    Tcl_FSRemoveDirectory: extern "C" fn(*mut RawObject, c_int, *mut c_void) -> c_int, // 447
    Tcl_FSRenameFile: extern "C" fn(*mut RawObject, *mut RawObject) -> c_int, // 448
    Tcl_FSLstat: extern "C" fn(*mut RawObject, *mut c_void) -> c_int,       // 449
    Tcl_FSUtime: extern "C" fn(*mut RawObject, *mut c_void) -> c_int,       // 450
    Tcl_FSFileAttrsGet:
        extern "C" fn(*const Interpreter, c_int, *mut RawObject, *mut c_void) -> c_int, // 451
    Tcl_FSFileAttrsSet:
        extern "C" fn(*const Interpreter, c_int, *mut RawObject, *mut RawObject) -> c_int, // 452
    Tcl_FSFileAttrStrings: extern "C" fn(*mut RawObject, *mut c_void) -> *const c_void, // 453
    Tcl_FSStat: extern "C" fn(*mut RawObject, *mut c_void) -> c_int,        // 454
    Tcl_FSAccess: extern "C" fn(*mut RawObject, c_int) -> c_int,            // 455
    Tcl_FSOpenFileChannel:
        extern "C" fn(*const Interpreter, *mut RawObject, *const c_char, c_int) -> *mut c_void, // 456
    Tcl_FSGetCwd: extern "C" fn(*const Interpreter) -> *mut RawObject, // 457
    Tcl_FSChdir: extern "C" fn(*mut RawObject) -> c_int,               // 458
    Tcl_FSConvertToPathType: extern "C" fn(*const Interpreter, *mut RawObject) -> c_int, // 459
    Tcl_FSJoinPath: extern "C" fn(*mut RawObject, usize) -> *mut RawObject, // 460
    TclFSSplitPath: extern "C" fn(*mut RawObject, *mut c_void) -> *mut RawObject, // 461
    Tcl_FSEqualPaths: extern "C" fn(*mut RawObject, *mut RawObject) -> c_int, // 462
    Tcl_FSGetNormalizedPath: extern "C" fn(*const Interpreter, *mut RawObject) -> *mut RawObject, // 463
    Tcl_FSJoinToPath: extern "C" fn(*mut RawObject, usize, *mut c_void) -> *mut RawObject, // 464
    Tcl_FSGetInternalRep: extern "C" fn(*mut RawObject, *const c_void) -> *mut c_void,     // 465
    Tcl_FSGetTranslatedPath: extern "C" fn(*const Interpreter, *mut RawObject) -> *mut RawObject, // 466
    Tcl_FSEvalFile: extern "C" fn(*const Interpreter, *mut RawObject) -> c_int, // 467
    Tcl_FSNewNativePath: extern "C" fn(*const c_void, *mut c_void) -> *mut RawObject, // 468
    Tcl_FSGetNativePath: extern "C" fn(*mut RawObject) -> *const c_void,        // 469
    Tcl_FSFileSystemInfo: extern "C" fn(*mut RawObject) -> *mut RawObject,      // 470
    Tcl_FSPathSeparator: extern "C" fn(*mut RawObject) -> *mut RawObject,       // 471
    Tcl_FSListVolumes: extern "C" fn() -> *mut RawObject,                       // 472
    Tcl_FSRegister: extern "C" fn(*mut c_void, *const c_void) -> c_int,         // 473
    Tcl_FSUnregister: extern "C" fn(*const c_void) -> c_int,                    // 474
    Tcl_FSData: extern "C" fn(*const c_void) -> *mut c_void,                    // 475
    Tcl_FSGetTranslatedStringPath:
        extern "C" fn(*const Interpreter, *mut RawObject) -> *const c_char, // 476
    Tcl_FSGetFileSystemForPath: extern "C" fn(*mut RawObject) -> *const c_void, // 477
    Tcl_FSGetPathType: extern "C" fn(*mut RawObject) -> *mut c_void,            // 478
    Tcl_OutputBuffered: extern "C" fn(*mut c_void) -> c_int,                    // 479
    Tcl_FSMountsChanged: extern "C" fn(*const c_void),                          // 480
    Tcl_EvalTokensStandard: extern "C" fn(*const Interpreter, *mut c_void, usize) -> c_int, // 481
    Tcl_GetTime: extern "C" fn(*mut c_void),                                    // 482
    Tcl_CreateObjTrace: extern "C" fn(
        *const Interpreter,
        usize,
        c_int,
        *mut c_void,
        *mut c_void,
        *mut c_void,
    ) -> *mut c_void, // 483
    Tcl_GetCommandInfoFromToken: extern "C" fn(*mut c_void, *mut c_void) -> c_int, // 484
    Tcl_SetCommandInfoFromToken: extern "C" fn(*mut c_void, *const c_void) -> c_int, // 485
    Tcl_DbNewWideIntObj: extern "C" fn(*mut c_void, *const c_char, c_int) -> *mut RawObject, // 486
    Tcl_GetWideIntFromObj: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 487
    Tcl_NewWideIntObj: extern "C" fn(*mut c_void) -> *mut RawObject, // 488
    Tcl_SetWideIntObj: extern "C" fn(*mut RawObject, *mut c_void),   // 489
    Tcl_AllocStatBuf: extern "C" fn() -> *mut c_void,                // 490
    Tcl_Seek: extern "C" fn(*mut c_void, c_longlong, c_int) -> c_longlong, // 491
    Tcl_Tell: extern "C" fn(*mut c_void) -> c_longlong,              // 492
    Tcl_ChannelWideSeekProc: extern "C" fn(*const c_void) -> *mut c_void, // 493
    Tcl_DictObjPut:
        extern "C" fn(*const Interpreter, *mut RawObject, *mut RawObject, *mut RawObject) -> c_int, // 494
    Tcl_DictObjGet:
        extern "C" fn(*const Interpreter, *mut RawObject, *mut RawObject, *mut c_void) -> c_int, // 495
    Tcl_DictObjRemove: extern "C" fn(*const Interpreter, *mut RawObject, *mut RawObject) -> c_int, // 496
    TclDictObjSize: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 497
    Tcl_DictObjFirst: extern "C" fn(
        *const Interpreter,
        *mut RawObject,
        *mut c_void,
        *mut c_void,
        *mut c_void,
        *mut c_void,
    ) -> c_int, // 498
    Tcl_DictObjNext: extern "C" fn(*mut c_void, *mut c_void, *mut c_void, *mut c_void),      // 499
    Tcl_DictObjDone: extern "C" fn(*mut c_void),                                             // 500
    Tcl_DictObjPutKeyList: extern "C" fn(
        *const Interpreter,
        *mut RawObject,
        usize,
        *mut c_void,
        *mut RawObject,
    ) -> c_int, // 501
    Tcl_DictObjRemoveKeyList:
        extern "C" fn(*const Interpreter, *mut RawObject, usize, *mut c_void) -> c_int, // 502
    Tcl_NewDictObj: extern "C" fn() -> *mut RawObject,                                       // 503
    Tcl_DbNewDictObj: extern "C" fn(*const c_char, c_int) -> *mut RawObject,                 // 504
    Tcl_RegisterConfig:
        extern "C" fn(*const Interpreter, *const c_char, *const c_void, *const c_char), // 505
    Tcl_CreateNamespace:
        extern "C" fn(*const Interpreter, *const c_char, *mut c_void, *mut c_void) -> *mut c_void, // 506
    Tcl_DeleteNamespace: extern "C" fn(*mut c_void), // 507
    Tcl_AppendExportList: extern "C" fn(*const Interpreter, *mut c_void, *mut RawObject) -> c_int, // 508
    Tcl_Export: extern "C" fn(*const Interpreter, *mut c_void, *const c_char, c_int) -> c_int, // 509
    Tcl_Import: extern "C" fn(*const Interpreter, *mut c_void, *const c_char, c_int) -> c_int, // 510
    Tcl_ForgetImport: extern "C" fn(*const Interpreter, *mut c_void, *const c_char) -> c_int, // 511
    Tcl_GetCurrentNamespace: extern "C" fn(*const Interpreter) -> *mut c_void,                // 512
    Tcl_GetGlobalNamespace: extern "C" fn(*const Interpreter) -> *mut c_void,                 // 513
    Tcl_FindNamespace:
        extern "C" fn(*const Interpreter, *const c_char, *mut c_void, c_int) -> *mut c_void, // 514
    Tcl_FindCommand:
        extern "C" fn(*const Interpreter, *const c_char, *mut c_void, c_int) -> *mut c_void, // 515
    Tcl_GetCommandFromObj: extern "C" fn(*const Interpreter, *mut RawObject) -> *mut c_void,  // 516
    Tcl_GetCommandFullName: extern "C" fn(*const Interpreter, *mut c_void, *mut RawObject),   // 517
    Tcl_FSEvalFileEx: extern "C" fn(*const Interpreter, *mut RawObject, *const c_char) -> c_int, // 518
    _deprecated_519: *const c_void, // 519
    Tcl_LimitAddHandler:
        extern "C" fn(*const Interpreter, c_int, *mut c_void, *mut c_void, *mut c_void), // 520
    Tcl_LimitRemoveHandler: extern "C" fn(*const Interpreter, c_int, *mut c_void, *mut c_void), // 521
    Tcl_LimitReady: extern "C" fn(*const Interpreter) -> c_int, // 522
    Tcl_LimitCheck: extern "C" fn(*const Interpreter) -> c_int, // 523
    Tcl_LimitExceeded: extern "C" fn(*const Interpreter) -> c_int, // 524
    Tcl_LimitSetCommands: extern "C" fn(*const Interpreter, usize), // 525
    Tcl_LimitSetTime: extern "C" fn(*const Interpreter, *mut c_void), // 526
    Tcl_LimitSetGranularity: extern "C" fn(*const Interpreter, c_int, c_int), // 527
    Tcl_LimitTypeEnabled: extern "C" fn(*const Interpreter, c_int) -> c_int, // 528
    Tcl_LimitTypeExceeded: extern "C" fn(*const Interpreter, c_int) -> c_int, // 529
    Tcl_LimitTypeSet: extern "C" fn(*const Interpreter, c_int), // 530
    Tcl_LimitTypeReset: extern "C" fn(*const Interpreter, c_int), // 531
    Tcl_LimitGetCommands: extern "C" fn(*const Interpreter) -> usize, // 532
    Tcl_LimitGetTime: extern "C" fn(*const Interpreter, *mut c_void), // 533
    Tcl_LimitGetGranularity: extern "C" fn(*const Interpreter, c_int) -> c_int, // 534
    Tcl_SaveInterpState: extern "C" fn(*const Interpreter, c_int) -> *mut c_void, // 535
    Tcl_RestoreInterpState: extern "C" fn(*const Interpreter, *mut c_void) -> c_int, // 536
    Tcl_DiscardInterpState: extern "C" fn(*mut c_void),         // 537
    Tcl_SetReturnOptions: extern "C" fn(*const Interpreter, *mut RawObject) -> c_int, // 538
    Tcl_GetReturnOptions: extern "C" fn(*const Interpreter, c_int) -> *mut RawObject, // 539
    Tcl_IsEnsemble: extern "C" fn(*mut c_void) -> c_int,        // 540
    Tcl_CreateEnsemble:
        extern "C" fn(*const Interpreter, *const c_char, *mut c_void, c_int) -> *mut c_void, // 541
    Tcl_FindEnsemble: extern "C" fn(*const Interpreter, *mut RawObject, c_int) -> *mut c_void, // 542
    Tcl_SetEnsembleSubcommandList:
        extern "C" fn(*const Interpreter, *mut c_void, *mut RawObject) -> c_int, // 543
    Tcl_SetEnsembleMappingDict:
        extern "C" fn(*const Interpreter, *mut c_void, *mut RawObject) -> c_int, // 544
    Tcl_SetEnsembleUnknownHandler:
        extern "C" fn(*const Interpreter, *mut c_void, *mut RawObject) -> c_int, // 545
    Tcl_SetEnsembleFlags: extern "C" fn(*const Interpreter, *mut c_void, c_int) -> c_int, // 546
    Tcl_GetEnsembleSubcommandList:
        extern "C" fn(*const Interpreter, *mut c_void, *mut c_void) -> c_int, // 547
    Tcl_GetEnsembleMappingDict:
        extern "C" fn(*const Interpreter, *mut c_void, *mut c_void) -> c_int, // 548
    Tcl_GetEnsembleUnknownHandler:
        extern "C" fn(*const Interpreter, *mut c_void, *mut c_void) -> c_int, // 549
    Tcl_GetEnsembleFlags: extern "C" fn(*const Interpreter, *mut c_void, *mut c_void) -> c_int, // 550
    Tcl_GetEnsembleNamespace: extern "C" fn(*const Interpreter, *mut c_void, *mut c_void) -> c_int, // 551
    Tcl_SetTimeProc: extern "C" fn(*mut c_void, *mut c_void, *mut c_void), // 552
    Tcl_QueryTimeProc: extern "C" fn(*mut c_void, *mut c_void, *mut c_void), // 553
    Tcl_ChannelThreadActionProc: extern "C" fn(*const c_void) -> *mut c_void, // 554
    Tcl_NewBignumObj: extern "C" fn(*mut c_void) -> *mut RawObject,        // 555
    Tcl_DbNewBignumObj: extern "C" fn(*mut c_void, *const c_char, c_int) -> *mut RawObject, // 556
    Tcl_SetBignumObj: extern "C" fn(*mut RawObject, *mut c_void),          // 557
    Tcl_GetBignumFromObj: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 558
    Tcl_TakeBignumFromObj: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 559
    Tcl_TruncateChannel: extern "C" fn(*mut c_void, c_longlong) -> c_int, // 560
    Tcl_ChannelTruncateProc: extern "C" fn(*const c_void) -> *mut c_void, // 561
    Tcl_SetChannelErrorInterp: extern "C" fn(*const Interpreter, *mut RawObject), // 562
    Tcl_GetChannelErrorInterp: extern "C" fn(*const Interpreter, *mut c_void), // 563
    Tcl_SetChannelError: extern "C" fn(*mut c_void, *mut RawObject),      // 564
    Tcl_GetChannelError: extern "C" fn(*mut c_void, *mut c_void),         // 565
    Tcl_InitBignumFromDouble: extern "C" fn(*const Interpreter, c_double, *mut c_void) -> c_int, // 566
    Tcl_GetNamespaceUnknownHandler:
        extern "C" fn(*const Interpreter, *mut c_void) -> *mut RawObject, // 567
    Tcl_SetNamespaceUnknownHandler:
        extern "C" fn(*const Interpreter, *mut c_void, *mut RawObject) -> c_int, // 568
    Tcl_GetEncodingFromObj: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 569
    Tcl_GetEncodingSearchPath: extern "C" fn() -> *mut RawObject, // 570
    Tcl_SetEncodingSearchPath: extern "C" fn(*mut RawObject) -> c_int, // 571
    Tcl_GetEncodingNameFromEnvironment: extern "C" fn(*mut c_void) -> *const c_char, // 572
    Tcl_PkgRequireProc:
        extern "C" fn(*const Interpreter, *const c_char, usize, *mut c_void, *mut c_void) -> c_int, // 573
    Tcl_AppendObjToErrorInfo: extern "C" fn(*const Interpreter, *mut RawObject), // 574
    Tcl_AppendLimitedToObj:
        extern "C" fn(*mut RawObject, *const c_char, usize, usize, *const c_char), // 575
    Tcl_Format:
        extern "C" fn(*const Interpreter, *const c_char, usize, *mut c_void) -> *mut RawObject, // 576
    Tcl_AppendFormatToObj: extern "C" fn(
        *const Interpreter,
        *mut RawObject,
        *const c_char,
        usize,
        *mut c_void,
    ) -> c_int, // 577
    Tcl_ObjPrintf: extern "C" fn(*const c_char, *const c_char) -> *mut RawObject, // 578
    Tcl_AppendPrintfToObj: extern "C" fn(*mut RawObject, *const c_char, *const c_char), // 579
    Tcl_CancelEval: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void, c_int) -> c_int, // 580
    Tcl_Canceled: extern "C" fn(*const Interpreter, c_int) -> c_int, // 581
    Tcl_CreatePipe: extern "C" fn(*mut c_void, *mut c_void, *mut c_void, c_int) -> c_int, // 582
    Tcl_NRCreateCommand: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *mut c_void,
        *mut c_void,
        *mut c_void,
        *mut c_void,
    ) -> *mut c_void, // 583
    Tcl_NREvalObj: extern "C" fn(*const Interpreter, *mut RawObject, c_int) -> c_int, // 584
    Tcl_NREvalObjv: extern "C" fn(*const Interpreter, usize, *mut c_void, c_int) -> c_int, // 585
    Tcl_NRCmdSwap:
        extern "C" fn(*const Interpreter, *mut c_void, usize, *mut c_void, c_int) -> c_int, // 586
    Tcl_NRAddCallback: extern "C" fn(
        *const Interpreter,
        *mut c_void,
        *mut c_void,
        *mut c_void,
        *mut c_void,
        *mut c_void,
    ), // 587
    Tcl_NRCallObjProc:
        extern "C" fn(*const Interpreter, *mut c_void, *mut c_void, usize, *mut c_void) -> c_int, // 588
    Tcl_GetFSDeviceFromStat: extern "C" fn(*const c_void) -> *mut c_void, // 589
    Tcl_GetFSInodeFromStat: extern "C" fn(*const c_void) -> *mut c_void,  // 590
    Tcl_GetModeFromStat: extern "C" fn(*const c_void) -> *mut c_void,     // 591
    Tcl_GetLinkCountFromStat: extern "C" fn(*const c_void) -> c_int,      // 592
    Tcl_GetUserIdFromStat: extern "C" fn(*const c_void) -> c_int,         // 593
    Tcl_GetGroupIdFromStat: extern "C" fn(*const c_void) -> c_int,        // 594
    Tcl_GetDeviceTypeFromStat: extern "C" fn(*const c_void) -> c_int,     // 595
    Tcl_GetAccessTimeFromStat: extern "C" fn(*const c_void) -> c_longlong, // 596
    Tcl_GetModificationTimeFromStat: extern "C" fn(*const c_void) -> c_longlong, // 597
    Tcl_GetChangeTimeFromStat: extern "C" fn(*const c_void) -> c_longlong, // 598
    Tcl_GetSizeFromStat: extern "C" fn(*const c_void) -> c_ulonglong,     // 599
    Tcl_GetBlocksFromStat: extern "C" fn(*const c_void) -> c_ulonglong,   // 600
    Tcl_GetBlockSizeFromStat: extern "C" fn(*const c_void) -> *mut c_void, // 601
    Tcl_SetEnsembleParameterList:
        extern "C" fn(*const Interpreter, *mut c_void, *mut RawObject) -> c_int, // 602
    Tcl_GetEnsembleParameterList:
        extern "C" fn(*const Interpreter, *mut c_void, *mut c_void) -> c_int, // 603
    TclParseArgsObjv: extern "C" fn(
        *const Interpreter,
        *const c_void,
        *mut c_void,
        *mut c_void,
        *mut c_void,
    ) -> c_int, // 604
    Tcl_GetErrorLine: extern "C" fn(*const Interpreter) -> c_int,         // 605
    Tcl_SetErrorLine: extern "C" fn(*const Interpreter, c_int),           // 606
    Tcl_TransferResult: extern "C" fn(*const Interpreter, c_int, *const Interpreter), // 607
    Tcl_InterpActive: extern "C" fn(*const Interpreter) -> c_int,         // 608
    Tcl_BackgroundException: extern "C" fn(*const Interpreter, c_int),    // 609
    Tcl_ZlibDeflate:
        extern "C" fn(*const Interpreter, c_int, *mut RawObject, c_int, *mut RawObject) -> c_int, // 610
    Tcl_ZlibInflate:
        extern "C" fn(*const Interpreter, c_int, *mut RawObject, usize, *mut RawObject) -> c_int, // 611
    Tcl_ZlibCRC32: extern "C" fn(c_uint, *const c_void, usize) -> c_uint, // 612
    Tcl_ZlibAdler32: extern "C" fn(c_uint, *const c_void, usize) -> c_uint, // 613
    Tcl_ZlibStreamInit: extern "C" fn(
        *const Interpreter,
        c_int,
        c_int,
        c_int,
        *mut RawObject,
        *mut c_void,
    ) -> c_int, // 614
    Tcl_ZlibStreamGetCommandName: extern "C" fn(*mut c_void) -> *mut RawObject, // 615
    Tcl_ZlibStreamEof: extern "C" fn(*mut c_void) -> c_int,               // 616
    Tcl_ZlibStreamChecksum: extern "C" fn(*mut c_void) -> c_int,          // 617
    Tcl_ZlibStreamPut: extern "C" fn(*mut c_void, *mut RawObject, c_int) -> c_int, // 618
    Tcl_ZlibStreamGet: extern "C" fn(*mut c_void, *mut RawObject, usize) -> c_int, // 619
    Tcl_ZlibStreamClose: extern "C" fn(*mut c_void) -> c_int,             // 620
    Tcl_ZlibStreamReset: extern "C" fn(*mut c_void) -> c_int,             // 621
    Tcl_SetStartupScript: extern "C" fn(*mut RawObject, *const c_char),   // 622
    Tcl_GetStartupScript: extern "C" fn(*const c_void) -> *mut RawObject, // 623
    Tcl_CloseEx: extern "C" fn(*const Interpreter, *mut c_void, c_int) -> c_int, // 624
    Tcl_NRExprObj: extern "C" fn(*const Interpreter, *mut RawObject, *mut RawObject) -> c_int, // 625
    Tcl_NRSubstObj: extern "C" fn(*const Interpreter, *mut RawObject, c_int) -> c_int, // 626
    Tcl_LoadFile: extern "C" fn(
        *const Interpreter,
        *mut RawObject,
        *mut c_void,
        c_int,
        *mut c_void,
        *mut c_void,
    ) -> c_int, // 627
    Tcl_FindSymbol: extern "C" fn(*const Interpreter, *mut c_void, *const c_char) -> *mut c_void, // 628
    Tcl_FSUnloadFile: extern "C" fn(*const Interpreter, *mut c_void) -> c_int, // 629
    Tcl_ZlibStreamSetCompressionDictionary: extern "C" fn(*mut c_void, *mut RawObject), // 630
    Tcl_OpenTcpServerEx: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *const c_char,
        c_uint,
        c_int,
        *mut c_void,
        *mut c_void,
    ) -> *mut c_void, // 631
    TclZipfs_Mount:
        extern "C" fn(*const Interpreter, *const c_char, *const c_char, *const c_char) -> c_int, // 632
    TclZipfs_Unmount: extern "C" fn(*const Interpreter, *const c_char) -> c_int, // 633
    TclZipfs_TclLibrary: extern "C" fn() -> *mut RawObject,                      // 634
    TclZipfs_MountBuffer: extern "C" fn(
        *const Interpreter,
        *const c_void,
        *mut c_void,
        *const c_char,
        c_int,
    ) -> c_int, // 635
    Tcl_FreeInternalRep: extern "C" fn(*mut RawObject),                          // 636
    Tcl_InitStringRep: extern "C" fn(*mut RawObject, *const c_char, usize) -> *mut c_char, // 637
    Tcl_FetchInternalRep: extern "C" fn(*mut RawObject, *const ObjectType) -> *mut c_void, // 638
    Tcl_StoreInternalRep: extern "C" fn(*mut RawObject, *const ObjectType, *const c_void), // 639
    Tcl_HasStringRep: extern "C" fn(*mut RawObject) -> c_int,                    // 640
    Tcl_IncrRefCount: extern "C" fn(*mut RawObject),                             // 641
    Tcl_DecrRefCount: extern "C" fn(*mut RawObject),                             // 642
    Tcl_IsShared: extern "C" fn(*mut RawObject) -> c_int,                        // 643
    Tcl_LinkArray:
        extern "C" fn(*const Interpreter, *const c_char, *mut c_void, c_int, usize) -> c_int, // 644
    Tcl_GetIntForIndex:
        extern "C" fn(*const Interpreter, *mut RawObject, usize, *mut c_void) -> c_int, // 645
    Tcl_UtfToUniChar: extern "C" fn(*const c_char, *mut c_void) -> usize,        // 646
    Tcl_UniCharToUtfDString: extern "C" fn(*const c_void, usize, *mut c_void) -> *mut c_char, // 647
    Tcl_UtfToUniCharDString: extern "C" fn(*const c_char, usize, *mut c_void) -> *mut c_void, // 648
    TclGetBytesFromObj:
        extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> *mut c_void, // 649
    Tcl_GetBytesFromObj:
        extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> *mut c_void, // 650
    Tcl_GetStringFromObj: extern "C" fn(*mut RawObject, *mut c_void) -> *mut c_char, // 651
    Tcl_GetUnicodeFromObj: extern "C" fn(*mut RawObject, *mut c_void) -> *mut c_void, // 652
    Tcl_GetSizeIntFromObj: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 653
    Tcl_UtfCharComplete: extern "C" fn(*const c_char, usize) -> c_int, // 654
    Tcl_UtfNext: extern "C" fn(*const c_char) -> *const c_char,        // 655
    Tcl_UtfPrev: extern "C" fn(*const c_char, *const c_char) -> *const c_char, // 656
    Tcl_FSTildeExpand: extern "C" fn(*const Interpreter, *const c_char, *mut c_void) -> c_int, // 657
    Tcl_ExternalToUtfDStringEx: extern "C" fn(
        *const Interpreter,
        *mut c_void,
        *const c_char,
        usize,
        c_int,
        *mut c_void,
        *mut c_void,
    ) -> c_int, // 658
    Tcl_UtfToExternalDStringEx: extern "C" fn(
        *const Interpreter,
        *mut c_void,
        *const c_char,
        usize,
        c_int,
        *mut c_void,
        *mut c_void,
    ) -> c_int, // 659
    Tcl_AsyncMarkFromSignal: extern "C" fn(*mut c_void, c_int) -> c_int, // 660
    Tcl_ListObjGetElements:
        extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void, *mut c_void) -> c_int, // 661
    Tcl_ListObjLength: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 662
    Tcl_DictObjSize: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 663
    Tcl_SplitList:
        extern "C" fn(*const Interpreter, *const c_char, *mut c_void, *const c_void) -> c_int, // 664
    Tcl_SplitPath: extern "C" fn(*const c_char, *mut c_void, *const c_void), // 665
    Tcl_FSSplitPath: extern "C" fn(*mut RawObject, *mut c_void) -> *mut RawObject, // 666
    Tcl_ParseArgsObjv: extern "C" fn(
        *const Interpreter,
        *const c_void,
        *mut c_void,
        *mut c_void,
        *mut c_void,
    ) -> c_int, // 667
    Tcl_UniCharLen: extern "C" fn(*const c_void) -> usize,                   // 668
    Tcl_NumUtfChars: extern "C" fn(*const c_char, usize) -> usize,           // 669
    Tcl_GetCharLength: extern "C" fn(*mut RawObject) -> usize,               // 670
    Tcl_UtfAtIndex: extern "C" fn(*const c_char, usize) -> *const c_char,    // 671
    Tcl_GetRange: extern "C" fn(*mut RawObject, usize, usize) -> *mut RawObject, // 672
    Tcl_GetUniChar: extern "C" fn(*mut RawObject, usize) -> c_int,           // 673
    Tcl_GetBool: extern "C" fn(*const Interpreter, *const c_char, c_int, *mut c_char) -> c_int, // 674
    Tcl_GetBoolFromObj:
        extern "C" fn(*const Interpreter, *mut RawObject, c_int, *mut c_char) -> c_int, // 675
    Tcl_CreateObjCommand2: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *mut c_void,
        *mut c_void,
        *mut c_void,
    ) -> *mut c_void, // 676
    Tcl_CreateObjTrace2: extern "C" fn(
        *const Interpreter,
        usize,
        c_int,
        *mut c_void,
        *mut c_void,
        *mut c_void,
    ) -> *mut c_void, // 677
    Tcl_NRCreateCommand2: extern "C" fn(
        *const Interpreter,
        *const c_char,
        *mut c_void,
        *mut c_void,
        *mut c_void,
        *mut c_void,
    ) -> *mut c_void, // 678
    Tcl_NRCallObjProc2:
        extern "C" fn(*const Interpreter, *mut c_void, *mut c_void, usize, *mut c_void) -> c_int, // 679
    Tcl_GetNumberFromObj:
        extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void, *mut c_void) -> c_int, // 680
    Tcl_GetNumber:
        extern "C" fn(*const Interpreter, *const c_char, usize, *mut c_void, *mut c_void) -> c_int, // 681
    Tcl_RemoveChannelMode: extern "C" fn(*const Interpreter, *mut c_void, c_int) -> c_int, // 682
    Tcl_GetEncodingNulLength: extern "C" fn(*mut c_void) -> usize,                         // 683
    Tcl_GetWideUIntFromObj: extern "C" fn(*const Interpreter, *mut RawObject, *mut c_void) -> c_int, // 684
    Tcl_DStringToObj: extern "C" fn(*mut c_void) -> *mut RawObject, // 685
    Tcl_UtfNcmp: extern "C" fn(*const c_char, *const c_char, *mut c_void) -> c_int, // 686
    Tcl_UtfNcasecmp: extern "C" fn(*const c_char, *const c_char, *mut c_void) -> c_int, // 687
    Tcl_NewWideUIntObj: extern "C" fn(*mut c_void) -> *mut RawObject, // 688
    Tcl_SetWideUIntObj: extern "C" fn(*mut RawObject, *mut c_void), // 689
}
// END STUBS VTABLE

/// Error codes for unwrapping a Tcl interpreter.
///
/// These exist primarily for debugging and advanced use-cases.  Unless you
/// are calling [from_raw](Interpreter::from_raw), you should not need to worry about these.
#[derive(Debug)]
pub enum Error {
    NullInterpreter,
    NullStubs,
    InvalidStubs,
    TclError(String),
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Error::NullInterpreter => write!(f, "interpreter pointer was null"),
            Error::NullStubs => write!(f, "stubs pointer was null"),
            Error::InvalidStubs => write!(f, "stubs magic number did not match expected value"),
            Error::TclError(msg) => write!(f, "Tcl error: {msg}"),
        }
    }
}

impl std::error::Error for Error {}

impl<'a> Interpreter {
    /// Converts a raw pointer to a Tcl interpreter into a Rust reference.
    ///
    /// Most users should not need to use this function because a reference is
    /// already passed to the appropriate functions.  This is public because
    /// of how the [module_init](rtea_proc::module_init) macro works.
    #[allow(clippy::not_unsafe_ptr_arg_deref)]
    pub fn from_raw(interpreter: *const Interpreter) -> Result<&'a Interpreter, Error> {
        let interpreter = unsafe { interpreter.as_ref() }.ok_or(Error::NullInterpreter)?;
        let stubs = unsafe { interpreter.stubs.as_ref() }.ok_or(Error::NullStubs)?;
        if stubs.magic != TCL_STUB_MAGIC {
            return Err(Error::InvalidStubs);
        }
        Ok(interpreter)
    }

    /// DO NOT USE THIS FUNCTION.
    ///
    /// This function is only public so that it can be called by the
    /// [module_init](rtea_proc::module_init) macro for derivative RTEA
    /// projects.
    pub fn init_global_functions(&self) {
        unsafe {
            let stubs = self
                .stubs
                .as_ref()
                .expect("stubs missing after initial check");

            ALLOC = Some(stubs.Tcl_AttemptAlloc);
            REALLOC = Some(stubs.Tcl_AttemptRealloc);
            FREE = Some(stubs.Tcl_Free);

            NEW_OBJ = Some(stubs.Tcl_NewObj);
            DUPLICATE_OBJ = Some(stubs.Tcl_DuplicateObj);
            INCR_REF_COUNT = Some(stubs.Tcl_IncrRefCount);
            DECR_REF_COUNT = Some(stubs.Tcl_DecrRefCount);
            IS_SHARED = Some(stubs.Tcl_IsShared);
            INVALIDATE_STRING_REP = Some(stubs.Tcl_InvalidateStringRep);
            GET_STRING = Some(stubs.Tcl_GetString);

            GET_OBJ_TYPE = Some(stubs.Tcl_GetObjType);
            CONVERT_TO_TYPE = Some(stubs.Tcl_ConvertToType);

            NEW_STRING_OBJ = Some(stubs.Tcl_NewStringObj);
            SET_STRING_OBJ = Some(stubs.Tcl_SetStringObj);
        }
    }

    /// Informs the Tcl interpreter that the given package and version is available.
    pub fn provide_package(&self, name: &str, version: &str) -> Result<TclStatus, String> {
        let name =
            CString::new(name).map_err(|_| "unexpected Nul in package version".to_string())?;
        let version =
            CString::new(version).map_err(|_| "unexpected Nul in package version".to_string())?;
        unsafe {
            (self
                .stubs
                .as_ref()
                .expect("stubs missing after initial check")
                .Tcl_PkgProvideEx)(
                self as *const Interpreter,
                name.as_ptr(),
                version.as_ptr(),
                std::ptr::null(),
            )
        };
        Ok(TclStatus::Ok)
    }

    /// Registers the command given by `proc` as `name`.
    pub fn create_command(&self, name: &str, proc: CmdProc) -> Result<TclStatus, String> {
        let name = CString::new(name).map_err(|_| "unexpected Nul in command name".to_string())?;

        // type TclCmdProc = extern "C" fn(
        //     data: *const c_void,
        //     interp: *const Interpreter,
        //     argc: usize,
        //     argv: *const *const i8,
        // ) -> TclStatus;
        extern "C" fn wrapper_proc(
            f_ptr: *const c_void,
            i: *const Interpreter,
            argc: usize,
            argv: *const *const i8,
        ) -> TclStatus {
            let interp = Interpreter::from_raw(i).expect("Tcl passed bad interpreter");
            let raw_args = unsafe { std::slice::from_raw_parts(argv, argc) };
            let mut args = Vec::with_capacity(raw_args.len());
            for arg in raw_args {
                args.push(
                    unsafe { std::ffi::CStr::from_ptr(*arg) }
                        .to_str()
                        .expect("invalid args from Tcl"),
                );
            }

            let f: CmdProc = unsafe { std::mem::transmute(f_ptr) };

            f(interp, args).unwrap_or_else(|s| {
                interp.set_result(&s);
                TclStatus::Error
            })
        }

        unsafe {
            (self
                .stubs
                .as_ref()
                .expect("stubs missing after initial check")
                .Tcl_CreateCommand)(
                self as *const Interpreter,
                name.as_ptr(),
                wrapper_proc as *mut c_void,
                proc as *mut c_void,
                std::ptr::null_mut::<c_void>(),
            )
        };

        Ok(TclStatus::Ok)
    }

    /// Registers the command given by `proc` as `name`.
    pub fn create_obj_command(&self, name: &str, proc: ObjCmdProc) -> Result<TclStatus, String> {
        let name = CString::new(name).map_err(|_| "unexpected Nul in command name".to_string())?;

        // type TclCmdProc = extern "C" fn(
        //     data: *const c_void,
        //     interp: *const Interpreter,
        //     argc: usize,
        //     argv: *const *mut RawObject,
        // ) -> TclStatus;
        extern "C" fn wrapper_proc(
            f_ptr: *const c_void,
            i: *const Interpreter,
            argc: usize,
            argv: *const *mut RawObject,
        ) -> TclStatus {
            let interp = Interpreter::from_raw(i).expect("Tcl passed bad interpreter");
            let raw_args = unsafe { std::slice::from_raw_parts(argv, argc) };
            let mut args = Vec::with_capacity(raw_args.len());
            for arg in raw_args {
                args.push(RawObject::wrap(*arg));
            }

            let f: ObjCmdProc = unsafe { std::mem::transmute(f_ptr) };

            f(interp, args).unwrap_or_else(|obj| {
                interp.set_obj_result(&obj);
                TclStatus::Error
            })
        }

        unsafe {
            (self
                .stubs
                .as_ref()
                .expect("stubs missing after initial check")
                .Tcl_CreateObjCommand)(
                self as *const Interpreter,
                name.as_ptr(),
                wrapper_proc as *mut c_void,
                proc as *mut c_void,
                std::ptr::null_mut::<c_void>(),
            )
        };

        Ok(TclStatus::Ok)
    }

    /// Registers the object with TCL
    pub fn register_obj_type<T: TclObjectType>(&self) {
        unsafe {
            (self
                .stubs
                .as_ref()
                .expect("stubs missing after initial check")
                .Tcl_RegisterObjType)(T::tcl_type() as *const ObjectType)
        }
    }

    /// Deletes the given command.
    ///
    /// This function attempts to delete the command `name` in the
    /// interpreter.  If it exists, `true` is returned, otherwise `false` is
    /// returned.  An error is only returned when the given `name` contains
    /// Nul characters and is therefore not a valid Tcl string.
    pub fn delete_command(&self, name: &str) -> Result<bool, String> {
        let name = CString::new(name).map_err(|_| "unexpected Nul in command name".to_string())?;

        let ret = unsafe {
            (self
                .stubs
                .as_ref()
                .expect("stubs missing after initial check")
                .Tcl_DeleteCommand)(self as *const Interpreter, name.as_ptr())
        };

        Ok(ret == 0)
    }

    /// Get the current result object for the interpreter.
    pub fn get_obj_result(&self) -> Object {
        unsafe {
            RawObject::wrap((self
                .stubs
                .as_ref()
                .expect("stubs missing after initial check")
                .Tcl_GetObjResult)(
                self as *const Interpreter
            ))
        }
    }

    /// Evaluate a Tcl script.
    ///
    /// Evaluates the given string as a Tcl script.  If the script return
    /// `TclStatus::Error`, then the associated error message is passed back
    /// as `Err`.  Otherwise the last commands return value is passed through
    /// as is.
    pub fn eval(&self, script: &str) -> Result<Object, Object> {
        if script.len() > 1 << 31 {
            return Err(
                Object::new(), // "Tcl versions prior to 9.0 do not support scripts greater than 2 GiB".to_string(),
            );
        }
        let status = unsafe {
            (self
                .stubs
                .as_ref()
                .expect("stubs missing after initial check")
                .Tcl_EvalEx)(
                self as *const Interpreter,
                script.as_ptr() as *const c_char,
                script.len(),
                0,
            )
        };
        let result = self.get_obj_result();
        if TclStatus::Error == status.into() {
            Err(result)
        } else {
            Ok(result)
        }
    }

    /// Set the interpreter's current result value.
    ///
    /// When inside command logic, this can be used to set the return value
    /// visible to the invoking Tcl script.
    pub fn set_result(&self, text: &str) {
        let result = Object::new_string(text);
        self.set_obj_result(&result);
    }

    pub fn set_obj_result(&self, result: &Object) {
        unsafe {
            (self
                .stubs
                .as_ref()
                .expect("stubs missing after initial check")
                .Tcl_SetObjResult)(self as *const Interpreter, result.obj)
        }
    }

    /// Allocates Tcl-managed memory.
    ///
    /// Allocates memory that is directly managed by Tcl.  This is required
    /// for certain interfaces (e.g., bytes representation of Tcl objects)
    /// and convenient for others (e.g., creating a Nul terminated string
    /// from a Rust `String`).
    pub fn alloc(&self, size: usize) -> Option<TclBuf> {
        if size >= 1 << 32 {
            return None;
        }
        let ptr = unsafe {
            // Trusting Tcl to handle this correctly (check above can be removed for Tcl 9.0)
            (self
                .stubs
                .as_ref()
                .expect("stubs missing after initial check")
                .Tcl_AttemptAlloc)(size)
        };

        if ptr.is_null() {
            None
        } else {
            // Safety: ptr is non-null, Tcl-allocated, and we are taking sole ownership.
            Some(unsafe { TclBuf::from_raw_parts(ptr as *mut u8, size) })
        }
    }
}

type CmdDataProc<T> =
    fn(interp: &Interpreter, data: &T, args: Vec<&str>) -> Result<TclStatus, String>;

/// A wrapper for creating stateful commands.
///
/// The `StatefulCommand` type enables the creation of Tcl commands that are
/// stateful.  In other words, they can be modified and carry-forward their
/// state to future invocations (in contrast to the `create_command` method
/// of [Interpreter] where the function must either be pure (from Tcl's
/// perspective) or use global state).
///
/// # Example
///
/// ```rust
/// use std::cell::RefCell;
///
/// use rtea::*;
///
/// fn create_stateful_command(interp: &Interpreter) {
///     fn cmd(
///         interp: &Interpreter,
///         counter: &RefCell<usize>,
///         _args: Vec<&str>,
///     ) -> Result<TclStatus, String> {
///         let mut val = counter.borrow_mut();
///         interp.set_result(&val.to_string());
///         *val += 1;
///
///         Ok(TclStatus::Ok)
///     }
///
///     let c = StatefulCommand::new(cmd, RefCell::<usize>::new(0));
///     c.attach_command(interp, "counter").unwrap();
///
///     for i in 0..10 {
///         interp.eval("counter").unwrap();
///         assert_eq!(i.to_string(), interp.get_obj_result().get_string());
///     }
/// }
/// ```
pub struct StatefulCommand<T> {
    proc: CmdDataProc<T>,
    data: T,
}

impl<T> StatefulCommand<T> {
    /// Creates a new `StatefulCommand`.
    ///
    /// The creates a new `StatefulComand` with ownership of `data`.  The
    /// underlying implementation should be as thread-safe as the original
    /// implementation of `data`, but care needs to be taken to ensure that
    /// any concurrency from Tcl is safe on `data` (there are no concerns for
    /// `proc`).
    pub fn new(proc: CmdDataProc<T>, data: T) -> StatefulCommand<T> {
        StatefulCommand { proc, data }
    }

    /// Attaches the `StatefulCommand` to a Tcl interpreter.
    ///
    /// This exposes the instantiated `StatefulCommand` to the given
    /// interpreter.  This should allow exposing a command to multiple
    /// interpreters (or as aliases in the same interpreter) for advanced
    /// functionality. While the borrow checker should prevent some misuses
    /// (type is passed by ownership), this has not been heavily tested for
    /// every type `T`.
    pub fn attach_command(self, interp: &Interpreter, name: &str) -> Result<TclStatus, String> {
        let state = Box::new(self);
        let name = CString::new(name).map_err(|_| "unexpected Nul in command name".to_string())?;

        // Simple wrapper of the Rust function and data to work with Tcl's API.
        extern "C" fn wrapper_proc<T>(
            state: *const StatefulCommand<T>,
            i: *const Interpreter,
            argc: usize,
            argv: *const *const i8,
        ) -> TclStatus {
            let interp = Interpreter::from_raw(i).expect("Tcl passed bad interpreter");
            let raw_args = unsafe { std::slice::from_raw_parts(argv, argc) };
            let mut args = Vec::with_capacity(raw_args.len());
            for arg in raw_args {
                args.push(
                    unsafe { std::ffi::CStr::from_ptr(*arg) }
                        .to_str()
                        .expect("invalid args from Tcl"),
                );
            }

            let state = unsafe { state.as_ref() }.expect("data command corrupted!");

            (state.proc)(interp, &state.data, args).unwrap_or_else(|s| {
                interp.set_result(&s);
                TclStatus::Error
            })
        }

        // Simple function to restore the `StatefulCommand` to Rust's
        // understanding to allow Rust's RAII code to kick in.
        fn free_state<T>(state: *mut StatefulCommand<T>) {
            // This relies on Tcl to properly track the command state and
            // invoke this at the appropriate moment.  Retaking ownership
            // of the underlying pointer ensures the destructor gets called
            unsafe {
                let _ = Box::from_raw(state);
            };
        }

        unsafe {
            (interp
                .stubs
                .as_ref()
                .expect("stubs missing after initial check")
                .Tcl_CreateCommand)(
                interp as *const Interpreter,
                name.as_ptr(),
                wrapper_proc::<T> as *mut c_void,
                Box::<StatefulCommand<T>>::into_raw(state) as *mut c_void,
                free_state::<T> as *mut c_void,
            )
        };

        Ok(TclStatus::Ok)
    }
}