mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-04 14:48:47 +00:00
Merge tag 'dev-2025-11'
This commit is contained in:
+10
-1
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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.
|
||||
@@ -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.
|
||||
|
||||
@@ -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).
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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).
|
||||
|
||||
|
||||
@@ -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
@@ -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.
|
||||
@@ -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
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 ==========================
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+34
-208
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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) }
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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[:]))
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ delete_args :: proc "contextless" () {
|
||||
Exit the current process.
|
||||
*/
|
||||
exit :: proc "contextless" (code: int) -> ! {
|
||||
_exit(code)
|
||||
runtime.exit(code)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user