Merge tag 'dev-2025-11'

This commit is contained in:
ed
2025-11-05 22:27:46 -05:00
213 changed files with 4956 additions and 966 deletions
+10 -1
View File
@@ -49,7 +49,7 @@ int_least64_t :: builtin.i64
uint_least64_t :: builtin.u64
// Same on Windows, Linux, and FreeBSD
when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
when ODIN_ARCH == .i386 {
int_fast8_t :: builtin.i8
uint_fast8_t :: builtin.u8
int_fast16_t :: builtin.i32
@@ -58,6 +58,15 @@ when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
uint_fast32_t :: builtin.u32
int_fast64_t :: builtin.i64
uint_fast64_t :: builtin.u64
} else when ODIN_ARCH == .amd64 {
int_fast8_t :: builtin.i8
uint_fast8_t :: builtin.u8
int_fast16_t :: long
uint_fast16_t :: ulong
int_fast32_t :: long
uint_fast32_t :: ulong
int_fast64_t :: builtin.i64
uint_fast64_t :: builtin.u64
} else {
int_fast8_t :: builtin.i8
uint_fast8_t :: builtin.u8
+1 -1
View File
@@ -3,7 +3,7 @@ package compress
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Jeroen van Rijn: Initial implementation, optimization.
+1 -1
View File
@@ -82,7 +82,7 @@ package compress_gzip
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Jeroen van Rijn: Initial implementation.
+1 -1
View File
@@ -2,7 +2,7 @@ package compress_gzip
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Jeroen van Rijn: Initial implementation.
+1 -1
View File
@@ -3,7 +3,7 @@ package compress_shoco
/*
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Jeroen van Rijn: Initial implementation.
+1 -1
View File
@@ -44,7 +44,7 @@ package compress_zlib
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Jeroen van Rijn: Initial implementation.
+1 -1
View File
@@ -3,7 +3,7 @@ package compress_zlib
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Jeroen van Rijn: Initial implementation, optimization.
+1 -1
View File
@@ -309,7 +309,7 @@ Example:
import "core:container/small_array"
import "core:fmt"
non_zero_resize :: proc() {
non_zero_resize_example :: proc() {
a: small_array.Small_Array(5, int)
small_array.push_back(&a, 1)
+1 -1
View File
@@ -29,4 +29,4 @@ constant-time byte comparison.
## License
This library is made available under the BSD-3 license.
This library is made available under the zlib license.
+1 -1
View File
@@ -2,7 +2,7 @@ package _blake2
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
Made available under Odin's license.
List of contributors:
zhibog, dotbmp: Initial implementation.
+1 -1
View File
@@ -2,7 +2,7 @@ package _sha3
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
Made available under Odin's license.
List of contributors:
zhibog, dotbmp: Initial implementation.
+1 -1
View File
@@ -9,7 +9,7 @@ package blake2b
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
Made available under Odin's license.
List of contributors:
zhibog, dotbmp: Initial implementation.
+1 -1
View File
@@ -9,7 +9,7 @@ package blake2s
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
Made available under Odin's license.
List of contributors:
zhibog, dotbmp: Initial implementation.
+1 -1
View File
@@ -2,7 +2,7 @@ package crypto_hash
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
Made available under Odin's license.
List of contributors:
zhibog, dotbmp: Initial implementation.
+1 -1
View File
@@ -10,7 +10,7 @@ package keccak
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
Made available under Odin's license.
List of contributors:
zhibog, dotbmp: Initial implementation.
+1 -1
View File
@@ -12,7 +12,7 @@ package md5
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
Made available under Odin's license.
List of contributors:
zhibog, dotbmp: Initial implementation.
+1 -1
View File
@@ -13,7 +13,7 @@ package sha1
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
Made available under Odin's license.
List of contributors:
zhibog, dotbmp: Initial implementation.
+1 -1
View File
@@ -9,7 +9,7 @@ package sha2
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
Made available under Odin's license.
List of contributors:
zhibog, dotbmp: Initial implementation.
+1 -1
View File
@@ -12,7 +12,7 @@ package sha3
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
Made available under Odin's license.
List of contributors:
zhibog, dotbmp: Initial implementation.
+1 -1
View File
@@ -11,7 +11,7 @@ package shake
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
Made available under Odin's license.
List of contributors:
zhibog, dotbmp: Initial implementation.
+1 -1
View File
@@ -11,7 +11,7 @@ package siphash
/*
Copyright 2022 zhibog
Made available under the BSD-3 license.
Made available under Odin's license.
List of contributors:
zhibog: Initial implementation.
+1 -1
View File
@@ -8,7 +8,7 @@ package sm3
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
Made available under Odin's license.
List of contributors:
zhibog, dotbmp: Initial implementation.
+18 -14
View File
@@ -130,9 +130,9 @@ tag_time_unmarshal :: proc(_: ^Tag_Implementation, d: Decoder, _: Tag_Number, v:
case .U8, .U16, .U32, .U64, .Neg_U8, .Neg_U16, .Neg_U32, .Neg_U64:
switch &dst in v {
case time.Time:
i: i64
_unmarshal_any_ptr(d, &i, hdr) or_return
dst = time.unix(i64(i), 0)
secs: i64
_unmarshal_any_ptr(d, &secs, hdr) or_return
dst = time.unix(i64(secs), 0)
return
case:
return _unmarshal_value(d, v, hdr)
@@ -152,19 +152,23 @@ tag_time_unmarshal :: proc(_: ^Tag_Implementation, d: Decoder, _: Tag_Number, v:
case:
maj, add := _header_split(hdr)
if maj == .Other {
i := _decode_tiny_u8(add) or_return
switch &dst in v {
case time.Time:
dst = time.unix(i64(i), 0)
case:
if _assign_int(v, i) { return }
}
secs: u8
#partial switch maj {
case .Unsigned:
secs = _decode_tiny_u8(add) or_return
case .Other:
secs = u8(_decode_tiny_simple(add) or_return)
case:
return .Bad_Tag_Value
}
// Only numbers and floats are allowed in this tag.
return .Bad_Tag_Value
switch &dst in v {
case time.Time:
dst = time.unix(i64(secs), 0)
return
case:
if _assign_int(v, secs) { return }
}
}
return _unsupported(v, hdr)
+1 -1
View File
@@ -15,7 +15,7 @@ package encoding_unicode_entity
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Jeroen van Rijn: Initial implementation.
+14 -25
View File
@@ -1,28 +1,17 @@
BSD 3-Clause License
Copyright (c) 2024-2025 Feoramund, Ginger Bill. All rights reserved.
Copyright (c) 2024, Feoramund
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
+1 -1
View File
@@ -2,7 +2,7 @@ package encoding_varint
/*
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Jeroen van Rijn: Initial implementation.
+1 -1
View File
@@ -4,7 +4,7 @@ package encoding_xml
An XML 1.0 / 1.1 parser
Copyright 2021-2022 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
A from-scratch XML implementation, loosely modeled on the [spec](https://www.w3.org/TR/2006/REC-xml11-20060816).
+1 -1
View File
@@ -4,7 +4,7 @@ package encoding_xml
An XML 1.0 / 1.1 parser
Copyright 2021-2022 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
This file contains helper functions.
*/
+1 -1
View File
@@ -4,7 +4,7 @@ package encoding_xml
An XML 1.0 / 1.1 parser
Copyright 2021-2022 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
A from-scratch XML implementation, loosely modeled on the [spec](https://www.w3.org/TR/2006/REC-xml11-20060816).
+1 -1
View File
@@ -3,7 +3,7 @@ package encoding_xml
An XML 1.0 / 1.1 parser
2021-2022 Jeroen van Rijn <nom@duclavier.com>.
available under Odin's BSD-3 license.
available under Odin's license.
List of contributors:
- Jeroen van Rijn: Initial implementation.
+14 -25
View File
@@ -1,28 +1,17 @@
BSD 3-Clause License
Copyright (c) 2024-2025 Feoramund, Ginger Bill. All rights reserved.
Copyright (c) 2024, Feoramund
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
+4 -5
View File
@@ -10,14 +10,14 @@ SomeType :: struct {
My_Custom_Base_Type :: distinct u32
main :: proc() {
// Ensure the fmt._user_formatters map is initialized
// Ensure the fmt._user_formatters map is initialized
fmt.set_user_formatters(new(map[typeid]fmt.User_Formatter))
// Register custom formatters for my favorite types
err := fmt.register_user_formatter(type_info_of(SomeType).id, SomeType_Formatter)
assert(err == .None)
assert(err == .None)
err = fmt.register_user_formatter(type_info_of(My_Custom_Base_Type).id, My_Custom_Base_Formatter)
assert(err == .None)
assert(err == .None)
// Use the custom formatters.
fmt.printfln("SomeType{{42}}: '%v'", SomeType{42})
@@ -53,5 +53,4 @@ My_Custom_Base_Formatter :: proc(fi: ^fmt.Info, arg: any, verb: rune) -> bool {
return false
}
return true
}
}
+61 -7
View File
@@ -1,10 +1,27 @@
package hash
/*
Compute CRC-16 in the manner of CCITT (ITU-T V.41), using the 0x1021 polynomial.
Generator polynomial: x^16 + x^12 + x^5 + 1
Used in the UDF (DVD *.iso) disk format's Volume Descriptor Tag,
and was more historically the ITU-T V.41 CRC-16 used in the XModem protocol,
which uses 0xffff as the initial value.
*/
@(optimization_mode="favor_size")
crc16_ccitt_0x1021 :: proc "contextless" (data: []u8, seed := u16(0)) -> (result: u16) #no_bounds_check {
result = seed
#no_bounds_check for b in data {
result = result << 8 ~ _ccitt_0x1021_table[(result >> 8) ~ u16(b)]
}
return result
}
@(optimization_mode="favor_size")
crc64_ecma_182 :: proc "contextless" (data: []byte, seed := u64(0)) -> (result: u64) #no_bounds_check {
result = seed
#no_bounds_check for b in data {
result = result<<8 ~ _crc64_table_ecma_182[((result>>56) ~ u64(b)) & 0xff]
result = result << 8 ~ _crc64_table_ecma_182[((result>>56) ~ u64(b)) & 0xff]
}
return result
}
@@ -49,9 +66,7 @@ crc64_xz :: proc "contextless" (data: []byte, seed := u64(0)) -> u64 #no_bounds_
return u64(~result)
}
/*
Generator polynomial: x^64 + x^4 + x^3 + x + 1
*/
// Generator polynomial: x^64 + x^4 + x^3 + x + 1
@(optimization_mode="favor_size")
crc64_iso_3306 :: proc "contextless" (data: []byte, seed := u64(0)) -> u64 #no_bounds_check {
@@ -75,7 +90,8 @@ crc64_iso_3306_inverse :: proc "contextless" (data: []byte, seed := u64(0)) -> u
return ~result
}
@private _crc64_table_ecma_182 := [256]u64{
@(private, rodata)
_crc64_table_ecma_182 := [256]u64{
0x0000000000000000, 0x42f0e1eba9ea3693, 0x85e1c3d753d46d26, 0xc711223cfa3e5bb5,
0x493366450e42ecdf, 0x0bc387aea7a8da4c, 0xccd2a5925d9681f9, 0x8e224479f47cb76a,
0x9266cc8a1c85d9be, 0xd0962d61b56fef2d, 0x17870f5d4f51b498, 0x5577eeb6e6bb820b,
@@ -142,7 +158,8 @@ crc64_iso_3306_inverse :: proc "contextless" (data: []byte, seed := u64(0)) -> u
0x5dedc41a34bbeeb2, 0x1f1d25f19d51d821, 0xd80c07cd676f8394, 0x9afce626ce85b507,
}
@private _crc64_table_xz := [8][256]u64le{
@(private, rodata)
_crc64_table_xz := [8][256]u64le{
{
0x0000000000000000, 0xb32e4cbe03a75f6f, 0xf4843657a840a05b, 0x47aa7ae9abe7ff34,
0x7bd0c384ff8f5e33, 0xc8fe8f3afc28015c, 0x8f54f5d357cffe68, 0x3c7ab96d5468a107,
@@ -673,7 +690,8 @@ crc64_iso_3306_inverse :: proc "contextless" (data: []byte, seed := u64(0)) -> u
},
}
@private _crc64_table_iso_3306 := [256]u16{
@(private, rodata)
_crc64_table_iso_3306 := [256]u16{
0x0000, 0x01b0, 0x0360, 0x02d0,
0x06c0, 0x0770, 0x05a0, 0x0410,
0x0d80, 0x0c30, 0x0ee0, 0x0f50,
@@ -739,3 +757,39 @@ crc64_iso_3306_inverse :: proc "contextless" (data: []byte, seed := u64(0)) -> u
0x9480, 0x9530, 0x97e0, 0x9650,
0x9240, 0x93f0, 0x9120, 0x9090,
}
@(private, rodata)
_ccitt_0x1021_table := [256]u16{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0,
}
+1 -1
View File
@@ -6,7 +6,7 @@ package xxhash
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license, based on the original C code.
Made available under Odin's license, based on the original C code.
List of contributors:
Jeroen van Rijn: Initial implementation.
+1 -1
View File
@@ -4,7 +4,7 @@ package xxhash
An implementation of Yann Collet's [xxhash Fast Hash Algorithm](https://cyan4973.github.io/xxHash/).
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license, based on the original C code.
Made available under Odin's license, based on the original C code.
List of contributors:
Jeroen van Rijn: Initial implementation.
+1 -1
View File
@@ -4,7 +4,7 @@ package xxhash
An implementation of Yann Collet's [xxhash Fast Hash Algorithm](https://cyan4973.github.io/xxHash/).
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license, based on the original C code.
Made available under Odin's license, based on the original C code.
List of contributors:
Jeroen van Rijn: Initial implementation.
+1 -1
View File
@@ -4,7 +4,7 @@ package xxhash
An implementation of Yann Collet's [xxhash Fast Hash Algorithm](https://cyan4973.github.io/xxHash/).
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license, based on the original C code.
Made available under Odin's license, based on the original C code.
List of contributors:
Jeroen van Rijn: Initial implementation.
+1 -1
View File
@@ -4,7 +4,7 @@ package xxhash
An implementation of Yann Collet's [xxhash Fast Hash Algorithm](https://cyan4973.github.io/xxHash/).
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license, based on the original C code.
Made available under Odin's license, based on the original C code.
List of contributors:
Jeroen van Rijn: Initial implementation.
+1 -1
View File
@@ -2,7 +2,7 @@ package image
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Jeroen van Rijn: Initial implementation, optimization.
+1 -1
View File
@@ -3,7 +3,7 @@ package png
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Jeroen van Rijn: Initial implementation.
+1 -1
View File
@@ -5,7 +5,7 @@ package qoi
/*
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Jeroen van Rijn: Initial implementation.
+1 -1
View File
@@ -3,7 +3,7 @@ package tga
/*
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Jeroen van Rijn: Initial implementation.
+1 -1
View File
@@ -2,7 +2,7 @@ package math_big
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
This file collects public proc maps and their aliases.
*/
+1 -1
View File
@@ -2,7 +2,7 @@ package math_big
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
*/
import "base:intrinsics"
+1 -1
View File
@@ -2,7 +2,7 @@ package math_big
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
*/
import "base:intrinsics"
+1 -1
View File
@@ -2,7 +2,7 @@ package math_big
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
========================== Low-level routines ==========================
+1 -1
View File
@@ -2,7 +2,7 @@ package math_big
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
An arbitrary precision mathematics implementation in Odin.
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
+1 -1
View File
@@ -2,7 +2,7 @@ package math_big
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
An arbitrary precision mathematics implementation in Odin.
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
+1 -1
View File
@@ -2,7 +2,7 @@ package math_big
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
An arbitrary precision mathematics implementation in Odin.
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
+1 -1
View File
@@ -3,7 +3,7 @@ package math_big
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
An arbitrary precision mathematics implementation in Odin.
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
+1 -1
View File
@@ -2,7 +2,7 @@ package math_big
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
An arbitrary precision mathematics implementation in Odin.
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
+1 -1
View File
@@ -3,7 +3,7 @@ package math_big
/*
Copyright 2021 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
A BigInt implementation in Odin.
For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3.
+1070 -59
View File
File diff suppressed because it is too large Load Diff
+34 -208
View File
@@ -1,9 +1,8 @@
// Easing procedures and flux easing used for animations.
// Easing procedures used for animations.
package ease
import "core:math"
@require import "core:math"
import "base:intrinsics"
import "core:time"
@(private) PI_2 :: math.PI / 2
@@ -174,7 +173,7 @@ exponential_in_out :: proc "contextless" (p: $T) -> T where intrinsics.type_is_f
if p == 0.0 || p == 1.0 {
return p
}
if p < 0.5 {
return 0.5 * math.pow(2, (20 * p) - 10)
} else {
@@ -307,224 +306,51 @@ Ease :: enum {
}
@(require_results)
ease :: proc "contextless" (type: Ease, p: $T) -> T
where intrinsics.type_is_float(T) {
ease :: proc "contextless" (type: Ease, p: $T) -> T where intrinsics.type_is_float(T) {
switch type {
case .Linear: return p
case .Linear: return p
case .Quadratic_In: return quadratic_in(p)
case .Quadratic_Out: return quadratic_out(p)
case .Quadratic_In_Out: return quadratic_in_out(p)
case .Quadratic_In: return quadratic_in(p)
case .Quadratic_Out: return quadratic_out(p)
case .Quadratic_In_Out: return quadratic_in_out(p)
case .Cubic_In: return cubic_in(p)
case .Cubic_Out: return cubic_out(p)
case .Cubic_In_Out: return cubic_in_out(p)
case .Cubic_In: return cubic_in(p)
case .Cubic_Out: return cubic_out(p)
case .Cubic_In_Out: return cubic_in_out(p)
case .Quartic_In: return quartic_in(p)
case .Quartic_Out: return quartic_out(p)
case .Quartic_In_Out: return quartic_in_out(p)
case .Quartic_In: return quartic_in(p)
case .Quartic_Out: return quartic_out(p)
case .Quartic_In_Out: return quartic_in_out(p)
case .Quintic_In: return quintic_in(p)
case .Quintic_Out: return quintic_out(p)
case .Quintic_In_Out: return quintic_in_out(p)
case .Quintic_In: return quintic_in(p)
case .Quintic_Out: return quintic_out(p)
case .Quintic_In_Out: return quintic_in_out(p)
case .Sine_In: return sine_in(p)
case .Sine_Out: return sine_out(p)
case .Sine_In_Out: return sine_in_out(p)
case .Sine_In: return sine_in(p)
case .Sine_Out: return sine_out(p)
case .Sine_In_Out: return sine_in_out(p)
case .Circular_In: return circular_in(p)
case .Circular_Out: return circular_out(p)
case .Circular_In_Out: return circular_in_out(p)
case .Circular_In: return circular_in(p)
case .Circular_Out: return circular_out(p)
case .Circular_In_Out: return circular_in_out(p)
case .Exponential_In: return exponential_in(p)
case .Exponential_Out: return exponential_out(p)
case .Exponential_In: return exponential_in(p)
case .Exponential_Out: return exponential_out(p)
case .Exponential_In_Out: return exponential_in_out(p)
case .Elastic_In: return elastic_in(p)
case .Elastic_Out: return elastic_out(p)
case .Elastic_In_Out: return elastic_in_out(p)
case .Elastic_In: return elastic_in(p)
case .Elastic_Out: return elastic_out(p)
case .Elastic_In_Out: return elastic_in_out(p)
case .Back_In: return back_in(p)
case .Back_Out: return back_out(p)
case .Back_In_Out: return back_in_out(p)
case .Back_In: return back_in(p)
case .Back_Out: return back_out(p)
case .Back_In_Out: return back_in_out(p)
case .Bounce_In: return bounce_in(p)
case .Bounce_Out: return bounce_out(p)
case .Bounce_In_Out: return bounce_in_out(p)
case .Bounce_In: return bounce_in(p)
case .Bounce_Out: return bounce_out(p)
case .Bounce_In_Out: return bounce_in_out(p)
}
// in case type was invalid
return 0
}
Flux_Map :: struct($T: typeid) {
values: map[^T]Flux_Tween(T),
keys_to_be_deleted: [dynamic]^T,
}
Flux_Tween :: struct($T: typeid) {
value: ^T,
start: T,
diff: T,
goal: T,
delay: f64, // in seconds
duration: time.Duration,
progress: f64,
rate: f64,
type: Ease,
inited: bool,
// callbacks, data can be set, will be pushed to callback
data: rawptr, // by default gets set to value input
on_start: proc(flux: ^Flux_Map(T), data: rawptr),
on_update: proc(flux: ^Flux_Map(T), data: rawptr),
on_complete: proc(flux: ^Flux_Map(T), data: rawptr),
}
// init flux map to a float type and a wanted cap
@(require_results)
flux_init :: proc($T: typeid, value_capacity := 8) -> Flux_Map(T) where intrinsics.type_is_float(T) {
return {
values = make(map[^T]Flux_Tween(T), value_capacity),
keys_to_be_deleted = make([dynamic]^T, 0, value_capacity),
}
}
// delete map content
flux_destroy :: proc(flux: Flux_Map($T)) where intrinsics.type_is_float(T) {
delete(flux.values)
delete(flux.keys_to_be_deleted)
}
// clear map content, stops all animations
flux_clear :: proc(flux: ^Flux_Map($T)) where intrinsics.type_is_float(T) {
clear(&flux.values)
}
// append / overwrite existing tween value to parameters
// rest is initialized in flux_tween_init, inside update
// return value can be used to set callbacks
@(require_results)
flux_to :: proc(
flux: ^Flux_Map($T),
value: ^T,
goal: T,
type: Ease = .Quadratic_Out,
duration: time.Duration = time.Second,
delay: f64 = 0,
) -> (tween: ^Flux_Tween(T)) where intrinsics.type_is_float(T) {
if res, ok := &flux.values[value]; ok {
tween = res
} else {
flux.values[value] = {}
tween = &flux.values[value]
}
tween^ = {
value = value,
goal = goal,
duration = duration,
delay = delay,
type = type,
data = value,
}
return
}
// init internal properties
flux_tween_init :: proc(tween: ^Flux_Tween($T), duration: time.Duration) where intrinsics.type_is_float(T) {
tween.inited = true
tween.start = tween.value^
tween.diff = tween.goal - tween.value^
s := time.duration_seconds(duration)
tween.rate = duration > 0 ? 1.0 / s : 0
tween.progress = duration > 0 ? 0 : 1
}
// update all tweens, wait for their delay if one exists
// calls callbacks in all stages, when they're filled
// deletes tween from the map after completion
flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float(T) {
clear(&flux.keys_to_be_deleted)
for key, &tween in flux.values {
delay_remainder := f64(0)
// Update delay if necessary.
if tween.delay > 0 {
tween.delay -= dt
if tween.delay < 0 {
// We finished the delay, but in doing so consumed part of this frame's `dt` budget.
// Keep track of it so we can apply it to this tween without affecting others.
delay_remainder = tween.delay
// We're done with this delay.
tween.delay = 0
}
}
// We either had no delay, or the delay has been consumed.
if tween.delay <= 0 {
if !tween.inited {
flux_tween_init(&tween, tween.duration)
if tween.on_start != nil {
tween.on_start(flux, tween.data)
}
}
// If part of the `dt` budget was consumed this frame, then `delay_remainder` will be
// that remainder, a negative value. Adding it to `dt` applies what's left of the `dt`
// to the tween so it advances properly, instead of too much or little.
tween.progress += tween.rate * (dt + delay_remainder)
x := tween.progress >= 1 ? 1 : ease(tween.type, tween.progress)
tween.value^ = tween.start + tween.diff * T(x)
if tween.on_update != nil {
tween.on_update(flux, tween.data)
}
if tween.progress >= 1 {
// append keys to array that will be deleted after the loop
append(&flux.keys_to_be_deleted, key)
if tween.on_complete != nil {
tween.on_complete(flux, tween.data)
}
}
}
}
// loop through keys that should be deleted from the map
if len(flux.keys_to_be_deleted) != 0 {
for key in flux.keys_to_be_deleted {
delete_key(&flux.values, key)
}
}
}
// stop a specific key inside the map
// returns true when it successfully removed the key
@(require_results)
flux_stop :: proc(flux: ^Flux_Map($T), key: ^T) -> bool where intrinsics.type_is_float(T) {
if key in flux.values {
delete_key(&flux.values, key)
return true
}
return false
}
// returns the amount of time left for the tween animation, if the key exists in the map
// returns 0 if the tween doesnt exist on the map
@(require_results)
flux_tween_time_left :: proc(flux: Flux_Map($T), key: ^T) -> f64 {
if tween, ok := flux.values[key]; ok {
return ((1 - tween.progress) * tween.rate) + tween.delay
} else {
return 0
}
}
+250
View File
@@ -0,0 +1,250 @@
// Inverse easing procedures
// These are the mathematical inverses of the corresponding easing functions,
// allowing you to reverse the transformation:
// if y = ease_fn(x), then x = ease_fn_inverse(y) + some_imprecision
package ease
@require import "core:math"
import "base:intrinsics"
// Helper for handling negative bases with fractional exponents
// since math.pow(negative, fraction) returns NaN
@(private)
_signed_pow :: proc "contextless" (x, exp: $T) -> T where intrinsics.type_is_float(T) {
if x >= 0 {
return math.pow(x, exp)
} else {
return -math.pow(-x, exp)
}
}
@(private) PI_2_INV :: 2 / math.PI
// Inverse of quadratic_in
// x = sqrt(y)
@(require_results)
quadratic_in_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return math.sqrt(p)
}
// Inverse of quadratic_out
// x = 1 - sqrt(1 - y)
@(require_results)
quadratic_out_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return 1 - math.sqrt(1 - p)
}
// Inverse of quadratic_in_out
// x = sqrt(y/2) ; [0, 0.5)
// x = 1 - sqrt((1-y)/2) ; [0.5, 1]
@(require_results)
quadratic_in_out_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
if p < 0.5 {
return math.sqrt(p * 0.5)
} else {
return 1 - math.sqrt((1 - p) * 0.5)
}
}
// Inverse of cubic_in
// x = y^(1/3)
@(require_results)
cubic_in_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return math.pow(p, 1.0/3.0)
}
// Inverse of cubic_out
// x = (y - 1)^(1/3) + 1
@(require_results)
cubic_out_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return _signed_pow(p - 1, 1.0/3.0) + 1
}
// Inverse of cubic_in_out
// x = (y/4)^(1/3) ; [0, 0.5)
// x = ((y-1)*2)^(1/3)/2 + 1 ; [0.5, 1]
@(require_results)
cubic_in_out_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
if p < 0.5 {
return math.pow(p * 0.25, 1.0/3.0)
} else {
return _signed_pow((p - 1) * 2, 1.0/3.0) * 0.5 + 1
}
}
// Inverse of quartic_in
// x = y^(1/4)
@(require_results)
quartic_in_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return math.pow(p, 0.25)
}
// Inverse of quartic_out
// x = 1 - (1 - y)^(1/4)
@(require_results)
quartic_out_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return 1 - math.pow(1 - p, 0.25)
}
// Inverse of quartic_in_out
// x = (y/8)^(1/4) ; [0, 0.5)
// x = 1 - ((1-y)/8)^(1/4) ; [0.5, 1]
@(require_results)
quartic_in_out_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
if p < 0.5 {
return math.pow(p * 0.125, 0.25)
} else {
return 1 - math.pow((1 - p) * 0.125, 0.25)
}
}
// Inverse of quintic_in
// x = y^(1/5)
@(require_results)
quintic_in_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return math.pow(p, 0.2)
}
// Inverse of quintic_out
// x = (y - 1)^(1/5) + 1
@(require_results)
quintic_out_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return _signed_pow(p - 1, 0.2) + 1
}
// Inverse of quintic_in_out
// x = (y/16)^(1/5) ; [0, 0.5)
// x = ((y-1)*2)^(1/5)/2 + 1 ; [0.5, 1]
@(require_results)
quintic_in_out_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
if p < 0.5 {
return math.pow(0.0625 * p, 0.2)
} else {
return _signed_pow((p - 1) * 2, 0.2) * 0.5 + 1
}
}
// Inverse of sine_in
// x = asin(y - 1) * 2/π + 1
@(require_results)
sine_in_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return math.asin(p - 1) * PI_2_INV + 1
}
// Inverse of sine_out
// x = asin(y) * 2/π
@(require_results)
sine_out_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return math.asin(p) * PI_2_INV
}
// Inverse of sine_in_out
// x = acos(1 - 2y) / π
@(require_results)
sine_in_out_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return math.acos(1 - 2*p) / math.PI
}
// Inverse of circular_in
// x = sqrt(2y - y²)
@(require_results)
circular_in_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return math.sqrt(2*p - p*p)
}
// Inverse of circular_out
// x = 1 - sqrt(1 - y²)
@(require_results)
circular_out_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return 1 - math.sqrt(1 - p*p)
}
// Inverse of circular_in_out
// x = sqrt(1 - (1-2y)²) / 2 ; [0, 0.5)
// x = 1 - sqrt(1 - (2y-1)²) / 2 ; [0.5, 1]
@(require_results)
circular_in_out_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
if p < 0.5 {
q := 1 - 2*p
return 0.5 * math.sqrt(1 - q*q)
} else {
q := 2*p - 1
return 1 - 0.5 * math.sqrt(1 - q*q)
}
}
// Inverse of exponential_in
// x = log(y) / 10 + 1
@(require_results)
exponential_in_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return p == 0.0 ? 0.0 : 0.1 * math.log2(p) + 1
}
// Inverse of exponential_out
// x = -log(1 - y) / 10
@(require_results)
exponential_out_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
return p == 1.0 ? 1.0 : 0.1 * -math.log2(1 - p)
}
// Inverse of exponential_in_out
// x = (log(2y) + 10) / 20 ; [0, 0.5)
// x = (10 - log(2(1-y))) / 20 ; [0.5, 1]
@(require_results)
exponential_in_out_inverse :: proc "contextless" (p: $T) -> T where intrinsics.type_is_float(T) {
if p == 0.0 || p == 1.0 {
return p
}
if p < 0.5 {
return 0.05 * (math.log2(2*p) + 10)
} else {
return 0.05 * (10 - math.log2(2*(1-p)))
}
}
// Additional enum variant
@(require_results)
ease_inverse :: proc "contextless" (type: Ease, p: $T) -> T where intrinsics.type_is_float(T) {
switch type {
case .Linear: return p
case .Quadratic_In: return quadratic_in_inverse(p)
case .Quadratic_Out: return quadratic_out_inverse(p)
case .Quadratic_In_Out: return quadratic_in_out_inverse(p)
case .Cubic_In: return cubic_in_inverse(p)
case .Cubic_Out: return cubic_out_inverse(p)
case .Cubic_In_Out: return cubic_in_out_inverse(p)
case .Quartic_In: return quartic_in_inverse(p)
case .Quartic_Out: return quartic_out_inverse(p)
case .Quartic_In_Out: return quartic_in_out_inverse(p)
case .Quintic_In: return quintic_in_inverse(p)
case .Quintic_Out: return quintic_out_inverse(p)
case .Quintic_In_Out: return quintic_in_out_inverse(p)
case .Sine_In: return sine_in_inverse(p)
case .Sine_Out: return sine_out_inverse(p)
case .Sine_In_Out: return sine_in_out_inverse(p)
case .Circular_In: return circular_in_inverse(p)
case .Circular_Out: return circular_out_inverse(p)
case .Circular_In_Out: return circular_in_out_inverse(p)
case .Exponential_In: return exponential_in_inverse(p)
case .Exponential_Out: return exponential_out_inverse(p)
case .Exponential_In_Out: return exponential_in_out_inverse(p)
case .Elastic_In, .Elastic_Out, .Elastic_In_Out,
.Back_In, .Back_Out, .Back_In_Out,
.Bounce_In, .Bounce_Out, .Bounce_In_Out:
// These do not have simple closed-form inverses
return 0
}
// In case type was invalid
return 0
}
+177
View File
@@ -0,0 +1,177 @@
// Flux easing used for animations
package ease
import "core:time"
Flux_Map :: struct($T: typeid) {
values: map[^T]Flux_Tween(T),
keys_to_be_deleted: [dynamic]^T,
}
Flux_Tween :: struct($T: typeid) {
value: ^T,
start: T,
diff: T,
goal: T,
delay: f64, // in seconds
duration: time.Duration,
progress: f64,
rate: f64,
type: Ease,
inited: bool,
// callbacks, data can be set, will be pushed to callback
data: rawptr, // by default gets set to value input
on_start: proc(flux: ^Flux_Map(T), data: rawptr),
on_update: proc(flux: ^Flux_Map(T), data: rawptr),
on_complete: proc(flux: ^Flux_Map(T), data: rawptr),
}
// init flux map to a float type and a wanted cap
@(require_results)
flux_init :: proc($T: typeid, value_capacity := 8, allocator := context.allocator, loc := #caller_location) -> Flux_Map(T) where intrinsics.type_is_float(T) {
return {
values = make(map[^T]Flux_Tween(T), value_capacity, allocator, loc),
keys_to_be_deleted = make([dynamic]^T, 0, value_capacity, allocator, loc),
}
}
// delete map content
flux_destroy :: proc(flux: Flux_Map($T), allocator := context.allocator, loc := #caller_location) where intrinsics.type_is_float(T) {
delete(flux.values, allocator, loc)
delete(flux.keys_to_be_deleted, allocator, loc)
}
// clear map content, stops all animations
flux_clear :: proc(flux: ^Flux_Map($T)) where intrinsics.type_is_float(T) {
clear(&flux.values)
}
// append / overwrite existing tween value to parameters
// rest is initialized in flux_tween_init, inside update
// return value can be used to set callbacks
@(require_results)
flux_to :: proc(
flux: ^Flux_Map($T),
value: ^T,
goal: T,
type: Ease = .Quadratic_Out,
duration: time.Duration = time.Second,
delay: f64 = 0,
) -> (tween: ^Flux_Tween(T)) where intrinsics.type_is_float(T) {
if res, ok := &flux.values[value]; ok {
tween = res
} else {
flux.values[value] = {}
tween = &flux.values[value]
}
tween^ = {
value = value,
goal = goal,
duration = duration,
delay = delay,
type = type,
data = value,
}
return
}
// init internal properties
flux_tween_init :: proc(tween: ^Flux_Tween($T), duration: time.Duration) where intrinsics.type_is_float(T) {
tween.inited = true
tween.start = tween.value^
tween.diff = tween.goal - tween.value^
s := time.duration_seconds(duration)
tween.rate = duration > 0 ? 1.0 / s : 0
tween.progress = duration > 0 ? 0 : 1
}
// update all tweens, wait for their delay if one exists
// calls callbacks in all stages, when they're filled
// deletes tween from the map after completion
flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float(T) {
clear(&flux.keys_to_be_deleted)
for key, &tween in flux.values {
delay_remainder := f64(0)
// Update delay if necessary.
if tween.delay > 0 {
tween.delay -= dt
if tween.delay < 0 {
// We finished the delay, but in doing so consumed part of this frame's `dt` budget.
// Keep track of it so we can apply it to this tween without affecting others.
delay_remainder = tween.delay
// We're done with this delay.
tween.delay = 0
}
}
// We either had no delay, or the delay has been consumed.
if tween.delay <= 0 {
if !tween.inited {
flux_tween_init(&tween, tween.duration)
if tween.on_start != nil {
tween.on_start(flux, tween.data)
}
}
// If part of the `dt` budget was consumed this frame, then `delay_remainder` will be
// that remainder, a negative value. Adding it to `dt` applies what's left of the `dt`
// to the tween so it advances properly, instead of too much or little.
tween.progress += tween.rate * (dt + delay_remainder)
x := tween.progress >= 1 ? 1 : ease(tween.type, tween.progress)
tween.value^ = tween.start + tween.diff * T(x)
if tween.on_update != nil {
tween.on_update(flux, tween.data)
}
if tween.progress >= 1 {
// append keys to array that will be deleted after the loop
append(&flux.keys_to_be_deleted, key)
if tween.on_complete != nil {
tween.on_complete(flux, tween.data)
}
}
}
}
// loop through keys that should be deleted from the map
if len(flux.keys_to_be_deleted) != 0 {
for key in flux.keys_to_be_deleted {
delete_key(&flux.values, key)
}
}
}
// stop a specific key inside the map
// returns true when it successfully removed the key
@(require_results)
flux_stop :: proc(flux: ^Flux_Map($T), key: ^T) -> bool where intrinsics.type_is_float(T) {
if key in flux.values {
delete_key(&flux.values, key)
return true
}
return false
}
// returns the amount of time left for the tween animation, if the key exists in the map
// returns 0 if the tween doesn't exist on the map
@(require_results)
flux_tween_time_left :: proc(flux: Flux_Map($T), key: ^T) -> f64 {
if tween, ok := flux.values[key]; ok {
return ((1 - tween.progress) * tween.rate) + tween.delay
} else {
return 0
}
}
File diff suppressed because it is too large Load Diff
@@ -2,6 +2,42 @@ package math_linalg_hlsl
import "core:math"
@(require_results) cos_half :: proc "c" (x: half) -> half { return math.cos(x) }
@(require_results) sin_half :: proc "c" (x: half) -> half { return math.sin(x) }
@(require_results) tan_half :: proc "c" (x: half) -> half { return math.tan(x) }
@(require_results) acos_half :: proc "c" (x: half) -> half { return math.acos(x) }
@(require_results) asin_half :: proc "c" (x: half) -> half { return math.asin(x) }
@(require_results) atan_half :: proc "c" (x: half) -> half { return math.atan(x) }
@(require_results) atan2_half :: proc "c" (y, x: half) -> half { return math.atan2(y, x) }
@(require_results) cosh_half :: proc "c" (x: half) -> half { return math.cosh(x) }
@(require_results) sinh_half :: proc "c" (x: half) -> half { return math.sinh(x) }
@(require_results) tanh_half :: proc "c" (x: half) -> half { return math.tanh(x) }
@(require_results) acosh_half :: proc "c" (x: half) -> half { return math.acosh(x) }
@(require_results) asinh_half :: proc "c" (x: half) -> half { return math.asinh(x) }
@(require_results) atanh_half :: proc "c" (x: half) -> half { return math.atanh(x) }
@(require_results) sqrt_half :: proc "c" (x: half) -> half { return math.sqrt(x) }
@(require_results) rsqrt_half :: proc "c" (x: half) -> half { return 1.0/math.sqrt(x) }
@(require_results) rcp_half :: proc "c" (x: half) -> half { return 1.0/x }
@(require_results) pow_half :: proc "c" (x, y: half) -> half { return math.pow(x, y) }
@(require_results) exp_half :: proc "c" (x: half) -> half { return math.exp(x) }
@(require_results) log_half :: proc "c" (x: half) -> half { return math.ln(x) }
@(require_results) log2_half :: proc "c" (x: half) -> half { return math.log(x, 2) }
@(require_results) log10_half :: proc "c" (x: half) -> half { return math.log(x, 10) }
@(require_results) exp2_half :: proc "c" (x: half) -> half { return math.pow(half(2), x) }
@(require_results) sign_half :: proc "c" (x: half) -> half { return math.sign(x) }
@(require_results) floor_half :: proc "c" (x: half) -> half { return math.floor(x) }
@(require_results) round_half :: proc "c" (x: half) -> half { return math.round(x) }
@(require_results) ceil_half :: proc "c" (x: half) -> half { return math.ceil(x) }
@(require_results) isnan_half :: proc "c" (x: half) -> bool { return math.classify(x) == .NaN}
@(require_results) fmod_half :: proc "c" (x, y: half) -> half { return math.mod(x, y) }
@(require_results)
frac_half :: proc "c" (x: half) -> half {
if x >= 0 {
return x - math.trunc(x)
}
return math.trunc(-x) + x
}
@(require_results) cos_float :: proc "c" (x: float) -> float { return math.cos(x) }
@(require_results) sin_float :: proc "c" (x: float) -> float { return math.sin(x) }
@(require_results) tan_float :: proc "c" (x: float) -> float { return math.tan(x) }
+4 -4
View File
@@ -208,7 +208,7 @@ Inputs:
Returns:
- val: A random 31 bit value in the range `[0, n)`
WARNING: Panics if n is less than 0
WARNING: Panics if n is less than or equal to 0
Example:
import "core:math/rand"
@@ -249,7 +249,7 @@ Inputs:
Returns:
- val: A random 63 bit value in the range `[0, n)`
WARNING: Panics if n is less than 0
WARNING: Panics if n is less than or equal to 0
Example:
import "core:math/rand"
@@ -290,7 +290,7 @@ Inputs:
Returns:
- val: A random 127 bit value in the range `[0, n)`
WARNING: Panics if n is less than 0
WARNING: Panics if n is less than or equal to 0
Example:
import "core:math/rand"
@@ -331,7 +331,7 @@ Inputs:
Returns:
- val: A random integer value in the range `[0, n)`
WARNING: Panics if n is less than 0
WARNING: Panics if n is less than or equal to 0
Example:
import "core:math/rand"
+2 -2
View File
@@ -99,8 +99,8 @@ panic_allocator :: proc() -> Allocator {
panic_allocator_proc :: proc(
allocator_data: rawptr,
mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr,
size, alignment: int,
old_memory: rawptr,
old_size: int,
loc := #caller_location,
) -> ([]byte, Allocator_Error) {
+2 -2
View File
@@ -332,7 +332,7 @@ and returns an integer count of the `T` between them.
- `b`: A pointer to a type T
**Returns**
- `b` - `a` in items of T as an `int`.
- `a` - `b` in items of T as an `int`.
Example:
@@ -704,4 +704,4 @@ calc_padding_with_header :: proc "contextless" (ptr: uintptr, align: uintptr, he
}
}
return int(padding)
}
}
+1 -1
View File
@@ -3,7 +3,7 @@ package mem_tlsf
/*
Copyright 2024 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under tlsf's LICENSE (BSD 3-clause).
List of contributors:
Matt Conte: Original C implementation, see LICENSE file in this package
+1 -1
View File
@@ -1,6 +1,6 @@
/*
Copyright 2024 Jeroen van Rijn <nom@duclavier.com>.
Made available under Odin's BSD-3 license.
Made available under tlsf's LICENSE (BSD 3-clause).
List of contributors:
Matt Conte: Original C implementation, see LICENSE file in this package
+1 -1
View File
@@ -11,7 +11,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -14,7 +14,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -12,7 +12,7 @@ package net
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Copyright 2025 Christiano Haesbaert <haesbaert@haesbaert.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -10,7 +10,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -11,7 +11,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -35,7 +35,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -11,7 +11,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -11,7 +11,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -11,7 +11,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -11,7 +11,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -11,7 +11,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -11,7 +11,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -11,7 +11,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -11,7 +11,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -11,7 +11,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -11,7 +11,7 @@ package net
Copyright 2022-2023 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022-2023 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -11,7 +11,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -11,7 +11,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -11,7 +11,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -11,7 +11,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+1 -1
View File
@@ -9,7 +9,7 @@ package net
Copyright 2022 Colin Davidson <colrdavidson@gmail.com>
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
Copyright 2024 Feoramund <rune@swevencraft.org>.
Made available under Odin's BSD-3 license.
Made available under Odin's license.
List of contributors:
Tetralux: Initial implementation
+17 -8
View File
@@ -99,10 +99,8 @@ end_pos :: proc(tok: tokenizer.Token) -> tokenizer.Pos {
pos := tok.pos
pos.offset += len(tok.text)
if tok.kind == .Comment {
if tok.text[:2] != "/*" {
pos.column += len(tok.text)
} else {
if tok.kind == .Comment || tok.kind == .String {
if tok.text[:2] == "/*" || tok.text[:1] == "`" {
for i := 0; i < len(tok.text); i += 1 {
c := tok.text[i]
if c == '\n' {
@@ -112,6 +110,8 @@ end_pos :: proc(tok: tokenizer.Token) -> tokenizer.Pos {
pos.column += 1
}
}
} else {
pos.column += len(tok.text)
}
} else {
pos.column += len(tok.text)
@@ -3210,6 +3210,17 @@ parse_call_expr :: proc(p: ^Parser, operand: ^ast.Expr) -> ^ast.Expr {
return ce
}
empty_selector_expr :: proc(tok: tokenizer.Token, operand: ^ast.Expr) -> ^ast.Selector_Expr {
field := ast.new(ast.Ident, tok.pos, end_pos(tok))
field.name = ""
sel := ast.new(ast.Selector_Expr, operand.pos, field)
sel.expr = operand
sel.op = tok
sel.field = field
return sel
}
parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^ast.Expr) {
operand = value
@@ -3343,8 +3354,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
case:
error(p, p.curr_tok.pos, "expected a selector")
advance_token(p)
operand = ast.new(ast.Bad_Expr, operand.pos, end_pos(tok))
operand = empty_selector_expr(tok, operand)
}
case .Arrow_Right:
@@ -3361,8 +3371,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
operand = sel
case:
error(p, p.curr_tok.pos, "expected a selector")
advance_token(p)
operand = ast.new(ast.Bad_Expr, operand.pos, end_pos(tok))
operand = empty_selector_expr(tok, operand)
}
case .Pointer:
+14
View File
@@ -6,6 +6,10 @@ import "core:strings"
read_dir :: read_directory
/*
Reads the file `f` (assuming it is a directory) and returns the unsorted directory entries.
This returns up to `n` entries OR all of them if `n <= 0`.
*/
@(require_results)
read_directory :: proc(f: ^File, n: int, allocator: runtime.Allocator) -> (files: []File_Info, err: Error) {
if f == nil {
@@ -47,11 +51,18 @@ read_directory :: proc(f: ^File, n: int, allocator: runtime.Allocator) -> (files
}
/*
Reads the file `f` (assuming it is a directory) and returns all of the unsorted directory entries.
*/
@(require_results)
read_all_directory :: proc(f: ^File, allocator: runtime.Allocator) -> (fi: []File_Info, err: Error) {
return read_directory(f, -1, allocator)
}
/*
Reads the named directory by path (assuming it is a directory) and returns the unsorted directory entries.
This returns up to `n` entries OR all of them if `n <= 0`.
*/
@(require_results)
read_directory_by_path :: proc(path: string, n: int, allocator: runtime.Allocator) -> (fi: []File_Info, err: Error) {
f := open(path) or_return
@@ -59,6 +70,9 @@ read_directory_by_path :: proc(path: string, n: int, allocator: runtime.Allocato
return read_directory(f, n, allocator)
}
/*
Reads the named directory by path (assuming it is a directory) and returns all of the unsorted directory entries.
*/
@(require_results)
read_all_directory_by_path :: proc(path: string, allocator: runtime.Allocator) -> (fi: []File_Info, err: Error) {
return read_directory_by_path(path, -1, allocator)
+1 -1
View File
@@ -18,7 +18,7 @@ find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW, al
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
path := concatenate({base_path, `\`, win32_wstring_to_utf8(cstring16(raw_data(d.cFileName[:])), temp_allocator) or_else ""}, allocator) or_return
handle := win32.HANDLE(_open_internal(path, {.Read}, 0o666) or_else 0)
handle := win32.HANDLE(_open_internal(path, {.Read}, Permissions_Read_Write_All) or_else 0)
defer win32.CloseHandle(handle)
fi.fullpath = path
+24
View File
@@ -3,6 +3,10 @@ package os2
import "core:io"
import "base:runtime"
/*
General errors that are common within this package which cannot
be categorized by `io.Error` nor `runtime.Allocator_Error`.
*/
General_Error :: enum u32 {
None,
@@ -33,8 +37,12 @@ General_Error :: enum u32 {
Unsupported,
}
// A platform specific error
Platform_Error :: _Platform_Error
/*
`Error` is a union of different classes of errors that could be returned from procedures in this package.
*/
Error :: union #shared_nil {
General_Error,
io.Error,
@@ -46,6 +54,7 @@ Error :: union #shared_nil {
ERROR_NONE :: Error{}
// Attempts to convert an `Error` into a platform specific error as an integer. `ok` is false if not possible
@(require_results)
is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) {
v := ferr.(Platform_Error) or_else {}
@@ -53,6 +62,7 @@ is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) {
}
// Attempts to return the error `ferr` as a string without any allocation
@(require_results)
error_string :: proc(ferr: Error) -> string {
if ferr == nil {
@@ -112,6 +122,9 @@ error_string :: proc(ferr: Error) -> string {
return "unknown error"
}
/*
`print_error` is a utility procedure which will print an error `ferr` to a specified file `f`.
*/
print_error :: proc(f: ^File, ferr: Error, msg: string) {
temp_allocator := TEMP_ALLOCATOR_GUARD({})
err_str := error_string(ferr)
@@ -127,3 +140,14 @@ print_error :: proc(f: ^File, ferr: Error, msg: string) {
buf[length - 1] = '\n'
write(f, buf)
}
// Attempts to convert an `Error` `ferr` into an `io.Error`
@(private)
error_to_io_error :: proc(ferr: Error) -> io.Error {
if ferr == nil {
return .None
}
return ferr.(io.Error) or_else .Unknown
}
+198 -13
View File
@@ -56,6 +56,7 @@ File_Type :: enum {
Character_Device,
}
// Represents the file flags for a file handle
File_Flags :: distinct bit_set[File_Flag; uint]
File_Flag :: enum {
Read,
@@ -90,17 +91,77 @@ O_SPARSE :: File_Flags{.Sparse}
*/
O_INHERITABLE :: File_Flags{.Inheritable}
stdin: ^File = nil // OS-Specific
stdout: ^File = nil // OS-Specific
stderr: ^File = nil // OS-Specific
Permissions :: distinct bit_set[Permission_Flag; u32]
Permission_Flag :: enum u32 {
Execute_Other = 0,
Write_Other = 1,
Read_Other = 2,
@(require_results)
create :: proc(name: string) -> (^File, Error) {
return open(name, {.Read, .Write, .Create}, 0o777)
Execute_Group = 3,
Write_Group = 4,
Read_Group = 5,
Execute_User = 6,
Write_User = 7,
Read_User = 8,
}
Permissions_Execute_All :: Permissions{.Execute_User, .Execute_Group, .Execute_Other}
Permissions_Write_All :: Permissions{.Write_User, .Write_Group, .Write_Other}
Permissions_Read_All :: Permissions{.Read_User, .Read_Group, .Read_Other}
Permissions_Read_Write_All :: Permissions_Read_All + Permissions_Write_All
Permissions_All :: Permissions_Read_All + Permissions_Write_All + Permissions_Execute_All
Permissions_Default_File :: Permissions_Read_All + Permissions_Write_All
Permissions_Default_Directory :: Permissions_Read_All + Permissions_Write_All + Permissions_Execute_All
Permissions_Default :: Permissions_Default_Directory
perm :: proc{
perm_number,
}
/*
`perm_number` converts an integer value `perm` to the bit set `Permissions`
*/
@(require_results)
open :: proc(name: string, flags := File_Flags{.Read}, perm := 0o777) -> (^File, Error) {
perm_number :: proc "contextless" (perm: int) -> Permissions {
return transmute(Permissions)u32(perm & 0o777)
}
// `stdin` is an open file pointing to the standard input file stream
stdin: ^File = nil // OS-Specific
// `stdout` is an open file pointing to the standard output file stream
stdout: ^File = nil // OS-Specific
// `stderr` is an open file pointing to the standard error file stream
stderr: ^File = nil // OS-Specific
/*
`create` creates or truncates a named file `name`.
If the file already exists, it is truncated.
If the file does not exist, it is created with the `Permissions_Default_File` permissions.
If successful, a `^File` is return which can be used for I/O.
And error is returned if any is encountered.
*/
@(require_results)
create :: proc(name: string) -> (^File, Error) {
return open(name, {.Read, .Write, .Create, .Trunc}, Permissions_Default_File)
}
/*
`open` is a generalized open call, which defaults to opening for reading.
If the file does not exist, and the `{.Create}` flag is passed, it is created with the permissions `perm`,
and please note that the containing directory must exist otherwise and an error will be returned.
If successful, a `^File` is return which can be used for I/O.
And error is returned if any is encountered.
*/
@(require_results)
open :: proc(name: string, flags := File_Flags{.Read}, perm := Permissions_Default) -> (^File, Error) {
return _open(name, flags, perm)
}
@@ -112,7 +173,10 @@ open :: proc(name: string, flags := File_Flags{.Read}, perm := 0o777) -> (^File,
// return _open_buffered(name, buffer_size, flags, perm)
// }
/*
`new_file` returns a new `^File` with the given file descriptor `handle` and `name`.
The return value will only be `nil` IF the `handle` is not a valid file descriptor.
*/
@(require_results)
new_file :: proc(handle: uintptr, name: string) -> ^File {
file, err := _new_file(handle, name, file_allocator())
@@ -122,16 +186,25 @@ new_file :: proc(handle: uintptr, name: string) -> ^File {
return file
}
/*
`clone` returns a new `^File` based on the passed file `f` with the same underlying file descriptor.
*/
@(require_results)
clone :: proc(f: ^File) -> (^File, Error) {
return _clone(f)
}
/*
`fd` returns the file descriptor of the file `f` passed. If the file is not valid, an invalid handle will be returned.
*/
@(require_results)
fd :: proc(f: ^File) -> uintptr {
return _fd(f)
}
/*
`name` returns the name of the file. The lifetime of this string lasts as long as the file handle itself.
*/
@(require_results)
name :: proc(f: ^File) -> string {
return _name(f)
@@ -150,6 +223,16 @@ close :: proc(f: ^File) -> Error {
return nil
}
/*
seek sets the offsets for the next read or write on a file to a specified `offset`,
according to what `whence` is set.
`.Start` is relative to the origin of the file.
`.Current` is relative to the current offset.
`.End` is relative to the end.
It returns the new offset and an error, if any is encountered.
Prefer `read_at` or `write_at` if the offset does not want to be changed.
*/
seek :: proc(f: ^File, offset: i64, whence: io.Seek_From) -> (ret: i64, err: Error) {
if f != nil {
return io.seek(f.stream, offset, whence)
@@ -157,6 +240,11 @@ seek :: proc(f: ^File, offset: i64, whence: io.Seek_From) -> (ret: i64, err: Err
return 0, .Invalid_File
}
/*
`read` reads up to len(p) bytes from the file `f`, and then stores them in `p`.
It returns the number of bytes read and an error, if any is encountered.
At the end of a file, it returns `0, io.EOF`.
*/
read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
if f != nil {
return io.read(f.stream, p)
@@ -164,6 +252,12 @@ read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
return 0, .Invalid_File
}
/*
`read_at` reads up to len(p) bytes from the file `f` at the byte offset `offset`, and then stores them in `p`.
It returns the number of bytes read and an error, if any is encountered.
`read_at` always returns a non-nil error when `n < len(p)`.
At the end of a file, the error is `io.EOF`.
*/
read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
if f != nil {
return io.read_at(f.stream, p, offset)
@@ -171,6 +265,11 @@ read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
return 0, .Invalid_File
}
/*
`write` writes `len(p)` bytes from `p` to the file `f`. It returns the number of bytes written to
and an error, if any is encountered.
`write` returns a non-nil error when `n != len(p)`.
*/
write :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
if f != nil {
return io.write(f.stream, p)
@@ -178,6 +277,11 @@ write :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
return 0, .Invalid_File
}
/*
`write_at` writes `len(p)` bytes from `p` to the file `f` starting at byte offset `offset`.
It returns the number of bytes written to and an error, if any is encountered.
`write_at` returns a non-nil error when `n != len(p)`.
*/
write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
if f != nil {
return io.write_at(f.stream, p, offset)
@@ -185,6 +289,9 @@ write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
return 0, .Invalid_File
}
/*
`file_size` returns the length of the file `f` in bytes and an error, if any is encountered.
*/
file_size :: proc(f: ^File) -> (n: i64, err: Error) {
if f != nil {
return io.size(f.stream)
@@ -192,6 +299,9 @@ file_size :: proc(f: ^File) -> (n: i64, err: Error) {
return 0, .Invalid_File
}
/*
`flush` flushes a file `f`
*/
flush :: proc(f: ^File) -> Error {
if f != nil {
return io.flush(f.stream)
@@ -199,31 +309,54 @@ flush :: proc(f: ^File) -> Error {
return nil
}
/*
`sync` commits the current contents of the file `f` to stable storage.
This usually means flushing the file system's in-memory copy to disk.
*/
sync :: proc(f: ^File) -> Error {
return _sync(f)
}
/*
`truncate` changes the size of the file `f` to `size` in bytes.
This can be used to shorten or lengthen a file.
It does not change the "offset" of the file.
*/
truncate :: proc(f: ^File, size: i64) -> Error {
return _truncate(f, size)
}
/*
`remove` removes a named file or (empty) directory.
*/
remove :: proc(name: string) -> Error {
return _remove(name)
}
/*
`rename` renames (moves) `old_path` to `new_path`.
*/
rename :: proc(old_path, new_path: string) -> Error {
return _rename(old_path, new_path)
}
/*
`link` creates a `new_name` as a hard link to the `old_name` file.
*/
link :: proc(old_name, new_name: string) -> Error {
return _link(old_name, new_name)
}
/*
`symlink` creates a `new_name` as a symbolic link to the `old_name` file.
*/
symlink :: proc(old_name, new_name: string) -> Error {
return _symlink(old_name, new_name)
}
/*
`read_link` returns the destinction of the named symbolic link `name`.
*/
read_link :: proc(name: string, allocator: runtime.Allocator) -> (string, Error) {
return _read_link(name,allocator)
}
@@ -231,36 +364,65 @@ read_link :: proc(name: string, allocator: runtime.Allocator) -> (string, Error)
chdir :: change_directory
/*
Changes the current working directory to the named directory.
*/
change_directory :: proc(name: string) -> Error {
return _chdir(name)
}
chmod :: change_mode
change_mode :: proc(name: string, mode: int) -> Error {
/*
Changes the mode/permissions of the named file to `mode`.
If the file is a symbolic link, it changes the mode of the link's target.
On Windows, only `{.Write_User}` of `mode` is used, and controls whether or not
the file has a read-only attribute. Use `{.Read_User}` for a read-only file and
`{.Read_User, .Write_User}` for a readable & writable file.
*/
change_mode :: proc(name: string, mode: Permissions) -> Error {
return _chmod(name, mode)
}
chown :: change_owner
/*
Changes the numeric `uid` and `gid` of a named file. If the file is a symbolic link,
it changes the `uid` and `gid` of the link's target.
On Windows, it always returns an error.
*/
change_owner :: proc(name: string, uid, gid: int) -> Error {
return _chown(name, uid, gid)
}
fchdir :: fchange_directory
/*
Changes the current working directory to the file, which must be a directory.
*/
fchange_directory :: proc(f: ^File) -> Error {
return _fchdir(f)
}
fchmod :: fchange_mode
fchange_mode :: proc(f: ^File, mode: int) -> Error {
/*
Changes the current `mode` permissions of the file `f`.
*/
fchange_mode :: proc(f: ^File, mode: Permissions) -> Error {
return _fchmod(f, mode)
}
fchown :: fchange_owner
/*
Changes the numeric `uid` and `gid` of the file `f`. If the file is a symbolic link,
it changes the `uid` and `gid` of the link's target.
On Windows, it always returns an error.
*/
fchange_owner :: proc(f: ^File, uid, gid: int) -> Error {
return _fchown(f, uid, gid)
}
@@ -268,27 +430,45 @@ fchange_owner :: proc(f: ^File, uid, gid: int) -> Error {
lchown :: change_owner_do_not_follow_links
/*
Changes the numeric `uid` and `gid` of the file `f`. If the file is a symbolic link,
it changes the `uid` and `gid` of the lin itself.
On Windows, it always returns an error.
*/
change_owner_do_not_follow_links :: proc(name: string, uid, gid: int) -> Error {
return _lchown(name, uid, gid)
}
chtimes :: change_times
/*
Changes the access `atime` and modification `mtime` times of a named file.
*/
change_times :: proc(name: string, atime, mtime: time.Time) -> Error {
return _chtimes(name, atime, mtime)
}
fchtimes :: fchange_times
/*
Changes the access `atime` and modification `mtime` times of the file `f`.
*/
fchange_times :: proc(f: ^File, atime, mtime: time.Time) -> Error {
return _fchtimes(f, atime, mtime)
}
/*
`exists` returns whether or not a named file exists.
*/
@(require_results)
exists :: proc(path: string) -> bool {
return _exists(path)
}
/*
`is_file` returns whether or not the type of a named file is a `File_Type.Regular` file.
*/
@(require_results)
is_file :: proc(path: string) -> bool {
temp_allocator := TEMP_ALLOCATOR_GUARD({})
@@ -301,6 +481,9 @@ is_file :: proc(path: string) -> bool {
is_dir :: is_directory
/*
Returns whether or not the type of a named file is a `File_Type.Directory` file.
*/
@(require_results)
is_directory :: proc(path: string) -> bool {
temp_allocator := TEMP_ALLOCATOR_GUARD({})
@@ -311,7 +494,9 @@ is_directory :: proc(path: string) -> bool {
return fi.type == .Directory
}
/*
`copy_file` copies a file from `src_path` to `dst_path` and returns an error if any was encountered.
*/
copy_file :: proc(dst_path, src_path: string) -> Error {
when #defined(_copy_file_native) {
return _copy_file_native(dst_path, src_path)
@@ -331,7 +516,7 @@ _copy_file :: proc(dst_path, src_path: string) -> Error {
return .Invalid_File
}
dst := open(dst_path, {.Read, .Write, .Create, .Trunc}, info.mode & 0o777) or_return
dst := open(dst_path, {.Read, .Write, .Create, .Trunc}, info.mode & Permissions_All) or_return
defer close(dst)
_, err := io.copy(to_writer(dst), to_reader(src))
+11 -11
View File
@@ -65,7 +65,7 @@ _standard_stream_init :: proc "contextless" () {
stderr = new_std(&files[2], 2, "/proc/self/fd/2")
}
_open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) {
_open :: proc(name: string, flags: File_Flags, perm: Permissions) -> (f: ^File, err: Error) {
temp_allocator := TEMP_ALLOCATOR_GUARD({})
name_cstr := clone_to_cstring(name, temp_allocator) or_return
@@ -88,7 +88,7 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err
if .Trunc in flags { sys_flags += {.TRUNC} }
if .Inheritable in flags { sys_flags -= {.CLOEXEC} }
fd, errno := linux.open(name_cstr, sys_flags, transmute(linux.Mode)u32(perm))
fd, errno := linux.open(name_cstr, sys_flags, transmute(linux.Mode)transmute(u32)perm)
if errno != .NONE {
return nil, _get_platform_error(errno)
}
@@ -132,7 +132,7 @@ _clone :: proc(f: ^File) -> (clone: ^File, err: Error) {
@(require_results)
_open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm := 0o777) -> (f: ^File, err: Error) {
_open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm: Permissions) -> (f: ^File, err: Error) {
assert(buffer_size > 0)
f, err = _open(name, flags, perm)
if f != nil && err == nil {
@@ -198,7 +198,7 @@ _seek :: proc(f: ^File_Impl, offset: i64, whence: io.Seek_From) -> (ret: i64, er
case .NONE:
return n, nil
case:
return -1, _get_platform_error(errno)
return 0, _get_platform_error(errno)
}
}
@@ -209,7 +209,7 @@ _read :: proc(f: ^File_Impl, p: []byte) -> (i64, Error) {
n, errno := linux.read(f.fd, p[:min(len(p), MAX_RW)])
if errno != .NONE {
return -1, _get_platform_error(errno)
return 0, _get_platform_error(errno)
}
return i64(n), io.Error.EOF if n == 0 else nil
}
@@ -223,7 +223,7 @@ _read_at :: proc(f: ^File_Impl, p: []byte, offset: i64) -> (i64, Error) {
}
n, errno := linux.pread(f.fd, p[:min(len(p), MAX_RW)], offset)
if errno != .NONE {
return -1, _get_platform_error(errno)
return 0, _get_platform_error(errno)
}
if n == 0 {
return 0, .EOF
@@ -276,7 +276,7 @@ _file_size :: proc(f: ^File_Impl) -> (n: i64, err: Error) {
s: linux.Stat = ---
errno := linux.fstat(f.fd, &s)
if errno != .NONE {
return -1, _get_platform_error(errno)
return 0, _get_platform_error(errno)
}
if s.mode & linux.S_IFMT == linux.S_IFREG {
@@ -369,15 +369,15 @@ _fchdir :: proc(f: ^File) -> Error {
return _get_platform_error(linux.fchdir(impl.fd))
}
_chmod :: proc(name: string, mode: int) -> Error {
_chmod :: proc(name: string, mode: Permissions) -> Error {
temp_allocator := TEMP_ALLOCATOR_GUARD({})
name_cstr := clone_to_cstring(name, temp_allocator) or_return
return _get_platform_error(linux.chmod(name_cstr, transmute(linux.Mode)(u32(mode))))
return _get_platform_error(linux.chmod(name_cstr, transmute(linux.Mode)transmute(u32)mode))
}
_fchmod :: proc(f: ^File, mode: int) -> Error {
_fchmod :: proc(f: ^File, mode: Permissions) -> Error {
impl := (^File_Impl)(f.impl)
return _get_platform_error(linux.fchmod(impl.fd, transmute(linux.Mode)(u32(mode))))
return _get_platform_error(linux.fchmod(impl.fd, transmute(linux.Mode)transmute(u32)mode))
}
// NOTE: will throw error without super user priviledges
+21 -14
View File
@@ -46,7 +46,7 @@ init_std_files :: proc "contextless" () {
stderr = new_std(&files[2], posix.STDERR_FILENO, "/dev/stderr")
}
_open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) {
_open :: proc(name: string, flags: File_Flags, perm: Permissions) -> (f: ^File, err: Error) {
if name == "" {
err = .Invalid_Path
return
@@ -72,7 +72,7 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err
temp_allocator := TEMP_ALLOCATOR_GUARD({})
cname := clone_to_cstring(name, temp_allocator) or_return
fd := posix.open(cname, sys_flags, transmute(posix.mode_t)posix._mode_t(perm))
fd := posix.open(cname, sys_flags, transmute(posix.mode_t)posix._mode_t(transmute(u32)perm))
if fd < 0 {
err = _get_platform_error()
return
@@ -284,17 +284,17 @@ _fchdir :: proc(f: ^File) -> Error {
return nil
}
_fchmod :: proc(f: ^File, mode: int) -> Error {
if posix.fchmod(__fd(f), transmute(posix.mode_t)posix._mode_t(mode)) != .OK {
_fchmod :: proc(f: ^File, mode: Permissions) -> Error {
if posix.fchmod(__fd(f), transmute(posix.mode_t)posix._mode_t(transmute(u32)mode)) != .OK {
return _get_platform_error()
}
return nil
}
_chmod :: proc(name: string, mode: int) -> (err: Error) {
_chmod :: proc(name: string, mode: Permissions) -> (err: Error) {
temp_allocator := TEMP_ALLOCATOR_GUARD({})
cname := clone_to_cstring(name, temp_allocator) or_return
if posix.chmod(cname, transmute(posix.mode_t)posix._mode_t(mode)) != .OK {
if posix.chmod(cname, transmute(posix.mode_t)posix._mode_t(transmute(u32)mode)) != .OK {
return _get_platform_error()
}
return nil
@@ -382,12 +382,14 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
}
to_read := uint(min(len(p), MAX_RW))
n = i64(posix.read(fd, raw_data(p), to_read))
_n := i64(posix.read(fd, raw_data(p), to_read))
switch {
case n == 0:
case _n == 0:
err = .EOF
case n < 0:
case _n < 0:
err = .Unknown
case:
n = _n
}
return
@@ -402,12 +404,14 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
}
to_read := uint(min(len(p), MAX_RW))
n = i64(posix.pread(fd, raw_data(p), to_read, posix.off_t(offset)))
_n := i64(posix.pread(fd, raw_data(p), to_read, posix.off_t(offset)))
switch {
case n == 0:
case _n == 0:
err = .EOF
case n < 0:
case _n < 0:
err = .Unknown
case:
n = _n
}
return
@@ -460,15 +464,18 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
return
}
n = i64(posix.lseek(fd, posix.off_t(offset), posix.Whence(whence)))
if n < 0 {
_n := i64(posix.lseek(fd, posix.off_t(offset), posix.Whence(whence)))
if _n < 0 {
#partial switch posix.get_errno() {
case .EINVAL:
err = .Invalid_Offset
case:
err = .Unknown
}
return
}
n = _n
return
case .Size:
+1 -1
View File
@@ -8,7 +8,7 @@ import "core:sys/posix"
_posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allocator) -> (path: cstring, err: Error) {
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
cname := clone_to_cstring(name, temp_allocator)
cname := clone_to_cstring(name, temp_allocator) or_return
buf: [posix.PATH_MAX]byte
path = posix.realpath(cname, raw_data(buf[:]))
+12 -9
View File
@@ -2,6 +2,7 @@ package os2
import "core:io"
// Converts a file `f` into an `io.Stream`
to_stream :: proc(f: ^File) -> (s: io.Stream) {
if f != nil {
assert(f.stream.procedure != nil)
@@ -10,14 +11,16 @@ to_stream :: proc(f: ^File) -> (s: io.Stream) {
return
}
/*
This is an alias of `to_stream` which converts a file `f` to an `io.Stream`.
It can be useful to indicate what the stream is meant to be used for as a writer,
even if it has no logical difference.
*/
to_writer :: to_stream
/*
This is an alias of `to_stream` which converts a file `f` to an `io.Stream`.
It can be useful to indicate what the stream is meant to be used for as a reader,
even if it has no logical difference.
*/
to_reader :: to_stream
@(private)
error_to_io_error :: proc(ferr: Error) -> io.Error {
if ferr == nil {
return .None
}
return ferr.(io.Error) or_else .Unknown
}
+94 -19
View File
@@ -4,10 +4,18 @@ import "base:runtime"
import "core:strconv"
import "core:unicode/utf8"
/*
`write_string` writes a string `s` to file `f`.
Returns the number of bytes written and an error, if any is encountered.
*/
write_string :: proc(f: ^File, s: string) -> (n: int, err: Error) {
return write(f, transmute([]byte)s)
}
/*
`write_strings` writes a variadic list of strings `strings` to file `f`.
Returns the number of bytes written and an error, if any is encountered.
*/
write_strings :: proc(f: ^File, strings: ..string) -> (n: int, err: Error) {
for s in strings {
m: int
@@ -19,11 +27,18 @@ write_strings :: proc(f: ^File, strings: ..string) -> (n: int, err: Error) {
}
return
}
/*
`write_byte` writes a byte `b` to file `f`.
Returns the number of bytes written and an error, if any is encountered.
*/
write_byte :: proc(f: ^File, b: byte) -> (n: int, err: Error) {
return write(f, []byte{b})
}
/*
`write_rune` writes a rune `r` as an UTF-8 encoded string to file `f`.
Returns the number of bytes written and an error, if any is encountered.
*/
write_rune :: proc(f: ^File, r: rune) -> (n: int, err: Error) {
if r < utf8.RUNE_SELF {
return write_byte(f, byte(r))
@@ -34,6 +49,10 @@ write_rune :: proc(f: ^File, r: rune) -> (n: int, err: Error) {
return write(f, b[:n])
}
/*
`write_encoded_rune` writes a rune `r` as an UTF-8 encoded string which with escaped control codes to file `f`.
Returns the number of bytes written and an error, if any is encountered.
*/
write_encoded_rune :: proc(f: ^File, r: rune) -> (n: int, err: Error) {
wrap :: proc(m: int, merr: Error, n: ^int, err: ^Error) -> bool {
n^ += m
@@ -73,6 +92,31 @@ write_encoded_rune :: proc(f: ^File, r: rune) -> (n: int, err: Error) {
return
}
/*
`write_ptr` is a utility procedure that writes the bytes points at `data` with length `len`.
It is equivalent to: `write(f, ([^]byte)(data)[:len])`
*/
write_ptr :: proc(f: ^File, data: rawptr, len: int) -> (n: int, err: Error) {
return write(f, ([^]byte)(data)[:len])
}
/*
`read_ptr` is a utility procedure that reads the bytes points at `data` with length `len`.
It is equivalent to: `read(f, ([^]byte)(data)[:len])`
*/
read_ptr :: proc(f: ^File, data: rawptr, len: int) -> (n: int, err: Error) {
return read(f, ([^]byte)(data)[:len])
}
/*
`read_at_least` reads from `f` into `buf` until it has read at least `min` bytes.
It returns the number of bytes copied and an error if fewer bytes were read.
The error is only an `io.EOF` if no bytes were read.
*/
read_at_least :: proc(f: ^File, buf: []byte, min: int) -> (n: int, err: Error) {
if len(buf) < min {
return 0, .Short_Buffer
@@ -88,17 +132,17 @@ read_at_least :: proc(f: ^File, buf: []byte, min: int) -> (n: int, err: Error) {
return
}
/*
`read_full` reads exactly `len(buf)` bytes from `f` into `buf`.
It returns the number of bytes copied and an error if fewer bytes were read.
The error is only an `io.EOF` if no bytes were read.
It is equivalent to `read_at_least(f, buf, len(buf))`.
*/
read_full :: proc(f: ^File, buf: []byte) -> (n: int, err: Error) {
return read_at_least(f, buf, len(buf))
}
write_ptr :: proc(f: ^File, data: rawptr, len: int) -> (n: int, err: Error) {
return write(f, ([^]byte)(data)[:len])
}
read_ptr :: proc(f: ^File, data: rawptr, len: int) -> (n: int, err: Error) {
return read(f, ([^]byte)(data)[:len])
}
read_entire_file :: proc{
@@ -106,18 +150,23 @@ read_entire_file :: proc{
read_entire_file_from_file,
}
/*
`read_entire_file_from_path` reads the entire named file `name` into memory allocated with `allocator`.
A slice of bytes and an error is returned, if any error is encountered.
*/
@(require_results)
read_entire_file_from_path :: proc(name: string, allocator: runtime.Allocator) -> (data: []byte, err: Error) {
f, ferr := open(name)
if ferr != nil {
return nil, ferr
}
read_entire_file_from_path :: proc(name: string, allocator: runtime.Allocator, loc := #caller_location) -> (data: []byte, err: Error) {
f := open(name) or_return
defer close(f)
return read_entire_file_from_file(f, allocator)
return read_entire_file_from_file(f, allocator, loc)
}
/*
`read_entire_file_from_file` reads the entire file `f` into memory allocated with `allocator`.
A slice of bytes and an error is returned, if any error is encountered.
*/
@(require_results)
read_entire_file_from_file :: proc(f: ^File, allocator: runtime.Allocator) -> (data: []byte, err: Error) {
read_entire_file_from_file :: proc(f: ^File, allocator: runtime.Allocator, loc := #caller_location) -> (data: []byte, err: Error) {
size: int
has_size := false
if size64, serr := file_size(f); serr == nil {
@@ -129,7 +178,7 @@ read_entire_file_from_file :: proc(f: ^File, allocator: runtime.Allocator) -> (d
if has_size && size > 0 {
total: int
data = make([]byte, size, allocator) or_return
data = make([]byte, size, allocator, loc) or_return
for total < len(data) {
n: int
n, err = read(f, data[total:])
@@ -145,13 +194,13 @@ read_entire_file_from_file :: proc(f: ^File, allocator: runtime.Allocator) -> (d
return
} else {
buffer: [1024]u8
out_buffer := make([dynamic]u8, 0, 0, allocator)
out_buffer := make([dynamic]u8, 0, 0, allocator, loc)
total := 0
for {
n: int
n, err = read(f, buffer[:])
total += n
append_elems(&out_buffer, ..buffer[:n]) or_return
append_elems(&out_buffer, ..buffer[:n], loc=loc) or_return
if err != nil {
if err == .EOF || err == .Broken_Pipe {
err = nil
@@ -163,8 +212,23 @@ read_entire_file_from_file :: proc(f: ^File, allocator: runtime.Allocator) -> (d
}
}
/*
`write_entire_file` writes the contents of `data` into named file `name`.
It defaults with the permssions `perm := Permissions_Read_All + {.Write_User}`, and `truncate`s by default.
An error is returned if any is encountered.
*/
write_entire_file :: proc{
write_entire_file_from_bytes,
write_entire_file_from_string,
}
/*
`write_entire_file_from_bytes` writes the contents of `data` into named file `name`.
It defaults with the permssions `perm := Permissions_Read_All + {.Write_User}`, and `truncate`s by default.
An error is returned if any is encountered.
*/
@(require_results)
write_entire_file :: proc(name: string, data: []byte, perm: int = 0o644, truncate := true) -> Error {
write_entire_file_from_bytes :: proc(name: string, data: []byte, perm := Permissions_Read_All + {.Write_User}, truncate := true) -> Error {
flags := O_WRONLY|O_CREATE
if truncate {
flags |= O_TRUNC
@@ -177,3 +241,14 @@ write_entire_file :: proc(name: string, data: []byte, perm: int = 0o644, truncat
return err
}
/*
`write_entire_file_from_string` writes the contents of `data` into named file `name`.
It defaults with the permssions `perm := Permissions_Read_All + {.Write_User}`, and `truncate`s by default.
An error is returned if any is encountered.
*/
@(require_results)
write_entire_file_from_string :: proc(name: string, data: string, perm := Permissions_Read_All + {.Write_User}, truncate := true) -> Error {
return write_entire_file(name, transmute([]byte)data, perm, truncate)
}
+7 -5
View File
@@ -51,8 +51,8 @@ init_std_files :: proc "contextless" () {
}
@(init)
init_preopens :: proc() {
strip_prefixes :: proc(path: string) -> string {
init_preopens :: proc "contextless" () {
strip_prefixes :: proc "contextless" (path: string) -> string {
path := path
loop: for len(path) > 0 {
switch {
@@ -69,6 +69,8 @@ init_preopens :: proc() {
return path
}
context = runtime.default_context()
n: int
n_loop: for fd := wasi.fd_t(3); ; fd += 1 {
_, err := wasi.fd_prestat_get(fd)
@@ -171,7 +173,7 @@ match_preopen :: proc(path: string) -> (wasi.fd_t, string, bool) {
return match.fd, relative, true
}
_open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) {
_open :: proc(name: string, flags: File_Flags, perm: Permissions) -> (f: ^File, err: Error) {
dir_fd, relative, ok := match_preopen(name)
if !ok {
return nil, .Invalid_Path
@@ -373,11 +375,11 @@ _fchdir :: proc(f: ^File) -> Error {
return .Unsupported
}
_fchmod :: proc(f: ^File, mode: int) -> Error {
_fchmod :: proc(f: ^File, mode: Permissions) -> Error {
return .Unsupported
}
_chmod :: proc(name: string, mode: int) -> Error {
_chmod :: proc(name: string, mode: Permissions) -> Error {
return .Unsupported
}
+7 -8
View File
@@ -12,7 +12,6 @@ import win32 "core:sys/windows"
INVALID_HANDLE :: ~uintptr(0)
S_IWRITE :: 0o200
_ERROR_BAD_NETPATH :: 53
MAX_RW :: 1<<30
@@ -81,7 +80,7 @@ _handle :: proc "contextless" (f: ^File) -> win32.HANDLE {
return win32.HANDLE(_fd(f))
}
_open_internal :: proc(name: string, flags: File_Flags, perm: int) -> (handle: uintptr, err: Error) {
_open_internal :: proc(name: string, flags: File_Flags, perm: Permissions) -> (handle: uintptr, err: Error) {
if len(name) == 0 {
err = .Not_Exist
return
@@ -122,7 +121,7 @@ _open_internal :: proc(name: string, flags: File_Flags, perm: int) -> (handle: u
}
attrs: u32 = win32.FILE_ATTRIBUTE_NORMAL|win32.FILE_FLAG_BACKUP_SEMANTICS
if perm & S_IWRITE == 0 {
if .Write_User not_in perm {
attrs = win32.FILE_ATTRIBUTE_READONLY
if create_mode == win32.CREATE_ALWAYS {
// NOTE(bill): Open has just asked to create a file in read-only mode.
@@ -150,7 +149,7 @@ _open_internal :: proc(name: string, flags: File_Flags, perm: int) -> (handle: u
}
_open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) {
_open :: proc(name: string, flags: File_Flags, perm: Permissions) -> (f: ^File, err: Error) {
flags := flags if flags != nil else {.Read}
handle := _open_internal(name, flags, perm) or_return
return _new_file(handle, name, file_allocator())
@@ -193,7 +192,7 @@ _new_file :: proc(handle: uintptr, name: string, allocator: runtime.Allocator) -
@(require_results)
_open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm := 0o777) -> (f: ^File, err: Error) {
_open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm: Permissions) -> (f: ^File, err: Error) {
assert(buffer_size > 0)
flags := flags if flags != nil else {.Read}
handle := _open_internal(name, flags, perm) or_return
@@ -744,7 +743,7 @@ _fchdir :: proc(f: ^File) -> Error {
return nil
}
_fchmod :: proc(f: ^File, mode: int) -> Error {
_fchmod :: proc(f: ^File, mode: Permissions) -> Error {
if f == nil || f.impl == nil {
return nil
}
@@ -753,7 +752,7 @@ _fchmod :: proc(f: ^File, mode: int) -> Error {
return _get_platform_error()
}
attrs := d.dwFileAttributes
if mode & S_IWRITE != 0 {
if .Write_User in mode {
attrs &~= win32.FILE_ATTRIBUTE_READONLY
} else {
attrs |= win32.FILE_ATTRIBUTE_READONLY
@@ -780,7 +779,7 @@ _chdir :: proc(name: string) -> Error {
return nil
}
_chmod :: proc(name: string, mode: int) -> Error {
_chmod :: proc(name: string, mode: Permissions) -> Error {
f := open(name, {.Write}) or_return
defer close(f)
return _fchmod(f, mode)
+3
View File
@@ -2,6 +2,9 @@ package os2
import "base:runtime"
/*
Returns the default `heap_allocator` for this specific platform.
*/
@(require_results)
heap_allocator :: proc() -> runtime.Allocator {
return runtime.Allocator{
+5 -1
View File
@@ -34,7 +34,7 @@ _mkdir_all :: proc(path: string, perm: int) -> Error {
return .Exist
}
clean_path := clean_path(path, temp_allocator)
clean_path := clean_path(path, temp_allocator) or_return
return internal_mkdir_all(clean_path)
internal_mkdir_all :: proc(path: string) -> Error {
@@ -114,3 +114,7 @@ _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err
return concatenate({"/", arg}, allocator)
}
_get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absolute_path: string, err: Error) {
return "", .Unsupported
}
+1 -1
View File
@@ -35,7 +35,7 @@ delete_args :: proc "contextless" () {
Exit the current process.
*/
exit :: proc "contextless" (code: int) -> ! {
_exit(code)
runtime.exit(code)
}
/*
+2 -6
View File
@@ -13,11 +13,6 @@ import "core:sys/linux"
PIDFD_UNASSIGNED :: ~uintptr(0)
@(private="package")
_exit :: proc "contextless" (code: int) -> ! {
linux.exit_group(i32(code))
}
@(private="package")
_get_uid :: proc() -> int {
return int(linux.getuid())
@@ -427,7 +422,8 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) {
strings.write_string(&exe_builder, executable_name)
exe_path = strings.to_cstring(&exe_builder) or_return
if linux.access(exe_path, linux.X_OK) == .NONE {
stat := linux.Stat{}
if linux.stat(exe_path, &stat) == .NONE && .IFREG in stat.mode && .IXUSR in stat.mode {
found = true
break
}

Some files were not shown because too many files have changed in this diff Show More