Compare commits

...

977 Commits

Author SHA1 Message Date
gingerBill a00d96c0de Merge pull request #3395 from odin-lang/darwin-reorganization
Move `vendor:darwin/Foundation` to `core:sys/darwin/Foundation`
2024-04-08 16:30:44 +01:00
gingerBill ecac3aef32 Change allocator to permanent 2024-04-08 16:18:14 +01:00
gingerBill ec45504631 Obfuscate #line 2024-04-08 16:14:47 +01:00
gingerBill 810cf22e5d Obfuscate #file and #procedure when -obfuscate-source-code-locations is enabled 2024-04-08 16:08:35 +01:00
gingerBill ef82f3e71e Move vendor:darwin/Foundation to core:sys/darwin/Foundation 2024-04-08 13:47:46 +01:00
gingerBill 16dc79fc5c Add "type" field to -json-errors 2024-04-08 13:36:23 +01:00
gingerBill 2aca370a0a Merge pull request #3394 from laytan/wasm-fixes
Wasm fixes
2024-04-08 13:33:29 +01:00
Laytan Laats ce196529dc enable the required target feature atomics when using them in wasm 2024-04-08 13:56:04 +02:00
Laytan Laats 9d8bb7f4e4 fix _end being called before the actual end when using the step function 2024-04-08 13:54:23 +02:00
Laytan Laats 667883b3d5 fix js_wasm time.tick_now, performance.now() returns a float 2024-04-08 13:53:16 +02:00
gingerBill 114ddc4a10 Fix printing error when field name could not be found 2024-04-08 12:06:06 +01:00
gingerBill 0df9c8bffc Improve error messages for people using keywords instead of identifiers 2024-04-08 12:04:33 +01:00
Jeroen van Rijn 0a73ed0799 Merge pull request #3390 from Lperlind/master
Update "core:runtime" to "base:runtime"
2024-04-07 01:09:47 +02:00
Lucas Perlind a71cd07b36 Update "core:runtime" to "base:runtime" 2024-04-07 09:02:01 +10:00
gingerBill 2bb20a2c1c Merge pull request #3388 from laytan/fix-raygui-symbol
fix raygui `GuiFade` being renamed to `GuiSetAlpha`
2024-04-06 22:52:08 +01:00
gingerBill 352d526b94 Merge pull request #3389 from laytan/fix-wasm-atomics
fix wasm atomics
2024-04-06 22:51:58 +01:00
Laytan Laats b150f49c46 fix wasm atomics
Fixes #2745
2024-04-06 23:32:38 +02:00
Laytan Laats d83532d29e fix raygui GuiFade being renamed to GuiSetAlpha 2024-04-06 20:20:16 +02:00
gingerBill 83d3bc74b0 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-04-06 16:59:07 +01:00
gingerBill fbf01543d1 Remove duplicate table 2024-04-06 16:59:02 +01:00
gingerBill 8a98ee800a Merge pull request #3379 from atomicptr/task/add-sdl-sempost
Add missing SDL2_SemPost binding
2024-04-06 16:12:41 +01:00
gingerBill f72e3f689b Merge pull request #3383 from oskarnp/or_return_crash
Fix checker crash when or_return used for non-existing proc
2024-04-06 16:10:09 +01:00
Jeroen van Rijn cd6153a125 Merge pull request #3385 from blob1807/fixed-removed-undefined-var
core:math/fixed Removed undefined & usused vars in init_from_parts
2024-04-06 14:01:25 +02:00
blob1807 fde4e8c905 Removed undefined & usused vars
Removed undefined& usused vars in init_from_parts
2024-04-06 21:49:50 +10:00
oskarnp ca46484ae3 Fix checker crash when or_return/or_break/or_continue used for non-existing proc 2024-04-06 11:02:43 +02:00
Jeroen van Rijn 280adc8a85 Merge pull request #3381 from Yawning/fix/chacha20poly1305
core/crypto/poly1305: The final addition is NOT mod p
2024-04-05 16:57:31 +02:00
Yawning Angel a45721e9ad core/crypto/poly1305: The final addition is NOT mod p 2024-04-05 23:45:41 +09:00
Christopher Kaster 8d399fa7c0 add missing SDL2_SemPost binding 2024-04-05 09:00:57 +02:00
gingerBill 1422e5bc26 Merge pull request #3377 from laytan/fix-amd64-sysv-abi
fix amd64 sysv abi to pass asan everywhere
2024-04-05 00:06:56 +01:00
Laytan Laats 133b45d843 fix amd64 sysv abi to pass asan everywhere
I verified the PR by running the entire test suite of Odin itself with
`-sanitize:address` and also the ols test suite (which caused unique problems
before).

A test has also been added with some problematic code, Windows seems to
have problems with asan in CI or in general so it is not ran there.

The LB_ABI_COMPUTE_RETURN_TYPES block has been removed entirely because
it was unused, I got pretty confused why it didn't effect anything at
first.

Fixes #3211
2024-04-04 23:45:23 +02:00
gingerBill 510574aa7f Merge pull request #3373 from laytan/add-some-windows-wsa-symbols
add some wsa based additions to `core:sys/windows`
2024-04-04 20:40:31 +01:00
gingerBill 3fd3bf2d4d Merge pull request #3371 from mailgerigk/windows-setevent
Add windows.SetEvent
2024-04-04 18:09:21 +01:00
gingerBill fbff2b4fd6 Merge pull request #3372 from laytan/fix-lbarg-ignore-logic
fix lbArg_Ignore logic
2024-04-04 18:09:12 +01:00
gingerBill 7f0ca315b3 Merge pull request #3374 from laytan/fix-128-ints-alignment-arm64
fix 128 bit int alignment on arm64
2024-04-04 18:06:01 +01:00
Laytan Laats 31407d9b1b fix 128 bit int alignment on arm64
Fixes #2403
2024-04-04 18:39:41 +02:00
gingerBill 83e2f5ff74 Add better error messages with suggestions for using context as an identifier 2024-04-04 17:01:31 +01:00
gingerBill 2375ac22a7 Improve error messages for A variable declaration must be an identifier 2024-04-04 16:57:08 +01:00
gingerBill b979fd4c43 Remove consecutive linking libraries 2024-04-04 16:14:05 +01:00
gingerBill 0e5a482c42 Default to "smart" linker behaviour; Add -min-link-libs to use minimize link libs if wanted 2024-04-04 16:11:26 +01:00
Laytan Laats 1af84e082c add some wsa based additions to core:sys/windows 2024-04-04 17:09:12 +02:00
gingerBill d248cddf90 Remove dead newline 2024-04-04 16:07:55 +01:00
Laytan Laats a7056f2b4f fix lbArg_Ignore logic
Fixes #2698
2024-04-04 16:58:22 +02:00
gerigk 62cebe1bc9 Add windows.SetEvent 2024-04-04 16:00:01 +02:00
gingerBill 99aff7e3fb Merge pull request #3370 from laytan/fix-objc-proc-group-edge-case
fix objc proc group edge case
2024-04-04 13:03:27 +01:00
Laytan Laats 5339e1e1b6 fix objc proc group edge case
Fixes #2648
2024-04-03 21:21:46 +02:00
gingerBill 5fe0788cff Minimize code duplication in core:mem by using the base:runtime calls 2024-04-03 11:47:39 +01:00
gingerBill e42b16b106 Merge pull request #3366 from laytan/fix-vet-scope-bug
fix vet scope bug skipping some scopes
2024-04-03 11:40:01 +01:00
gingerBill a1d9442380 Merge pull request #3367 from laytan/fix-stack-overflow-warning
fix -vet warning for stack overflows not showing up
2024-04-03 11:39:25 +01:00
Laytan Laats b754c1e072 fix -vet warning for stack overflows not showing up
Due to the placement of this code, the warning would only ever be added
if the variable was also either unused or shadowed.
2024-04-03 01:05:54 +02:00
Laytan Laats 3a0df80066 correct newly found vets 2024-04-03 00:52:58 +02:00
gingerBill a9bfb3ac2e Clarity warning and error printing 2024-04-02 23:39:14 +01:00
gingerBill 692a47f080 Fix printing of warnings 2024-04-02 23:36:36 +01:00
Laytan Laats 21fcf7c874 fix vet scope bug skipping some scopes
Fixes #3146
2024-04-02 23:59:38 +02:00
gingerBill 05d07983c3 Merge pull request #3363 from laytan/fix-c-varargs-named-args
fix named arguments and untyped nil with #c_vararg
2024-04-02 18:36:10 +01:00
Laytan Laats fc30bde0f6 fix untyped nil into c varargs
Fixes #2842
2024-04-02 18:49:35 +02:00
Laytan Laats a8d8696e2f fix named arguments with #c_vararg
Previously `args=1`, `args={}`, `args={1, 2, 3}` would all crash the
compiler. Now it passes them correctly, and if given a compound literal,
the values are expanded into the call so you can use a named arg while
passing multiple values.

Fixes #3168
2024-04-02 17:25:11 +02:00
gingerBill 66f9ef9a00 Merge pull request #3361 from yay/ns-application-activate
Add NSApplication.activate to Foundation bindings.
2024-04-02 06:59:13 +01:00
Vitalii Kravchenko fdd4ef3c59 Add NSApplication.active to Foundation bindings. 2024-04-02 02:35:00 +01:00
Jeroen van Rijn f9f6fbfe1f Merge pull request #3360 from laytan/debug-info-fixes
fix wrong type in map debug info
2024-04-01 19:12:24 +02:00
Laytan Laats 4fc96e1ca5 change unneeded permanent allocation to temporary 2024-04-01 19:06:05 +02:00
Laytan Laats cfc85fd737 fix wrong type in map debug info 2024-04-01 18:42:10 +02:00
Jeroen van Rijn 6b7e9f0a2d Merge pull request #3359 from Kelimion/tests_digests
Add SHA3-512 digests verification to test assets.
2024-04-01 18:24:36 +02:00
Jeroen van Rijn b3580fa63a Make it a HMAC. 2024-04-01 18:20:14 +02:00
gingerBill 406aa587e2 Merge pull request #3358 from laytan/debug-info-fixes
debug info fixes/refactor
2024-04-01 16:53:56 +01:00
Jeroen van Rijn b2f432c223 Add SHA3-512 digests verification to test assets. 2024-04-01 17:18:31 +02:00
Laytan Laats 7c2352ea08 remove soa handling in debug info, fields are already added in checker 2024-04-01 16:51:16 +02:00
Laytan Laats 9647cb74ad debug info fixes/refactor
This fixes (on my end) #3340, #3117, #2945, #2922, and #2762

A general refactor of debug info generation in order to fix issues and
increase stability.

What I believe is the root cause of a bunch of issues is that we use the
temporary metadata/forward declarations too much (/ hold onto them for
too long). It seems to cause problems with the reference counting inside
LLVM.

This PR reduces the use of these forward declarations to a minimum, it
creates it, fills in the fields, and resolves it, instead of waiting
until the end of generating code.

Some smaller issues I came across have also been solved.
2024-04-01 16:28:44 +02:00
gingerBill bb72ff9c35 Fix nested ERROR_BLOCK bug 2024-04-01 14:28:11 +01:00
gingerBill 397c2aa201 Merge pull request #3318 from flysand7/os2-file-pipe-read
[core/os2]: Fix read_entire_file for reads from pipe and console.
2024-04-01 13:38:10 +01:00
gingerBill b47d73c651 Fix type checking for invalid enum backing type 2024-04-01 13:34:30 +01:00
flysand7 3ee9184537 [core/os2]: Fix memory leak on read_entire_file 2024-04-01 23:32:16 +11:00
gingerBill 2938def707 Remove dead comment 2024-04-01 13:27:51 +01:00
gingerBill 84686c70c5 Error message when RTTI is disabled when iterating over an enum type or a bit_set of enum with for in 2024-04-01 13:16:49 +01:00
gingerBill 3fa02427b3 Unify error message logic for ranges over bit_set 2024-04-01 13:12:09 +01:00
gingerBill b862691d75 Support for in with bit_set 2024-04-01 13:08:07 +01:00
gingerBill f482cc8374 Fix error message 2024-04-01 12:33:56 +01:00
gingerBill 030b8d3f66 Merge pull request #3354 from serberoth/issue-3349
Patch for #3349 to address API concerns for Darwin platform in core:os
2024-04-01 12:25:17 +01:00
Jeroen van Rijn 0d8dadb084 Merge pull request #3357 from DragosPopse/win32-coinit-fix
Fixed windows.COINIT.MULTITHREADED declaration.
2024-03-31 20:41:13 +02:00
Dragos Popescu d0674cb70f Fixed windows.COINIT.MULTITHREADED declaration. It's supposed to be 0 rather than 3 2024-03-31 21:29:49 +03:00
nicola 3975b5e736 :Updated core:os for darwin to include flush function and match close to api documentation returning errno 2024-03-30 16:48:52 -04:00
gingerBill 2bdf5f58ef Enforce error on old style for/switch l-value 2024-03-30 14:23:47 +00:00
gingerBill 8e1a2094a7 Fix debug info for map 2024-03-30 13:46:23 +00:00
gingerBill 9271372fef Fix #field_align issues, by simplifying the LLVM struct type generation 2024-03-30 13:06:51 +00:00
gingerBill 4edcaa6124 Try storing a pointer to a fake metadata type in the debug info for a map 2024-03-30 10:29:20 +00:00
gingerBill d84d65ba45 Merge pull request #3348 from rick-masters/fix_convert_smaller_float_endian
Implement endian conversions for smaller float types.
2024-03-29 22:13:58 +00:00
gingerBill 28fb1ba83d Merge pull request #3350 from laytan/fix-gb.h-for-fsanitize-address
fix gb.h to be able to use -fsanitize=address
2024-03-29 22:13:32 +00:00
gingerBill db95ed7cdd Merge pull request #3353 from laytan/fix-incomplete-types-resize-segfault
fix a segfault when incomplete types array resizes while processing
2024-03-29 22:13:01 +00:00
Laytan Laats e6a552e0ce fix gb.h to be able to use -fsanitize=address 2024-03-29 22:51:58 +01:00
Laytan Laats 915f63b3f9 fix a segfault when incomplete types array resizes while processing 2024-03-29 22:42:12 +01:00
rick-masters e1b545860f Implement endian conversions for smaller float types. 2024-03-29 11:05:27 +00:00
Jeroen van Rijn 8899f42478 Merge pull request #3347 from harold-b/macos-timing-fix
Fix incorrect timings on macOS
2024-03-29 10:15:16 +01:00
Harold Brenes 13b8a5b73d Reverting to calculated frequency timings method on macOS, but fixed 2024-03-29 05:04:40 -04:00
Harold Brenes b84a660806 Fix incorrect timings on macOS 2024-03-28 21:09:37 -04:00
Jeroen van Rijn d325c8ad23 Merge pull request #3346 from laytan/add-macos-14.4.1
add MacOS 14.4.1 to sys/info and odin report
2024-03-28 19:43:57 +01:00
Laytan Laats b7fd51a251 add MacOS 14.4.1 to sys/info and odin report 2024-03-28 19:39:18 +01:00
Jeroen van Rijn 7325120ca9 Merge pull request #3345 from laytan/speed-up-path-to-fullpath
fix not setting ok in cached code path
2024-03-28 19:27:31 +01:00
Laytan Laats 9a5a39c07d fix not setting ok in cached code path 2024-03-28 19:16:55 +01:00
Jeroen van Rijn 9b43aa3c94 Merge pull request #3344 from laytan/speed-up-path-to-fullpath
compiler: speed up path_to_fullpath on Linux/MacOS
2024-03-28 19:02:39 +01:00
Laytan Laats 63f30a8207 speed up path_to_fullpath on Linux/MacOS
We did some profiling for #3343 and this seems to be the biggest
problem. `realpath` is expensive, and we are locking here for no reason
that I can think of.

This improves the "check procedure bodies" timing (of the linked issue)
from 2.4s to .4s on my machine.
2024-03-28 18:44:21 +01:00
gingerBill 308e9112f2 Disable packing on ARM64 and AMD64 2024-03-28 10:58:40 +00:00
gingerBill 58d0635f48 Merge pull request #3342 from FrancisTheCat/master
Json: Improved unmarshalling of `using _: T` fields
2024-03-27 18:57:34 +00:00
FrancisTheCat 2ccb326a41 Merge branch 'odin-lang:master' into master 2024-03-27 17:52:29 +01:00
gingerBill cf9bdc134c Fix #3341 2024-03-27 16:48:51 +00:00
FrancisTheCat 29e4e85152 Merge branch 'odin-lang:master' into master 2024-03-27 16:43:02 +01:00
Franz Höltermann a422aba578 Json: improved unmarshalling of using _: T fields.
`using _: T` fields will now have their members unmarshalled to their
parent types reflecting the new behaviour of json.marshall.

Example:
```go
A :: struct {
    using _: B,
}

B :: struct {
    field: string,
}

data := `{"field": "Hello World"}`

a: A
json.unmarshal_string(data, &a)
```
2024-03-27 15:46:44 +01:00
gingerBill 7b387fd3aa Improve C-like syntax mistakes error messages 2024-03-27 13:10:46 +00:00
gingerBill 12ec9bce7d Fix parsing bug on bit_set[;x] 2024-03-27 13:05:15 +00:00
gingerBill b378eb2df3 Fix free bug not using the correct allocator 2024-03-27 12:54:52 +00:00
gingerBill 6422c090f2 Make hash procedures contextless where possible 2024-03-27 12:54:37 +00:00
gingerBill 3bc7c51325 Merge pull request #3283 from laytan/darwin-new-wait-on-address-api
darwin: use new wait on address API if possible
2024-03-27 11:20:32 +00:00
gingerBill f57cc6beb1 Merge pull request #3331 from laytan/darwin-fix-entrypoint-warning-dylibs
darwin: fix linker warning when building dynamic library
2024-03-27 11:19:11 +00:00
gingerBill 2031d2769a Merge branch 'master' of https://github.com/odin-lang/Odin 2024-03-27 00:58:35 +00:00
gingerBill 83c9739a7d Update year 2024-03-27 00:58:21 +00:00
gingerBill d9ba698b7b Merge pull request #3337 from FrancisTheCat/master
Json: Improve marshalling of `using _: T` fields
2024-03-27 00:57:03 +00:00
Laytan Laats 19d566ebc5 darwin: fix linker warning when building dynamic library
Trying to fix all linker warnings that macOS comes up with, when
building a dynamic library it currently emits `ld: warning: ignoring -e, not used for output type`
2024-03-26 21:00:14 +01:00
Franz Höltermann 92a5666c1c Json: fields on structs like 'using _: T' will now have T's fields
marshalled directly into the parent type without an '"_":{ ... }'.
This seems like desirable behavior to me, since you can't access the
fields with 'Parent_Type._.field' either.
2024-03-26 20:22:51 +01:00
gingerBill 63d6b4752b Fix type info layout for wasm64p32 targets 2024-03-26 17:16:12 +00:00
gingerBill 6588fe35b3 Fix wasm abi 2024-03-26 16:47:29 +00:00
gingerBill fa84272d5e Merge pull request #3335 from rick-masters/fix_incomplete_struct_type
Don't add type info for incomplete structs.
2024-03-26 16:08:12 +00:00
rick-masters c90a6ab0d5 Remove accidentally added test binary. 2024-03-26 15:08:32 +00:00
gingerBill 0989eac681 Add extra sanity check for nullptr 2024-03-26 14:57:06 +00:00
rick-masters b8c0a02164 Don't add type info for incomplete structs. 2024-03-26 14:34:56 +00:00
gingerBill df526549e2 Fix min/max for wasm 2024-03-26 14:31:28 +00:00
gingerBill 1009182f7b Fix another #soa race condition bug 2024-03-26 14:13:55 +00:00
gingerBill 620dd2c812 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-03-26 13:06:46 +00:00
gingerBill 533ba63c82 Fix #3327 #3204 #3200 2024-03-26 13:06:39 +00:00
gingerBill 2165303f5e Merge pull request #3332 from laytan/darwin-be-less-annoying-about-library-versions
darwin: be less annoying about "incompatible" library versions
2024-03-26 11:16:25 +00:00
gingerBill c59f6d548b Merge pull request #3333 from blob1807/change-time-sleep-doc
time.accurate_sleep Windows Doc update
2024-03-26 11:15:55 +00:00
blob1807 8eed65ad4c Update time.odin 2024-03-26 11:20:05 +10:00
blob1807 bc0a2b8d39 Update time.odin 2024-03-26 11:17:44 +10:00
blob1807 a405c72d4d Updated windows time period call
Updated win32.time_begin_period to windows.timeBeginPeriod
Added a note about calling windows.timeEndPeriod once you don't need accurate_sleep, as per MS's docs https://learn.microsoft.com/en-us/windows/win32/api/timeapi/nf-timeapi-timebeginperiod#remarks
2024-03-26 11:13:27 +10:00
Laytan Laats b26a685b76 darwin: be less annoying about "incompatible" library versions
After #3316 we set a default minimum version, now this will warn if you
link with a library that is targeting later versions.

This might be a bit annoying, especially when the user hasn't actually
given Odin a minimum target.

So this PR makes these warnings only show when you explicitly give a
target version (afaik that is the only thing that -mmacosx-min-version
actually does for us because we don't use it to compile anything, just
to link).
2024-03-25 22:11:20 +01:00
gingerBill 3a8971c260 Merge pull request #3330 from laytan/remove-mistaken-dll
remove mistakenly added dll
2024-03-25 17:14:36 +00:00
Laytan Laats ed742efc33 remove mistakenly added dll
Just noticed I oopsied the glfw dll into the repo
2024-03-25 18:11:41 +01:00
gingerBill 06ee9117d2 Merge pull request #3124 from laytan/update-releases-llvm-version
update LLVM to 17 for CI/releases
2024-03-25 16:36:38 +00:00
gingerBill e100d9264f Merge pull request #3329 from laytan/fix-darwin_amd64-f16-emulation-on-older-microarches
darwin: fix amd64 f16 emulation
2024-03-25 16:35:57 +00:00
gingerBill 53b02c5e6f Fix printing errors issue 2024-03-25 14:46:45 +00:00
gingerBill 50618759a6 Fix error reporting for type cycles 2024-03-25 13:44:00 +00:00
gingerBill 600ca83386 Merge pull request #3326 from rick-masters/fix_fields_wait_signal
Fix fields_wait_signal futex.
2024-03-25 13:29:08 +00:00
gingerBill e5629dafd0 Potentially fix a race condition with parapoly types (related to #3328) 2024-03-25 13:23:43 +00:00
Laytan Laats a2167587ae Merge branch 'fix-darwin_amd64-f16-emulation-on-older-microarches' of github.com:laytan/Odin into update-releases-llvm-version 2024-03-25 14:15:18 +01:00
Laytan Laats b2a35683a4 darwin: fix amd64 f16 emulation
Fixes #3222
2024-03-25 14:07:49 +01:00
Laytan Laats dcc263c618 re-enable core tests on macos arm 2024-03-25 14:05:07 +01:00
Laytan Laats 3b34cf6dbb Also update to LLVM 17 for general CI 2024-03-25 14:05:07 +01:00
Laytan ae9f026f4b llvm 17 on macos arm releases 2024-03-25 14:05:07 +01:00
Laytan Laats 46093bad1e update LLVM to 17 for releases 2024-03-25 14:05:07 +01:00
flysand7 c843002d07 [core/os2]: Move .Broken_Pipe to General_Error enum 2024-03-25 23:35:01 +11:00
rick-masters 6d4f30de1a Fix fields_wait_signal futex. 2024-03-24 16:28:55 +00:00
gingerBill 68ff945419 Remove old error message for #3062 2024-03-24 14:39:42 +00:00
gingerBill cab53e12b7 Add assert message to tell me people to report the bug 2024-03-24 13:53:09 +00:00
gingerBill d92767cb77 Fix #3226 2024-03-24 13:49:51 +00:00
gingerBill 670fc70f1f Remove private attributes for #3227 2024-03-24 13:46:26 +00:00
gingerBill 223a336eb4 Fix #3249 2024-03-24 13:45:10 +00:00
gingerBill 1ea1229516 Fix #3319 2024-03-24 13:42:37 +00:00
gingerBill 6da6393735 Fix #3320 2024-03-24 13:40:10 +00:00
gingerBill 87688936c6 Improve error messages for some wrong constant value attributes 2024-03-24 13:36:50 +00:00
gingerBill 590e52cc05 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-03-24 13:33:37 +00:00
gingerBill 398af659e5 Fix #3323 2024-03-24 13:33:30 +00:00
gingerBill 2e416c1a48 Merge pull request #3316 from laytan/fix-ld-warnings-and-set-default-minimum-version
darwin: fix ld warnings and set minimum os version
2024-03-24 13:26:35 +00:00
gingerBill 34247b2658 Fix resize bug caused by typo 2024-03-24 12:24:44 +00:00
gingerBill 45d7dd8f27 Fix resize zeroing behaviour 2024-03-24 12:20:39 +00:00
gingerBill 09d7f1337b Merge pull request #3317 from laytan/arm64-abi-fixes
darwin: arm64 abi fixes
2024-03-24 00:41:52 +00:00
flysand7 0f944bc0a1 [core/os2]: Reading from unsized files 2024-03-24 10:52:48 +11:00
Laytan Laats 07a9969a41 darwin: arm64 abi fixes
Since commit b4fe9677a1 some core tests
segfault during build, upon investigation it is because some arg types
were of size 0 and you can't have a 0 sized int.

It also applies the earlier fix for parameters to the return types, this
fixes #3223

Thought I would put this PR up, but I am in no way an expert in abi so
feel free to close for a better fix if there is one.

I am able to run the entire core test suite with `-sanitize:address`
with these changes.
2024-03-23 23:17:01 +01:00
Laytan Laats 15c1e8274d darwin: fix ld warnings and set minimum os version 2024-03-23 22:12:05 +01:00
gingerBill 517d7ae0b0 Add error block around error_line calls 2024-03-23 17:51:56 +00:00
gingerBill efb0933965 Improve error suggestion and propagation for x->y 2024-03-23 16:57:35 +00:00
gingerBill eb51cc6835 Improve error propagation for (*x).y style errors from C-programmers 2024-03-23 16:53:40 +00:00
gingerBill 1d46adb598 Treat *x as an unary operator to improve error messages for common C-programmer mistakes 2024-03-23 16:51:04 +00:00
gingerBill 61aa4558dc Fix #3314 2024-03-23 16:41:50 +00:00
gingerBill 194d3fe6bd Ignore wrong types 2024-03-23 14:59:35 +00:00
gingerBill 624b870f28 Add some basic escape analysis errors for return &x 2024-03-23 14:58:10 +00:00
gingerBill eb61cf6043 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-03-23 12:56:09 +00:00
gingerBill 7abb459861 Add missing field flags in debug printing 2024-03-23 12:56:04 +00:00
gingerBill e9ac7d5fab Merge pull request #3311 from laytan/fix-simd128-wasm
fix wasm with `-target-features:"simd128"`
2024-03-23 10:42:36 +00:00
Laytan Laats bb5dab342a fix wasm with -target-features:"simd128"
the required procs within wasm would compile to take native v128
arguments in, but the procs are supposed to take in i64's causing bad wasm
modules.

Fixes #3263
2024-03-22 17:04:15 +01:00
gingerBill 7d6e9ef39c Merge branch 'master' of https://github.com/odin-lang/Odin 2024-03-21 20:44:00 +00:00
gingerBill d47ba09743 Fix at error printing bug 2024-03-21 20:43:52 +00:00
gingerBill 5c9da66595 Merge pull request #3294 from laytan/update-glfw-from-3.3.8-to-3.4
glfw: update from 3.3.8 to 3.4
2024-03-21 15:43:25 +00:00
gingerBill 9cbb9d8551 Merge pull request #3304 from mailgerigk/master
Remove entry point when compiled with no-entry-point as shared library
2024-03-21 15:19:38 +00:00
gingerBill 6b6f72e7bd Fix #3305 2024-03-21 14:59:47 +00:00
gingerBill c8cdb22f0b Disallow for x in y.(T) and for x in y.? 2024-03-21 14:42:48 +00:00
gingerBill 6e2efce670 Fix missing ERROR_BLOCK(); calls 2024-03-21 12:05:15 +00:00
gingerBill 6d7afd3fa9 Update format version 2024-03-21 11:59:45 +00:00
gingerBill 006ea11c56 Update doc-format for #by_ptr and #no_broadcast parameters 2024-03-21 11:58:32 +00:00
gingerBill 010ffc486c Minor clean up of #no_broadcast handling 2024-03-21 11:54:40 +00:00
gingerBill 29e5f94c2a Add #no_broadcast procedure parameter to disallow automatic array programming broadcasting on procedure arguments 2024-03-21 11:52:48 +00:00
mailgerigk 6a0d2ffcac Merge branch 'odin-lang:master' into master 2024-03-21 00:26:42 +01:00
gingerBill fc587c507a Merge branch 'master' of https://github.com/odin-lang/Odin 2024-03-20 22:44:43 +00:00
gingerBill 65cb382135 Fix error handling for type switch statement 2024-03-20 22:44:35 +00:00
Jeroen van Rijn 8f0d74c08d Merge pull request #3292 from Kelimion/rfc3339
Add WiP datetime package and tests.
2024-03-20 23:23:27 +01:00
gerigk 800014e40c Remove entry point when compiled with no-entry-point as shared library 2024-03-20 23:18:08 +01:00
Jeroen van Rijn fda283c55e More better validation. 2024-03-20 23:09:09 +01:00
gingerBill f39b34a8b7 Fix error message 2024-03-20 18:17:06 +00:00
gingerBill 1cc5e23801 Fix #3299 2024-03-20 18:16:46 +00:00
gingerBill 8e0806be2d Fix #3301 2024-03-20 18:09:57 +00:00
gingerBill c17adc98f5 Try doing <{i64, i32}> instead of [i64, i64] for ARM64 12-byte parameters 2024-03-20 17:39:00 +00:00
gingerBill d381b77164 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-03-20 17:27:12 +00:00
gingerBill e804fbd891 Force packed structs in ABI parameters 2024-03-20 17:27:05 +00:00
Jeroen van Rijn ed5fd15f6e Ensmallen Date struct. 2024-03-20 18:13:29 +01:00
Jeroen van Rijn 89ca15014c Ensmallen Time struct. 2024-03-20 18:09:07 +01:00
gingerBill a5efcfdd78 Merge pull request #3303 from laytan/allow-darwin-cross-arch-linking
darwin: allow cross linking darwin_amd64 from darwin_arm64
2024-03-20 16:56:24 +00:00
Jeroen van Rijn 9c144dd24f Change Ordinal from int to i64 2024-03-20 17:56:22 +01:00
gingerBill c0f9e8d6a3 Merge pull request #3302 from laytan/missing-cmark-api
commonmark: add missing on_exit api
2024-03-20 16:56:11 +00:00
Laytan Laats f312adb26a darwin: allow cross linking darwin_amd64 from darwin_arm64 2024-03-20 17:44:35 +01:00
Laytan Laats 9c879e5e17 commonmark: add missing on_exit api 2024-03-20 17:42:20 +01:00
gingerBill b4fe9677a1 Change ARM64 ABI for integer-like parameters 2024-03-20 16:06:50 +00:00
gingerBill 1951bc45a6 Fix #3133 by show the line of the syntax error 2024-03-20 13:55:47 +00:00
gingerBill ba77a9464c Add suggestion for x: ^T; y = x to be x^ 2024-03-20 13:36:14 +00:00
gingerBill b1dae2d59a Add x: T; y: ^T = x suggestion to do &x 2024-03-20 13:28:17 +00:00
gingerBill 1514d64964 Update ARM64 ABI return type 2024-03-20 11:12:43 +00:00
gingerBill e4c502e79b Add offset (in bytes) field to -json-errors 2024-03-20 11:06:02 +00:00
gingerBill 553a244fec Fix bounds checking 2024-03-20 10:24:39 +00:00
gingerBill 3bff922b6f m[i] on #row_major matrices will reduce the i-th row-vector 2024-03-20 10:23:57 +00:00
gingerBill 56004c56fc Merge pull request #3295 from kavalee/parser-newline-fix
Fixed issue #3264 regarding `core:odin/parser` compound literal not allowing a newline
2024-03-20 10:09:55 +00:00
gingerBill 863ee0b8d1 Merge pull request #3297 from laytan/linker-improvements
linker improvements
2024-03-20 10:09:45 +00:00
Jeroen van Rijn 89ba8b4139 Merge pull request #3298 from laytan/update-macos-releases
update macOS releases for `core:sys/info` and `odin report`
2024-03-20 00:23:53 +01:00
Laytan Laats d0b3b18e26 update macOS releases for core:sys/info and odin report 2024-03-20 00:14:01 +01:00
gingerBill cd7137af60 Update raylib to use #row_major matrices 2024-03-19 21:16:04 +00:00
gingerBill 18fb665bf6 Correct matrix builtins for #row_major 2024-03-19 21:15:47 +00:00
gingerBill a750fc0ba6 Add #row_major matrix[R, C]T
As well as `#column_major matrix[R, C]T` as an alias for just `matrix[R, C]T`.
This is because some libraries require a row_major internal layout but still want to be used with row or major oriented vectors.
2024-03-19 21:05:23 +00:00
Laytan Laats a555862522 linker improvements
`path_to_fullpath` did different things on Windows&Unix, an attempt to
bring them closer together was made here.
This was prompted by the compiler completely ignoring
`foreign import "foo.dylib"` when `foo.dylib` does not exist (because
`path_to_fullpath` returns an empty string).
Causing just unresolved symbol errors, when on Windows it would pass
along the path to the linker and actually say it doesn't exist, which
is now also the case for Unix.
This also fixes some checker errors that relied on the Windows
behaviour, for example: `Error: File name, , cannot be as a library name
as it is not a valid identifier`.

Made `-no-crt` require either `-default-to-nil-allocator` or
`-default-to-panic-allocator` on Unix, the current default allocators
rely on libc and this was not obvious and would immediately bring up
unresolved symbol errors for the linked memory management functions, or
just link with libc anyways because it was foreign imported.

Added a suggestion to install `nasm` with the user's package manager
when assembling using `nasm` fails on Unix, I saw some confusion about
it in the Discord.

Ignore explicit foreign imports of libc. It is already linked in later
on in the linking process and would otherwise (at least on macOS) cause
linker warnings for duplicate libraries. This also makes it so when
using `-no-crt` and importing something that requires libc, linker
errors are given (like I would expect), instead of silently still
linking with libc because it was foreign imported.
2024-03-19 19:57:35 +01:00
gingerBill 433109ff52 Replace gb_exit(1) with exit_with_errors() where appropriate 2024-03-19 16:29:45 +00:00
gingerBill ba428fecdb Add -json-errors 2024-03-19 16:25:09 +00:00
gingerBill 17cc7a2c5e General clean-up for error.cpp 2024-03-19 15:42:59 +00:00
gingerBill 9a2fc6cf4c Serialize errors to make them sortable, deterministic, and generally more control 2024-03-19 15:34:29 +00:00
gingerBill 8ff788f4ff Add better suggestion for [?]T mistake 2024-03-19 13:38:13 +00:00
gingerBill 80ecf5b68a On x: [?]T = {...}, minimize errors by using the [?]T expression as a kind of hint 2024-03-19 13:32:37 +00:00
gingerBill 5159f30c9c Fix error block handling 2024-03-19 13:10:35 +00:00
gingerBill d5daa9fda5 Minimize error propagation of bad array syntax by treating this like a type 2024-03-19 13:05:28 +00:00
gingerBill 89315986d4 Add suggestion when mistyping an array backwards e.g. T[] 2024-03-19 12:37:11 +00:00
Aaron Kavaler 096b4f5454 fixed issue #3264 regarding core:odin/parser not allowing a newline at the end of a compound literal 2024-03-18 20:33:02 -07:00
Laytan Laats 65e68f11f8 glfw: update from 3.3.8 to 3.4 2024-03-18 23:54:26 +01:00
gingerBill ec9ac59323 Unify "Did you mean" strings 2024-03-18 21:37:40 +00:00
gingerBill 97be7feb99 Add list of C identifier suggestions (types and keywords) 2024-03-18 17:32:26 +00:00
gingerBill 00344e1323 Add check to people trying to foreign import C files. 2024-03-18 16:56:01 +00:00
Laytan Laats dd92d3054d add ODIN_ prefix to the new constant 2024-03-18 17:22:58 +01:00
Jeroen van Rijn 07ef969546 Fix test label. 2024-03-18 17:05:40 +01:00
Jeroen van Rijn 72c15d7699 Add WiP datetime package and tests.
A new package `core:time/datetime` has been added which can represent moments much further in the past and future than `core:time`.
It is based on *the* reference work on the subject, Calendrical Calculations Ultimate Edition, Reingold & Dershowitz.

More procedures will be added to it in the future, to for example calculate the 3rd Thursday in March to figure out holidays.
The package has been tested for more than a year and can handle dates 25 quadrillion years into the past and future with 64-bit day ordinals, or 5 million with 32-bit ones.

This also fixes a longstanding bug where converting between YYYY-MM:DD hh:mm:ss and `time.Time` and back could result in a mismatch.

RFC 3339 timestamps can now also be parsed using the `core:time` package.
2024-03-18 16:47:16 +01:00
gingerBill 009b6f44e3 Add loads of checks for common mistakes for C programmer 2024-03-18 15:18:10 +00:00
gingerBill ebd3065aa2 Add error message for C programmers which do Foo{.x = 123} rather than Foo{x = 123} 2024-03-18 14:17:13 +00:00
gingerBill 6cb74b63ec Fix #3286 2024-03-18 12:39:34 +00:00
gingerBill effc71ca43 Fix case: bug with by-ref unions 2024-03-18 12:20:53 +00:00
gingerBill 43d695a990 Fix for x in y where y is an "optional ok" value, but ignores #optional_allocator_error values 2024-03-18 11:21:06 +00:00
gingerBill 19eb2a8890 Fix #3282 2024-03-16 22:24:34 +00:00
gingerBill 3875fb08e8 Fix #3284 2024-03-16 22:12:17 +00:00
Laytan Laats 9c455b2213 darwin: use new wait on address API if possible 2024-03-15 21:43:16 +01:00
gingerBill 04f0fbf23a Merge pull request #3272 from iansimonson/add_getrusage_darwin
Add getrusage syscall for mac/darwin
2024-03-14 19:45:25 +00:00
gingerBill 51d6a254cf Merge pull request #3277 from kavalee/slice-unique-fixes
fixed slice.unique and slice.unique_proc
2024-03-14 19:40:18 +00:00
Ian Simonson 835effdef1 Use c.long rather than int 2024-03-14 09:36:57 -07:00
Ian Simonson c7bec2962e Fix __darwin_suseconds_t definition
__darwin_suseconds_t is defined as long which on macos
64 bit systems is equivalent to 8 bytes. It is equivalent
to Odin int type _not_ i32
2024-03-14 07:21:26 -07:00
Aaron Kavaler ac634acd4b fixed slice.unique and slice.unique_proc 2024-03-13 19:19:31 -07:00
Ian Simonson 34c4389d75 No need for timeval definition
It already existed so lets just use that rather than
redeclaring it
2024-03-13 14:58:56 -07:00
Ian Simonson 8917a7ef88 Make RUsage more inline with macos man page
Swap to tabs to adhere to the Odin Core library standard
and also rename the rusage fields to match the actual
definitions from the macos bsd man pages
2024-03-13 14:51:17 -07:00
gingerBill 45d5066029 Merge pull request #3274 from iansimonson/darwin_munmap_syscall_fix
Fix syscall_munmap in darwin
2024-03-13 20:17:31 +00:00
gingerBill b47eeac414 Merge pull request #3275 from Chickenkeeper/bit-set-error-message-fix
Improve bit_set error message
2024-03-13 20:17:06 +00:00
Chris 5cc936245c Improve bit_set error message 2024-03-13 19:50:41 +00:00
gingerBill e68d3c8bbc Merge pull request #3143 from Pariatech/cgltf-linux-build
Adding linux & darwin makefile for cgltf
2024-03-13 17:47:18 +00:00
Ian Simonson d7b1901b16 Fix syscall_munmap in darwin
this was using the .mmap syscall number when it should be
using the .munmap syscall number
2024-03-13 10:39:50 -07:00
gingerBill 97d6bf6d8f Merge branch 'master' of https://github.com/odin-lang/Odin 2024-03-13 16:30:28 +00:00
gingerBill 271f84ab5b Expect stream as a field directly on os2.File 2024-03-13 16:30:22 +00:00
gingerBill 75b60fdb12 Merge pull request #3273 from Chickenkeeper/mutex-allocator-fix
Make Mutex_Allocator use Ada_Case
2024-03-13 15:45:52 +00:00
Chris 55141bdbb1 Make Mutex_Allocator use Ada_Case 2024-03-13 15:29:02 +00:00
gingerBill 5f2496226f Change return to panic 2024-03-13 15:17:21 +00:00
gingerBill dee66b8451 Fix typo due to deletion 2024-03-13 15:14:31 +00:00
gingerBill 4aec2de7bd Merge branch 'master' of https://github.com/odin-lang/Odin 2024-03-13 15:12:19 +00:00
gingerBill ac10f504e4 Add infinite loop check and early out in map_insert_hash_dynamic 2024-03-13 15:12:14 +00:00
Ian Simonson 26d107ce64 Add getrusage syscall for mac/darwin
The syscall number existed but the wrapper for calling it
did not. Also adds the RUsage struct to receive the data.

Naming is kept the same as in sys/linux
2024-03-13 08:07:12 -07:00
gingerBill d62c92f5a9 Merge pull request #3267 from harold-b/copy-dirent-path
Retain copies of `dirent->name` for .odin files when using `read_directory`
2024-03-13 12:23:28 +00:00
gingerBill 5c1646a6b3 Merge pull request #3271 from rick-masters/too_many_poly_args
Fix check for too many arguments to a polymorphic record type
2024-03-13 12:23:19 +00:00
Pariatech b539bb2693 Update vendor/cgltf/src/Makefile
missing darwin folder

Co-authored-by: Laytan <laytanlaats@hotmail.com>
2024-03-13 07:37:42 -04:00
rick-masters 7bc962b852 Fix variable used to index polymorphic parameter. 2024-03-12 23:58:20 +00:00
rick-masters f7ec628cb2 Fix check for too many arguments to a polymorphic record type. 2024-03-12 23:57:13 +00:00
Jeroen van Rijn 23f3898b4e Merge pull request #3270 from edyu/master
Expose internal invmod and int_exponent_mod with more consistent naming
2024-03-12 19:06:10 +01:00
Ed Yu dd74a57c44 Expose internal invmod and int_exponent_mod with more consistent naming 2024-03-12 11:01:09 -07:00
gingerBill d6353daf91 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-03-12 12:11:53 +00:00
gingerBill c7c6852057 Support swizzle selector syntax .xyzw for #simd vectors 2024-03-12 12:11:48 +00:00
Harold Brenes b543be0d15 Copy file names fromdirent into FileInfo during read_directory 2024-03-11 18:09:41 -04:00
gingerBill 47837b206e Merge pull request #3266 from nnym/master
Use a POSIX-compliant equality operator in `build_odin.sh`.
2024-03-11 13:00:01 +00:00
gingerBill 9a41a450e7 Add builtin map_upsert 2024-03-11 12:30:24 +00:00
Muhammad f20d0202fa Use a POSIX-compliant equality operator. 2024-03-11 06:05:42 +00:00
gingerBill 8721d03cfe Merge pull request #3199 from JamesDSource/soa
Add into_dynamic_soa, unordered_remove_soa, and ordered_remove_soa
2024-03-09 16:56:04 +00:00
gingerBill d06575dd49 Merge pull request #3149 from IllusionMan1212/missing-x11-funcs
vendor/x11: added XQueryExtension, XGetEventData, and XFreeEventData
2024-03-09 16:53:11 +00:00
gingerBill 568b07473f Merge pull request #3148 from IllusionMan1212/cookie-struct-fix
vendor/x11: fix "display" with no pointer in XGenericEventCookie
2024-03-09 16:52:53 +00:00
gingerBill 04666746d7 Merge pull request #3261 from spindlebink/fix-orthonormalize
Properly initialize return matrices in linalg.orthonormalize
2024-03-09 15:51:53 +00:00
spindlebink b2e7eb4db4 Properly initialize return matrices in linalg.orthonormalize 2024-03-09 09:10:25 -06:00
gingerBill f88af59372 Merge pull request #3258 from deckarep/patch-1
Base/runtime (darwin): Incorrect write syscall on Darwin - fixes stderr output.
2024-03-09 11:11:09 +00:00
Ralph Caraveo a974c08aff Incorrect write syscall on Darwin - fixes stderr output.
On macos, Odin was previously swallowing errors that would be reported via stderr. 

I've confirmed with @laytan on Discord that this fixes the issue.
2024-03-08 16:19:59 -08:00
Jeroen van Rijn fc9d3ec5a7 Merge branch 'master' of github.com:odin-lang/Odin 2024-03-08 18:06:13 +01:00
Jeroen van Rijn db03c86544 Fix typo in big.internal_invmod
Fixes #3253
2024-03-08 18:05:34 +01:00
gingerBill 51d12acab3 Enforce linalg 2024-03-08 13:28:15 +00:00
gingerBill 032e193d0d Merge branch 'master' of https://github.com/odin-lang/Odin 2024-03-08 13:20:33 +00:00
gingerBill 0f83ab466f Minor change to spacing when printing a map 2024-03-08 13:20:27 +00:00
gingerBill 53ce945034 Merge pull request #3230 from avanspector/haiku
Add Haiku OS support
2024-03-08 11:15:13 +00:00
gingerBill 0e168dd292 Merge pull request #3241 from Hyrtwol/sys-windows
Gathered what I made for sys/windows
2024-03-07 15:26:31 +00:00
gingerBill 5ff6a25bdc Improve formatting for %# on maps 2024-03-07 13:45:52 +00:00
gingerBill b6b8e640f5 Replace b with _ as it is not needed 2024-03-07 13:41:54 +00:00
gingerBill 573402c97e Begin work on %w - 'w'rite as valid Odin literals 2024-03-07 13:39:44 +00:00
gingerBill e01701ce0e Fix typo 2024-03-07 12:32:46 +00:00
gingerBill f9b14500be Add default_commit_size to virtual.Arena 2024-03-07 12:30:34 +00:00
gingerBill 4bb7cd5e4b Add bit_field option to core_type in the compiler 2024-03-07 11:31:00 +00:00
gingerBill 6d5b1800fe Fix typo 2024-03-06 16:34:17 +00:00
gingerBill 0f5328973e Add mem.Mutex_Allocator 2024-03-06 16:33:54 +00:00
gingerBill 65277ddd6b Add missing attribute 2024-03-06 16:30:39 +00:00
gingerBill 46718d6d85 Add Query_Info to Buddy_Allocator 2024-03-06 16:26:10 +00:00
gingerBill 2a0543d2f0 Add mem.Buddy_Allocator 2024-03-06 16:14:45 +00:00
gingerBill 792f06a234 Fix indentation 2024-03-06 15:29:07 +00:00
gingerBill 14f7619cdc Merge pull request #3069 from pcleavelin/master
Respect `-lld` CLI arg on non-windows machines
2024-03-06 15:25:16 +00:00
gingerBill ffa3669d02 Add virtual.Arena utilities: new, new_aligned, make 2024-03-06 15:23:56 +00:00
gingerBill b1903b915b Change to IEEE 754-2008 conformance for min/max runtime operations. 2024-03-06 15:16:11 +00:00
gingerBill a7bab89c93 Unify min/max semantics for simd_(min|max) 2024-03-06 15:07:21 +00:00
gingerBill a1ee9e7035 Change min/max runtime behaviour to match IEEE 754-2019 2024-03-06 15:04:46 +00:00
gingerBill c05a92ab3e Merge pull request #3215 from blob1807/json-better-enum-support
core:encoding/json Add support for writing enum value names
2024-03-06 14:56:19 +00:00
gingerBill 5789df5c0c Disable core library tests for ARM (Silly CI) 2024-03-06 14:54:23 +00:00
gingerBill 78c05a49a3 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-03-06 14:52:04 +00:00
gingerBill 8d496dc3d0 Fix #3173 2024-03-06 14:51:56 +00:00
gingerBill 703eab2f15 Merge pull request #3229 from Yawning/feature/moar-crypto
core/crypto: More improvements/additions
2024-03-06 14:49:15 +00:00
gingerBill 04bfc926ee Merge pull request #3238 from laytan/libc-free-raylib-and-rectpack
makes raylib and stb_rect_pack free of libc
2024-03-06 14:11:41 +00:00
gingerBill 791c9c16ba Merge pull request #3242 from laytan/fix-cgltf-binding
fix minor cgltf binding issue
2024-03-06 14:11:27 +00:00
gingerBill 6d3a57b4ac Zero intrinsics.alloca 2024-03-06 13:48:37 +00:00
gingerBill c7b8f1fb0a Use intrinsics.alloca rather than context.temp_allocator in json.unmarshal_object 2024-03-06 13:42:38 +00:00
gingerBill 462f3f4abd Merge branch 'master' of https://github.com/odin-lang/Odin 2024-03-06 11:49:24 +00:00
gingerBill 5eef29290c Fix #3250 2024-03-06 11:49:17 +00:00
gingerBill a944aa406d Merge pull request #3246 from edyu/master
For invmod, b has to be > 1, fix a logic typo
2024-03-05 14:00:52 +00:00
gingerBill 8c6c2543da Merge pull request #2999 from laytan/crypto-random-bytes-on-freebsd-and-darwin
add crypto.rand_bytes for Darwin and BSD
2024-03-05 12:55:37 +00:00
gingerBill 7ae22b7ce5 Update are_types_identical for bit_field 2024-03-04 20:22:49 +00:00
gingerBill 3e295734cb Correct is_type_comparable for bit_field 2024-03-04 20:10:34 +00:00
Ed Yu de41c2256d For invmod, b has to be > 1, fix a logic typo 2024-03-04 10:16:19 -08:00
blob1807 b419615002 Apply suggestions from code review
Fixing spelling mistakes pointed out & fixed by layton.

Co-authored-by: Laytan <laytanlaats@hotmail.com>
2024-03-04 21:20:13 +10:00
Yawning Angel c044e295ce vendor/botan: Remove
This is infrequently maintained, and has been a strict subset of what is
available in `core:crypto` for a while.  Instead of improving the
bindings, it is better to spend resources improving `core:crypto`.
2024-03-04 18:20:56 +09:00
Yawning Angel 87ab3f5dc8 tests/core/crypto: Use the tests/common boilerplate 2024-03-04 18:20:56 +09:00
Yawning Angel fa8dd5a13b core/crypto: Misc cleanups and documentation improvements 2024-03-04 17:50:45 +09:00
Yawning Angel b818ebc02f core/crypto/kmac: Initial import 2024-03-04 17:50:45 +09:00
Yawning Angel c04a53e453 core/crypto/tuplehash: Initial import 2024-03-04 17:50:43 +09:00
Yawning Angel 15287a771f core/crypto/shake: Support cSHAKE 2024-03-04 17:50:24 +09:00
Yawning Angel 2db31cf0d5 core/crypto/_sha3: Cleanups, prepare for cSHAKE 2024-03-04 14:51:38 +09:00
Yawning Angel 550e798c1b core/crypto/hkdf: Initial import 2024-03-04 14:51:38 +09:00
Yawning Angel 290168f862 core/crypto/pbkdf2: Initial import 2024-03-04 14:51:38 +09:00
Yawning Angel 2f2a92866b core/crypto/hmac: Add a clone method 2024-03-04 14:51:38 +09:00
blob1807 116edb9052 convert spaces to tabs 2024-03-04 15:09:17 +10:00
blob1807 9070e613a4 Return underlining value instead of panicing
when no name it found.

Renamed use_enum_value_names to use_enum_names
it get the same point across & inline with the
reflect procs
2024-03-04 15:06:30 +10:00
Thomas la Cour 6243160ecd Cleanup of ShowCursor after Bill pushed a fix 2024-03-03 19:53:34 +01:00
Thomas la Cour 980ee3310f didn't help :/ so removed it to see if it can build again 2024-03-03 19:53:34 +01:00
Thomas la Cour c5d5d055ac Trying to resolve a strange nameclash on ShowCursor seems like raylib is also defining that. Unsure why exactly this is related so for now just tried to change the name here to _ShowCursor :/ 2024-03-03 19:53:34 +01:00
Thomas la Cour a783d4ce5b Callback types 2024-03-03 19:53:33 +01:00
Thomas la Cour a7b09a24b7 Waveform Functions
https://learn.microsoft.com/en-us/windows/win32/multimedia/waveform-functions
2024-03-03 19:53:33 +01:00
Thomas la Cour 602e000379 hid usage flags
https://learn.microsoft.com/en-us/windows-hardware/drivers/hid/hid-usages
2024-03-03 19:53:33 +01:00
Thomas la Cour f93074a082 A few extra gdi procs for icons, cursors and drawing 2024-03-03 19:53:33 +01:00
Thomas la Cour 28f05e8aaa SHChangeNotify + flags
https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shchangenotify
2024-03-03 19:53:33 +01:00
Thomas la Cour 9eb1596939 Flags for GlobalAlloc
https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globalalloc
2024-03-03 19:53:33 +01:00
Thomas la Cour 8412352e5a bitmap v5 header
https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapv5header
2024-03-03 19:53:33 +01:00
Jeroen van Rijn 4c35633e01 math.big constants were no longer initialized
Fixes #3243
2024-03-03 15:09:38 +01:00
Laytan Laats b1371d5c7a fix minor cgltf binding issue 2024-03-01 20:33:23 +01:00
Laytan Laats 3ada83a503 clean imports 2024-03-01 20:32:07 +01:00
Laytan Laats 50ded324e0 move va_list into core:c 2024-03-01 20:30:19 +01:00
gingerBill 674bd94f72 Add check to see if raylib is imported with ShowCursor on sys/windows 2024-03-01 18:30:23 +00:00
gingerBill ff24cfe314 Fix debug issue with maps 2024-03-01 14:00:14 +00:00
gingerBill bc191d4f84 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-03-01 13:36:12 +00:00
gingerBill 5c20676c76 Fix type for SDL LoadFile(_RW) 2024-03-01 13:36:06 +00:00
gingerBill 11b7be1640 Merge pull request #3203 from listeriaceae/master
port math.round from Golang
2024-03-01 11:33:43 +00:00
gingerBill 6ae8288142 Merge pull request #3240 from laytan/macos-self-contained-releases
reduce dynamic library dependencies for macos release
2024-03-01 11:33:20 +00:00
gingerBill 7f1069cb0b Add Recursive_Mutex procedures to procedure groups 2024-03-01 11:31:13 +00:00
blob1807 41fbaaf1d3 changed to use reflect.enum_name_from_value_any 2024-03-01 14:53:39 +10:00
blob1807 f14babe419 Merge branch 'odin-lang:master' into json-better-enum-support 2024-03-01 14:24:51 +10:00
avanspector 0bb2327d76 Merge branch 'haiku' of https://github.com/avanspector/Odin into haiku 2024-03-01 00:43:13 +01:00
avanspector f92042e7dd Merge branch 'odin-lang:master' into haiku 2024-03-01 00:42:28 +01:00
avanspector 1861ecff86 Merge branch 'haiku' of https://github.com/avanspector/Odin into haiku 2024-03-01 00:42:08 +01:00
avanspector d4d9f55556 Update threading.cpp 2024-03-01 00:41:28 +01:00
Laytan Laats 23cd64ec35 reduce dynamic library dependencies for macos release 2024-02-29 23:39:18 +01:00
Laytan Laats 6734a7096a makes raylib and stb_rect_pack free of libc 2024-02-29 23:33:25 +01:00
gingerBill 3263e54144 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-02-29 20:20:43 +00:00
gingerBill 6805b85f89 Fix leap year bug 2024-02-29 20:20:37 +00:00
gingerBill 88c97cbbd0 Merge pull request #3237 from laytan/macos-self-contained-releases
fix releases being a zip of a zip
2024-02-29 16:16:04 +00:00
Laytan Laats 17b1c8d338 fix releases being a zip of a zip 2024-02-29 17:00:20 +01:00
gingerBill 0a5c85f8e3 Merge pull request #3207 from Tetralux/printfln
Add `fmt.*printfln`
2024-02-29 14:04:38 +00:00
gingerBill 9c20df5b1b Merge pull request #3201 from Yawning/feature/avl
core/container/avl: Add an AVL tree implementation
2024-02-29 14:02:45 +00:00
avanspector 5d6b4eda1e Merge branch 'odin-lang:master' into haiku 2024-02-29 03:16:04 +01:00
avanspector 290ada7f90 add exit to core:os 2024-02-28 22:43:55 +01:00
avanspector bf37bee4f7 improve core:sys 2024-02-28 22:29:06 +01:00
gingerBill 7df7fec6f7 Keep -vet happy 2024-02-28 18:27:49 +00:00
gingerBill e423a6d692 Make types distinct 2024-02-28 18:25:29 +00:00
gingerBill f4c74a9f32 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-02-28 18:25:06 +00:00
gingerBill dce176fa39 Remove unnecessary use of transmute 2024-02-28 18:24:59 +00:00
gingerBill d666ff3744 Merge pull request #3135 from colrdavidson/basic_egl
Add support for basic EGL on Linux
2024-02-28 14:42:49 +00:00
gingerBill 1678391db3 Merge pull request #3224 from laytan/macos-self-contained-releases
Make MacOS releases self contained / bundle LLVM
2024-02-28 13:44:50 +00:00
gingerBill d1174f66bc Fix #3233 2024-02-28 13:41:54 +00:00
gingerBill 84a7e03178 Merge pull request #3220 from laytan/promote-types-in-c-varargs
Promote types in `#c_varargs` according to C rules
2024-02-28 10:49:28 +00:00
gingerBill 1bffc8baac Merge pull request #3228 from EddieWoodley/glfw-raw-mouse-supported
vendor/glfw: Add RawMouseMotionSupported to wrapper
2024-02-28 10:48:08 +00:00
gingerBill c558b694eb Merge pull request #3232 from karl-zylinski/raylib-5-binding-errors
Additional fixes for errors in Raylib bindings since Raylib 4 -> 5 upgrade.
2024-02-28 10:46:41 +00:00
gingerBill a06bde729b Merge pull request #3234 from odin-lang/rtti-table-layout
Change `runtime.type_table` layout to allow RTTI to be constantly initialized
2024-02-27 16:25:47 +00:00
gingerBill 5107bdc06b Make lb_type_info use a procedure to load the global value 2024-02-27 15:45:53 +00:00
gingerBill 5137d12d36 Fix lb_type_info for the new layout 2024-02-27 15:40:45 +00:00
gingerBill c6ee025063 Add type info generation for bit_field 2024-02-27 15:27:51 +00:00
gingerBill 826cf1508b Remove __$startup_type_info procedure 2024-02-27 15:09:33 +00:00
gingerBill 51edf01162 Change type info table to be initializable constantly
[]Type_Info -> []^Type_Info
2024-02-27 15:07:55 +00:00
avanspector 87f6f3a1fe Merge branch 'haiku' of https://github.com/avanspector/Odin into haiku 2024-02-27 02:38:19 +01:00
avanspector fca691a066 fix core:thread and a memory leak
in the future probably native non-pthread implementation for haiku will be required
2024-02-27 02:38:06 +01:00
avanspector 494cac02d7 Merge branch 'odin-lang:master' into haiku 2024-02-27 02:00:19 +01:00
avanspector 38c69b9691 small fixes 2024-02-27 01:59:17 +01:00
Colin Davidson deb8922181 Merge branch 'master' into basic_egl 2024-02-26 12:17:53 -05:00
Karl Zylinski cdda8f0eb9 Additional fixes for errors in Raylib bindings since Raylib 4 -> 5 upgrade. 2024-02-26 17:16:45 +01:00
gingerBill cba8cb2201 Merge pull request #3231 from karl-zylinski/raylib-model-animation-binding-fix
Fix ModelAnimation in raylib.odin missing a field
2024-02-26 12:57:39 +00:00
Karl Zylinski ae67f37fc1 Fix ModelAnimation in raylib.odin missing a field. 2024-02-26 13:32:16 +01:00
avanspector 8d4bb35bcc Update futex_haiku.odin 2024-02-26 08:14:05 +01:00
avanspector 180902468f Revert "fix haiku"
This reverts commit 7290c69257.
2024-02-26 08:09:58 +01:00
avanspector 7290c69257 fix haiku 2024-02-26 08:07:17 +01:00
avanspector 3ebf5dcc0e fix haiku 2024-02-26 07:59:53 +01:00
avanspector 9d4c2ba0d8 fix haiku 2024-02-26 07:43:10 +01:00
avanspector 1d79521e81 fix sys/haiku 2024-02-26 06:18:33 +01:00
avanspector 31d7ef5696 Update os_haiku.odin 2024-02-26 06:16:13 +01:00
avanspector 8c621453ae update sys/haiku 2024-02-26 06:13:54 +01:00
avanspector c712af3bc2 Update os_haiku.odin 2024-02-26 04:54:21 +01:00
avanspector f0a89f8d5d add sys/haiku 2024-02-26 04:41:30 +01:00
avanspector 9b839621a9 Update os_haiku.odin 2024-02-25 18:49:42 +01:00
avanspector 66456714e1 update pthread 2024-02-25 18:45:00 +01:00
avanspector fc8e5b8a61 Update os_haiku.odin 2024-02-25 18:31:14 +01:00
avanspector 05cfc89283 fix core:os 2024-02-25 18:20:03 +01:00
avanspector dc5cf23066 add haiku to unix 2024-02-25 16:50:04 +01:00
avanspector 2e80879e88 Update os_haiku.odin 2024-02-25 16:24:50 +01:00
avanspector dfa0ccf976 Update entry_unix.odin 2024-02-25 03:46:52 +01:00
avanspector 6c16860be6 fix runtime and libc 2024-02-25 03:43:41 +01:00
avanspector d032cff23b Update os_specific_haiku.odin 2024-02-25 03:38:15 +01:00
avanspector c3746d9f56 fix core and libc 2024-02-25 03:32:35 +01:00
avanspector 0fa6ba726f add haiku build token 2024-02-25 03:03:12 +01:00
avanspector b03f17dd8d add haiku to base:runtime and core:c/libc 2024-02-25 02:59:45 +01:00
avanspector 24c8b15409 small fixes 2024-02-25 02:38:35 +01:00
avanspector 028a79e66c Update threading.cpp 2024-02-25 02:34:41 +01:00
avanspector 0a6673220b Merge branch 'haiku' of https://github.com/avanspector/Odin into haiku 2024-02-25 02:24:58 +01:00
avanspector 88add0b6b1 Improve Haiku support 2024-02-25 02:24:52 +01:00
Eddie Woodley 8a78b0d241 vendor/glfw Add RawMouseMotionSupported to wrapper 2024-02-24 23:06:05 +00:00
avanspector 824c831190 Implement futex 2024-02-24 23:46:55 +01:00
Yawning Angel 874d6ccb60 core/container/avl: Initial import 2024-02-24 14:05:15 +09:00
Yawning Angel db3279e7da test/core/container: Refactor for multiple container types 2024-02-24 14:05:15 +09:00
Yawning Angel 9251e06143 tests/core: Bring the Makefile more in-sync with build.bat 2024-02-24 14:05:15 +09:00
gingerBill a642ea0b28 Add intrinsics.type_bit_set_backing_type 2024-02-23 11:38:23 +00:00
gingerBill 00fc4c4e1b Make that warning an error with -vet-style 2024-02-22 20:21:21 +00:00
gingerBill 9ea11da00f Add warning when using bit_field when a bit_set would be a much better idea. 2024-02-22 20:10:56 +00:00
gingerBill a8909f06ae Improve parsing for bit_field 2024-02-22 20:10:38 +00:00
Laytan Laats ee543a304a Zip so compiler keeps executable permissions 2024-02-22 21:04:08 +01:00
gingerBill 5c5b78cbbe Improve bit_field printing 2024-02-22 19:48:44 +00:00
gingerBill 54515af8cc Add field tags to bit_field 2024-02-22 19:41:48 +00:00
Laytan Laats b894df2125 Make MacOS releases self contained / bundle LLVM 2024-02-22 20:38:25 +01:00
gingerBill 3f193d7446 Format change 2024-02-22 19:27:13 +00:00
gingerBill e127d21fed Check for pseudo-fields before bit fields 2024-02-22 19:24:50 +00:00
gingerBill 3060225f46 Simplify usage code 2024-02-22 19:24:16 +00:00
gingerBill c14b9d461a Support using of a bit_field within a struct 2024-02-22 19:14:16 +00:00
gingerBill 8060e3170e Remove debug message 2024-02-22 18:53:02 +00:00
gingerBill 980947b355 Give a better error message when the user uses context as if it was an identifier in a field list. 2024-02-22 18:52:17 +00:00
gingerBill fd987b29ff Improve error handling with assignments to bit_field using constants 2024-02-22 18:47:43 +00:00
gingerBill afcc2889ec Support compound literals for bit_field 2024-02-22 18:41:15 +00:00
gingerBill 5f001f6d51 Allow casting between a bit_field and its backing type 2024-02-22 18:15:13 +00:00
gingerBill fc07211772 Change hack a little 2024-02-22 17:43:37 +00:00
gingerBill c9e37a08be Add backing type of a bit_field to the doc-format 2024-02-22 17:41:22 +00:00
gingerBill dcbcf75269 Add doc-format support for bit_field 2024-02-22 17:37:42 +00:00
gingerBill 59479b2ba6 Fix typo 2024-02-22 17:26:32 +00:00
gingerBill 007bd993a6 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-02-22 17:24:48 +00:00
gingerBill 5a84a08225 Add general support for bit_fields 2024-02-22 17:24:42 +00:00
Laytan Laats bb23648c71 Also convert and promote bit_set types for #c_varargs 2024-02-22 18:17:52 +01:00
gingerBill a4b8c1ea17 Begin work adding bit_field 2024-02-22 15:55:54 +00:00
Jeroen van Rijn 20e75cd463 Merge pull request #3221 from Tetralux/net/reservedports
[net] Better error code for binding a privileged port without root access
2024-02-22 16:23:15 +01:00
Tetralux d74ddb2d91 fixup 2024-02-22 15:01:55 +00:00
Tetralux ec0831da70 [net] Better error code for binding a privileged port without root access on Darwin
This condition results in os.EACCESS, which we were translating to Broadcast_Disabled.
This was the case because binding to the broadcast address on a UDP port, without setting the BROADCAST flag, also results in this error.

Given the fact that reserved ports also produce this error, we now check for this condition in net.bind() and translate it to a custom, clearer error:
Privileged_Port_Without_Root.
2024-02-22 14:55:27 +00:00
gingerBill b12ba1508e Update vulkan bindings for to work with the new keyword bit_field 2024-02-22 14:09:12 +00:00
gingerBill f3b0b82461 Fix futex 2024-02-22 14:04:31 +00:00
gingerBill fea38f6910 Minor changes to futex implementation on Linux 2024-02-22 14:01:39 +00:00
gingerBill 213b2fd0f8 Add bit_field as a keyword 2024-02-22 14:01:23 +00:00
gingerBill 42d595f6a1 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-02-22 13:59:27 +00:00
gingerBill 656de10ba4 Minor changes to sync/chan (HIGHLY EXPERIMENTAL) 2024-02-22 13:59:22 +00:00
Laytan Laats f6f3a760bc Promote types in #c_varargs according to C rules 2024-02-21 22:05:11 +01:00
gingerBill bafc791f1c Merge pull request #3219 from laytan/fix-terminators-in-defer
Fix divergent proc call in `defer`
2024-02-21 18:53:40 +00:00
Laytan Laats 1fc256dd90 Fix divergent proc call in defer
Fixes #3216
Fixes #2985
2024-02-21 19:43:34 +01:00
gingerBill 41549b502b Basic concept of core:sync/chan 2024-02-21 15:24:24 +00:00
gingerBill f989f4df3e Add sync.One_Shot_Event 2024-02-21 13:08:12 +00:00
gingerBill 21d1c0e5a4 Revert change since it is not needed 2024-02-21 12:58:26 +00:00
gingerBill d7b7804215 if -> while in wait_signal_until_available to check for spurious wake-ups 2024-02-21 12:55:26 +00:00
gingerBill 8472338bfa Add reflect.enum_name_from_value and reflect.enum_name_from_value_any 2024-02-21 12:43:09 +00:00
gingerBill 1de1d97429 Merge pull request #3213 from laytan/add-backend-info-to-odin-report
Add backend info to odin report
2024-02-21 12:33:06 +00:00
gingerBill f21ead4f78 Merge pull request #3212 from laytan/improve-net-tests
Improve net tests
2024-02-21 12:32:43 +00:00
blob1807 a95cead8e7 add all inter types to switch 2024-02-21 14:05:50 +10:00
blob1807 c276b1c0bc replace spaces with tabs 2024-02-21 11:51:29 +10:00
blob1807 b39ef29ec6 add missing comma 2024-02-21 11:15:35 +10:00
blob1807 b2b8b14955 Add better support for Enums in json
Can now output enum value's name instead of its underlineing value
2024-02-21 11:07:03 +10:00
blob1807 7e0473dded Revert json union fix 2024-02-21 11:03:15 +10:00
Laytan Laats e6bd79c882 Make sure we are listening before starting the client 2024-02-20 23:54:11 +01:00
Laytan Laats 9e417592e3 Add logs to flaky test 2024-02-20 23:45:15 +01:00
Laytan Laats db87c34613 Add backend info to odin report 2024-02-20 23:23:56 +01:00
Laytan Laats 159257597a Convert weird DOS line-endings to UNIX 2024-02-20 23:22:05 +01:00
Laytan Laats bdd6a86d73 Remove flaky test
It wasn't testing the right thing in the previous
iteration.
And in this iteration the behaviour is a timeout on Unix, and
nothing on Windows.
2024-02-20 23:15:18 +01:00
Laytan Laats 1ab3ec5731 Improve net tests
Watching the sporadic CI failures it seems to come from these tests a
lot of the time, this PR cleans up and simplifies (while testing the
same things):

1. Lots of tests were using threads without a need for it
2. Tests had hardcoded `time.sleep` calls which is never a good idea
3. An unclear abstraction was implemented without a real need
4. They weren't being ran on non-windows
5. The `client_connects_to_open_but_not_accepting_port` was not doing
   what you wanted to test for, the `tcp_server` proc was returning, and
   then `dial` was called, which meant that the server already closed
   and you got a refusal error. Now it correctly listens without
   accepting, which even results in a different error because the kernel
   buffer would have buffered the send
2024-02-20 23:06:18 +01:00
blob1807 004cd4933d Merge branch 'master' of https://github.com/blob1807/Odin 2024-02-21 00:43:27 +10:00
blob1807 14ee2181cb Fix bug https://github.com/odin-lang/Odin/issues/3173 2024-02-21 00:42:11 +10:00
gingerBill b43c1f2b5b Merge pull request #3134 from laytan/non-universal-binaries-raylib
vendor/raylib: change to non-universal binaries
2024-02-19 14:18:44 +00:00
Tetralux b1e608bfba [fmt] Add *printfln()
Adds the following procedures, which just call through to the `printf` versions, with `newline = true`; a new parameter
also added in this commit.
In all cases, `wprintf` is the one that ultimately writes the newline, if requested.

- printfln
- fprintfln
- eprintfln
- aprintfln
- tprintfln
- bprintfln
- caprintfln
- ctprintfln
- sbprintfln
- wprintfln
2024-02-18 16:14:59 +00:00
gingerBill 57c5455827 Merge pull request #3206 from flysand7/linux-fdflags-fix
[sys/linux]: Fix numeric values for socket fd flags
2024-02-18 14:56:31 +00:00
flysand7 cc185d98b4 [sys/linux]: Fix numeric values for socket fd flags 2024-02-18 23:04:41 +11:00
Juan Ignacio Díaz cd61251d39 add Go license 2024-02-17 11:49:07 -03:00
gingerBill 43a199b57b Merge branch 'master' of https://github.com/odin-lang/Odin 2024-02-17 13:42:02 +00:00
gingerBill fa1875a8f1 Minor changes to os2 2024-02-17 13:41:54 +00:00
James Duran 44aae76294 Fix syntax mistake again
Sorry for being blind
2024-02-16 10:55:55 -08:00
James Duran 009cebe8bf Fix Syntax Mistake 2024-02-16 10:50:54 -08:00
James Duran 9399cb53b6 Make into_dynamic_soa more concise and remove builtin tag from it 2024-02-16 10:46:46 -08:00
gingerBill bed81c8829 Merge pull request #3197 from laytan/update-miniaudio
Update miniaudio to 0.11.21
2024-02-16 18:08:29 +00:00
Juan Ignacio Díaz 7a592cbb31 port math.round from Golang 2024-02-16 13:23:44 -03:00
Slendi c178f7199d Get Odin to compile on Haiku
This patch makes Odin to compile on Haiku which is a good first step.
Now, all that's needed to do is to figure out how to do futexes, which
I am blaming for the program crashing.
2024-02-15 15:51:28 +02:00
James Duran a4d3777ab2 Added into_dynamic_soa, unordered_remove_soa, and ordered_remove_soa 2024-02-14 16:51:09 -08:00
Laytan Laats e931c82b9b miniaudio: add version mismatch check 2024-02-14 21:55:15 +01:00
laytan a7f0275093 miniaudio: update .lib to 0.11.21 2024-02-14 21:17:12 +01:00
laytan 9ab2fbea00 miniaudio: update .lib 2024-02-14 21:07:57 +01:00
Laytan Laats 7fe86ed565 miniaudio: fix wrong sizes for ma_device 2024-02-14 21:00:26 +01:00
Laytan Laats 16584779fb miniaudio: update to 0.11.21 2024-02-14 19:57:57 +01:00
gingerBill c5c2a4d09d Fix typo 2024-02-13 17:13:39 +00:00
gingerBill 912c326d8b Fix typo that causes map info debug issues 2024-02-13 17:06:04 +00:00
gingerBill d496dbf3a0 Fix race condition with #soa 2024-02-13 16:54:41 +00:00
Laytan Laats 88e6980b13 fix build tags 2024-02-13 17:34:40 +01:00
Laytan Laats 0d413b8136 implement part of core foundation framework bindings for err message 2024-02-13 17:34:40 +01:00
Laytan Laats 32a4a5e601 remove darwin from bsd filename 2024-02-13 17:34:40 +01:00
Laytan Laats 91cf0826c1 use Security.framework with SecRandomCopyBytes for rand_bytes on darwin 2024-02-13 17:34:40 +01:00
Laytan Laats 3bc172c70b add crypto.rand_bytes for Darwin and FreeBSD 2024-02-13 17:34:00 +01:00
gingerBill cbfb32c34c Fix race condition with regards to #soa arrays by using the fields mutex 2024-02-13 16:21:41 +00:00
gingerBill 5cd57a3a7f Use Raw_Map as the debug information for a map 2024-02-13 15:50:07 +00:00
gingerBill 563ce2bd81 Merge pull request #3193 from Lperlind/master
Add ID3DUserDefinedAnnotation
2024-02-13 14:17:20 +00:00
Lucas Perlind 9469b90b01 Add ID3DUserDefinedAnnotation 2024-02-13 17:13:17 +11:00
gingerBill d2e1ec13f0 Merge pull request #3192 from Lperlind/revert-the-matrices
Revert the matrices
2024-02-12 23:44:36 +00:00
Lucas Perlind 6df07a2c0a Remove bounds checking on a lot of linalg 2024-02-13 10:23:29 +11:00
Lucas Perlind c0d407a2b4 Revert "Change minor/adjoint to be row, col from c, r to be consistent with [row, col] syntax; Add #no_bounds_check were appropriate"
This reverts commit 5dd2e38aff.
2024-02-13 10:13:34 +11:00
gingerBill f378367fe7 Store cell data in map debug metadata 2024-02-12 15:17:06 +00:00
gingerBill c291fffce1 Add metadata type to maps debug information to aid debuggers knowing what is in it it 2024-02-12 12:29:37 +00:00
gingerBill 900fe95ba0 Split out linalg.identity between matrices and array-based matrix 2024-02-12 12:08:43 +00:00
gingerBill 5dd2e38aff Change minor/adjoint to be row, col from c, r to be consistent with [row, col] syntax; Add #no_bounds_check were appropriate 2024-02-12 11:54:24 +00:00
gingerBill 5ad8ebba9f Merge pull request #3188 from Tetralux/fixchdir
[os] Fix os.change_directory(), os.set_current_directory()
2024-02-12 11:24:45 +00:00
gingerBill e7719eed65 Merge pull request #3189 from mothfuzz/json_unmarshal_enumerated_enums_fix
remove return statement from case Type_Info_Enumerated_Array
2024-02-12 11:23:51 +00:00
Kay 5f49b8997a remove return statement from case Type_Info_Enumerated_Array, as it causes early exit in JSON unmarshalling. 2024-02-12 01:45:11 -06:00
Tetralux d6734c85b8 [os] Fix os.change_directory(), os.set_current_directory()
- set_current_directory() was leaking the wstring path string because it wasn't using the temp allocator.
- change_directory() wasn't calling SetCurrentDirectoryW() under the lock!
2024-02-12 06:03:51 +00:00
gingerBill 4ca23499fa Add raymath procedures (with numerous deprecated attributes to suggest to use array programming) 2024-02-10 16:31:03 +00:00
gingerBill e201a2fabb Add rand.choice_enum 2024-02-10 15:13:09 +00:00
gingerBill 5c4485f657 Add #load_directory(path: string) > []runtime.Load_Directory_File 2024-02-09 15:18:29 +00:00
gingerBill bae2a6fc1e Merge pull request #3184 from Lperlind/master
Add more window procedures
2024-02-09 11:59:12 +00:00
Lucas Perlind 8777fa1c04 Add more window procedures 2024-02-09 14:04:16 +11:00
gingerBill d771b3286d Merge pull request #3182 from laytan/fix-instrumentation-in-debug-mode
fix instrumentation in debug mode
2024-02-08 21:36:43 +00:00
Laytan 0e6dd56ac1 fix instrumentation in debug mode 2024-02-08 22:29:45 +01:00
gingerBill 9127e584c5 Merge pull request #3181 from laytan/fix-no-crt-on-linux
fix -no-crt on Linux
2024-02-08 21:07:42 +00:00
Laytan eab0e730a0 fix -no-crt on Linux 2024-02-08 19:48:37 +01:00
gingerBill 7128bc4b34 Add core:relative
This will eventually replace the #relative types
2024-02-08 15:15:16 +00:00
gingerBill 7b672ac72a Disallow mixture of polymorphic $ names and normal identifiers within record parameters 2024-02-08 14:03:03 +00:00
gingerBill 8f4ab3c07d Add check for a procedure 2024-02-08 13:49:27 +00:00
gingerBill dc5cfacc0a Fix edge case for procedures 2024-02-08 13:45:18 +00:00
gingerBill 3aea2e1fff Merge branch 'master' of https://github.com/odin-lang/Odin 2024-02-08 13:41:07 +00:00
gingerBill 59933b244d Allow polymorphic checking with intrinsics.type_is_subtype_of(Derived_Type, Poly_Type) 2024-02-08 13:41:02 +00:00
gingerBill 42aca72d9f Correct the logic for parapoly records to match that of procedures (polymorphic non-typeid parameters) 2024-02-08 13:21:41 +00:00
gingerBill 7034a31745 Merge pull request #3180 from z64/z64/fix
Remove invalid allocator assignment to slice
2024-02-08 12:39:49 +00:00
Zac Nowicki 9d0786ded7 Remove invalid allocator assignment to slice
`T` is `#soa[]$E`, which does not carry an allocator.
2024-02-08 04:14:16 -05:00
gingerBill 4c51706941 Merge pull request #3179 from laytan/fix-ci
fix ci
2024-02-07 19:09:04 +00:00
Laytan Laats a8c4f46747 fix ci 2024-02-07 19:53:52 +01:00
gingerBill 8e367d221b Merge branch 'master' of https://github.com/odin-lang/Odin 2024-02-07 17:16:05 +00:00
gingerBill a08250ac5b Improve error handling for missing library collection provided by the compiler 2024-02-07 17:15:59 +00:00
gingerBill 131c71ea76 Merge pull request #3142 from jay-j/feature/gl-allow-geometry-shaders
Expose OpenGL shader procs to allow creation of pipelines with geometry shaders
2024-02-07 16:09:58 +00:00
gingerBill 9db04fe446 Merge pull request #3156 from laytan/spall-instrumentation
Make spall able to be used in instrumentation procedures
2024-02-07 12:16:20 +00:00
gingerBill abaa906f34 Fix lb_hasher_proc_for_type 2024-02-07 11:05:38 +00:00
gingerBill fa093d9b09 Add runtime.map_insert_and_check_for_previous 2024-02-06 23:58:22 +00:00
gingerBill 4035a226da Fix filepath.rel allocation behaviour 2024-02-06 23:39:20 +00:00
gingerBill df5ee2dd06 Merge pull request #3178 from laytan/fix-virtual-static-reset-logic
mem/virtual: fix arena_static_reset_to inverted logic
2024-02-06 23:31:07 +00:00
Laytan 9b4cd0743c mem/virtual: fix arena_static_reset_to inverted logic 2024-02-06 20:24:38 +01:00
laytan 3f090ed523 fix for instrumenting on Windows 2024-02-06 19:55:09 +01:00
gingerBill 79173ef119 Merge pull request #3136 from Yawning/feature/crypto-hash
core:crypto/hash - Add and refactor
2024-02-06 17:40:45 +00:00
Yawning Angel 44758f2a60 core/crypto: Stop using context.temp_allocator
The max digest size for the foreseeable future will be 512 bits, and the
max block size is currently 1152 bits (SHA3-224).  If people add more
exotic hash algorithms without bumping the constants when required,
tests will fail.

The stream buffer will currently be 576 bytes, which is "fine" to just
stick on the stack, and is a sensible multiple of the more common block
size of 64 bytes.
2024-02-07 02:33:53 +09:00
gingerBill 1f0b24b735 Remove unneeded casts 2024-02-06 17:22:13 +00:00
gingerBill 327853ab92 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-02-06 17:20:13 +00:00
gingerBill a6878fcd91 Clean up code for initialize_symbols 2024-02-06 17:20:07 +00:00
gingerBill 61202b5abd Merge pull request #3174 from thetarnav/webgl2-matrix-flatten-2
Use `intrinsics.matrix_flatten` in `webgl2.odin`
2024-02-06 17:00:33 +00:00
Yawning Angel 56516ee8b2 core/crypto/poly1305: Relax the tag length check on the verify helper 2024-02-07 00:42:01 +09:00
Yawning Angel 1cc639bc93 core/crypto/hmac: Initial import 2024-02-07 00:42:01 +09:00
Yawning Angel 2357293e05 core/crypto/hash: Make the low level interface allocator-less
Just (ab)using reflect to victory is probably fine.
2024-02-07 00:37:18 +09:00
Yawning Angel 7a8b1669b0 core/crypto: Expose the block sizes for every hash algorithm
While I just went and made this private, this information is required
for keying HMAC.
2024-02-07 00:37:18 +09:00
Yawning Angel bc160d2eb7 tests/core/crypto: Reorganize
All of our crypto is modern now unless exiled to the legacy sub-package,
so move the test cases for the currently un-unified algorithms into the
main test driver file, and rename the benchmark driver to reflect
reality.
2024-02-07 00:37:18 +09:00
Yawning Angel b02b85d242 core/crypto/shake: SHAKE is an XOF, not a hash 2024-02-07 00:37:18 +09:00
Yawning Angel 1d151c4c92 tests/core/crypto: Cleanup/modernize a bit 2024-02-07 00:37:18 +09:00
Yawning Angel 899fab64d9 core/crypto: Documentation cleanups 2024-02-07 00:37:18 +09:00
Yawning Angel 00ab3beed9 core:crypto/hash: Add a generic higher level hash interface
There is a lot of code duplicated in convenience methods in each hash
implementation, and having a generic hash type makes implementing
higher-level constructs such as HMAC significantly easier down the road.
2024-02-07 00:37:18 +09:00
Yawning Angel ca10fc2d47 repo: Add yet another test binary to .gitignore 2024-02-07 00:37:18 +09:00
gingerBill 1ed6a484ac Merge pull request #3175 from Murtagy/patch-1
Update raylib.odin
2024-02-06 14:59:35 +00:00
gingerBill b0675358c3 Add angle_between and matrix2_rotate 2024-02-06 14:09:05 +00:00
Murtagy 456dd22dc4 Update raylib.odin 2024-02-05 21:38:17 +03:00
Laytan 02b8fefa30 indent doc.odin, makes it render nicely on the documentation site 2024-02-05 18:59:08 +01:00
Laytan 95808fd2e7 remove unneeded no instrumentation comment, are all foreign procs anyway 2024-02-05 18:54:37 +01:00
Laytan e63d71c23b implement bsd's, same as darwin 2024-02-05 18:48:17 +01:00
Damian Tarnawski 23a49ce65b USe intrinsics.matrix_flatten in webgl2.odin 2024-02-05 18:28:03 +01:00
Laytan Laats ca6300c860 spall instrumentation 2024-02-05 16:54:22 +01:00
gingerBill 1ebb7f8e9d Merge pull request #3170 from flysand7/run-args-fix
Make run args take the first '--' as the start of the args, instead of the last '--'
2024-02-05 13:58:32 +00:00
gingerBill 4685cf1085 Merge pull request #3140 from JustinRyanH/master
Implement `last_write_time` and `last_write_time_by_name` for Darwin
2024-02-05 13:57:28 +00:00
gingerBill 80a0b161b0 Force 128-bit calls on wasm 2024-02-05 13:51:16 +00:00
gingerBill 27feb5998c Add require to 128-bit and f16 casts 2024-02-05 13:49:10 +00:00
gingerBill e88db2818b force requiring the 128-bit calls on WASM targets 2024-02-05 13:48:08 +00:00
gingerBill 19535d8721 Add require flags to 128-bit integer procedures 2024-02-05 11:11:28 +00:00
flysand7 8ea8fbeccb Make run args take the first '--' as the start of the args, instead of the last '--' 2024-02-04 14:25:53 +11:00
Jeroen van Rijn 4e300ff90a Merge pull request #3167 from Murtagy/patch-1
Typo in comment in raylib
2024-02-03 17:04:10 +01:00
Murtagy 7bf25a4cf2 typo in comment 2024-02-03 18:43:34 +03:00
gingerBill 5f0f9f477e Merge pull request #3161 from laytan/fix-no-crt-darwin
fix -no-crt on Darwin
2024-02-03 12:30:00 +00:00
gingerBill dd7c65a89c Merge pull request #2998 from laytan/os-improvements
OS improvements
2024-02-03 12:29:39 +00:00
gingerBill 8620281191 Merge pull request #3163 from laytan/arm-releases-and-ci
Add MacOS ARM releases and CI
2024-02-03 12:25:49 +00:00
gingerBill c311a60aaf Merge pull request #3164 from FourteenBrush/master
Fix compiler panic: "src/parser.cpp(128): Panic: Unhandled Ast or branch expression"
2024-02-03 12:24:54 +00:00
gingerBill 2993490c75 Merge pull request #3165 from korvahkh/fix-dyn-array-init
Fix #3155
2024-02-03 12:24:40 +00:00
gingerBill 60b324d4ed Merge pull request #3166 from mothfuzz/patch-2
Change ClearMask to ColorMask in webgl.odin
2024-02-03 12:24:10 +00:00
Kay 89a2fdd106 Change ClearMask to ColorMask in webgl.odin
https://registry.khronos.org/OpenGL-Refpages/gl4/html/glColorMask.xhtml
2024-02-02 23:42:37 -06:00
korvahkh 8530829ca4 Fix dynamic array index = value with const value initializing to 0 2024-02-02 15:27:39 -06:00
FourteenBrush 0e5d7801dd Fix code style 2024-02-02 21:17:10 +01:00
Laytan Laats d5db49a3b0 name the workflows 2024-02-02 21:10:35 +01:00
Laytan Laats 606f11ebe8 fix hxa test use after free, skip weird pow test failure 2024-02-02 21:10:11 +01:00
Laytan Laats 07a4f4d017 add MacOS ARM target to CI and releases 2024-02-02 21:09:57 +01:00
FourteenBrush d463adfe4f Merge remote-tracking branch 'upstream/master' 2024-02-02 21:01:52 +01:00
FourteenBrush 16bd19ed43 Fix Unhandled Ast_OrBranchExpr 2024-02-02 21:00:00 +01:00
Laytan Laats eb811e8341 fix -no-crt on Darwin 2024-02-02 19:49:40 +01:00
Justin Hurstwright 8a63b6dff7 fix: remove returns ErrNo for Windows, FreeBSD, Unix 2024-02-02 09:10:25 -06:00
Justin Hurstwright 829654e3a2 steal the last_write from freebsd implementation 2024-02-02 09:10:25 -06:00
gingerBill cec08114fd Mock out comments 2024-02-02 14:57:22 +00:00
gingerBill bf90b61908 Fix type_elem_type for complex32 and quaternion64 2024-02-02 14:52:42 +00:00
gingerBill ae0a5b1a87 RUNTIME_REQUIRE :: false 2024-02-02 12:03:14 +00:00
gingerBill 55ff9b857e Add contextless where missing 2024-02-02 11:51:26 +00:00
gingerBill e7122a0950 Minimize extra dependencies if u128/i128 and f16 are not used 2024-02-02 11:42:22 +00:00
gingerBill 539cec7496 Move Tracking_Allocator to its own file. 2024-02-01 13:01:38 +00:00
gingerBill 000709b594 Make file_console_logger.odin be ignored on freestanding targets 2024-01-31 22:01:35 +00:00
gingerBill c51f94b600 Merge pull request #2978 from thetarnav/patch-2
Many small typos and fixes to wasm bindings
2024-01-31 21:02:03 +00:00
gingerBill b703d5ca58 Merge pull request #3157 from jakubtomsu/fix-generic-fixed-soa-ptr
Fix polymorphic fixed SOA pointers
2024-01-31 20:49:30 +00:00
jakubtomsu aff345f57f Allow fixed SOA structs 2024-01-31 21:38:05 +01:00
gingerBill a4664f82cc Fix dummy code 2024-01-31 14:10:18 +00:00
gingerBill 9fb090d1b8 Merge pull request #3141 from laytan/add-all-packages-flag-for-tests
Add `odin test -all-packages` to be able to test an entire project
2024-01-31 11:59:54 +00:00
gingerBill 4a2ad3b13a Merge pull request #3152 from laytan/fix-no-base-collection-in-releases
Fix not having the base collection in releases
2024-01-31 11:58:53 +00:00
Laytan Laats 9d5afee24b Fix not having the base collection in releases 2024-01-30 21:15:56 +01:00
gingerBill 6736205723 Merge pull request #3138 from FourteenBrush/master
Add a testing.expectf proc as a way to avoid a tprintf call.
2024-01-29 17:33:29 +00:00
gingerBill f0a7f1812f Rename runtime.os_write to runtime.stderr_write 2024-01-29 16:29:56 +00:00
gingerBill 9c9ae5987a Fix #3150 2024-01-29 16:21:26 +00:00
gingerBill f588593ff1 Merge pull request #3147 from odin-lang/base-work
`base` library collection work
2024-01-29 16:18:38 +00:00
gingerBill a626adac8e Use long-form names and alias with short-form UNIX-like names 2024-01-29 13:33:39 +00:00
gingerBill 338793b68e Remove use of incl in vendor:nanovg 2024-01-29 13:11:14 +00:00
gingerBill 59575d9b22 Remove incl and excl 2024-01-29 12:52:41 +00:00
gingerBill b58a0b60d0 Add matrix related intrinsics to dummy file 2024-01-29 11:48:50 +00:00
gingerBill 3a4c82abf8 Move core:(builtin|intrinsics) to base: 2024-01-29 11:46:16 +00:00
IllusionMan1212 301b9eef31 vendor/x11: added XQueryExtension, XGetEventData, and XFreeEventData 2024-01-29 06:22:33 +02:00
IllusionMan1212 36ed8fe55d vendor/x11: change display to be a ^Display in XGenericEventCookie struct 2024-01-29 05:54:14 +02:00
gingerBill 946cf52df1 Merge branch 'master' into base-work 2024-01-28 23:50:31 +00:00
gingerBill a78f062499 Fix semantics for casting between polymorphic specialized procedures 2024-01-28 23:49:59 +00:00
gingerBill 3c47503780 Improve foreign variable fuzzy type checking 2024-01-28 23:35:01 +00:00
gingerBill 6da82e038d Fix types for BSD 2024-01-28 23:27:30 +00:00
gingerBill 38af752cd1 Fix typo 2024-01-28 23:24:05 +00:00
gingerBill 0428f508d8 Fix typo of _heap_resize 2024-01-28 23:21:59 +00:00
gingerBill 3c24584290 Remove cyclic import hack for package runtime 2024-01-28 23:12:48 +00:00
gingerBill 535b8a9483 Remove core:os dependency completely from base:runtime 2024-01-28 23:11:38 +00:00
gingerBill 038086d1d9 Alias heap calls from base:runtime is core:os 2024-01-28 22:47:55 +00:00
gingerBill 9a16bc5fc5 Remove core:os dependency for base:runtime 2024-01-28 22:40:46 +00:00
gingerBill eee8e0faa2 Make //+private 2024-01-28 22:20:12 +00:00
gingerBill 3e7e779abf Replace core:* to base:* where appropriate 2024-01-28 22:18:51 +00:00
gingerBill 6a07effdd2 Freestanding - default to nil allocator; wasm - default to panic allocator 2024-01-28 22:15:28 +00:00
gingerBill 395e0fb225 -default-to-panic-allocator 2024-01-28 22:09:20 +00:00
gingerBill 9be9f0bb2c Remove core:os dependency for runtime.os_write on linux 2024-01-28 22:05:13 +00:00
gingerBill 9e7cc8cf93 Remove core:os dependency from base:runtime; change to base:intrinsics 2024-01-28 21:59:43 +00:00
gingerBill 2743bf7e44 Remove sdl.stack_* calls 2024-01-28 21:42:36 +00:00
gingerBill d95c28f41b Fix demo docs 2024-01-28 21:39:18 +00:00
gingerBill e57224d6e4 Fix demo 2024-01-28 21:30:08 +00:00
gingerBill f67691c457 Move matrix related procedures to the different linalg packages 2024-01-28 21:28:54 +00:00
gingerBill d04c82e547 Move matrix compiler builtins to intrinsics; alias within core_builtin_matrix.odin 2024-01-28 21:20:30 +00:00
gingerBill 09fa1c29cd Move core:runtime to base:runtime; keep alias around 2024-01-28 21:05:53 +00:00
gingerBill ddcaa0de53 Remove core:mem dependency from core:reflect 2024-01-28 20:52:01 +00:00
gingerBill 621b3c7829 Add missing clone for Struct_Type 2024-01-28 17:34:32 +00:00
gingerBill 68df35b378 Add #field_align(N)
It sets the minimum alignment for the fields within a struct. This cannot be used with `#packed`, but can be used with `#align(N)`.
If `#align(N)` is less than `#field_align(N)`, then a warning will be printed.
2024-01-28 17:33:29 +00:00
gingerBill c1d853a24e Remove dead code 2024-01-28 17:32:34 +00:00
gingerBill 30636f5114 Change return values from Struct_Tag to string 2024-01-28 15:48:19 +00:00
Patrick Cleavelin 7b9ea9eca0 Merge branch 'odin-lang:master' into master 2024-01-27 14:12:19 -06:00
Gabriel Pariat 89404147f6 fix whitespace 2024-01-27 14:10:32 -05:00
Gabriel Pariat 29d4bdc80b Revert "fix whitespace"
This reverts commit 594078cc1d.
2024-01-27 14:09:08 -05:00
Gabriel Pariat 594078cc1d fix whitespace 2024-01-27 14:08:14 -05:00
Gabriel Pariat ab68e4c6c4 change ordering 2024-01-27 14:06:58 -05:00
Gabriel Pariat 4956f9dad3 fix typo 2024-01-27 14:04:43 -05:00
Gabriel Pariat fd090c6672 adding linux + unix makefile for cgltf 2024-01-27 14:00:02 -05:00
jay-j b46b3010ec Expose OpenGL shader procedures to allow creation of shader pipelines with geometry shaders 2024-01-26 19:43:47 -08:00
Laytan Laats 31914e9cb9 Add odin test -all-packages to be able to test an entire project 2024-01-26 18:27:05 +01:00
gingerBill da6edb3764 Merge pull request #3139 from flysand7/file-attrib
sys/windows: Make `INVALID_FILE_ATTRIBUTES` a `u32` constant
2024-01-26 15:05:23 +00:00
gingerBill 9a9625f885 Fix #3053 2024-01-26 13:04:47 +00:00
gingerBill 15b40a4f29 Fix #3122 2024-01-26 12:56:16 +00:00
gingerBill 5406acc8fa Fix type_ptr_set_update 2024-01-26 12:47:39 +00:00
flysand7 d5b0ec712b os/os2: Remove file attribute casting from core:os2 2024-01-26 09:07:12 +11:00
FourteenBrush 766d6aa946 Fix typo 2024-01-25 12:05:19 +01:00
FourteenBrush 895ebb95d5 Need to unpack args 2024-01-25 11:44:53 +01:00
flysand7 af636eedde os: Fix casting errors in other files 2024-01-25 21:32:24 +11:00
flysand7 57b7822e12 Merge branch 'master' into unsigned-file-attrib 2024-01-25 20:57:18 +11:00
flysand7 03736d8bcb sys/windows: Make INVALID_FILE_ATTRIBUTES a u32 constant 2024-01-25 20:52:39 +11:00
FourteenBrush 3a5d80b291 Forgot to include loc param 2024-01-25 10:20:23 +01:00
FourteenBrush 967ccfc7cc Merge branch 'master' of https://github.com/FourteenBrush/Odin 2024-01-25 10:15:25 +01:00
FourteenBrush 712ae1c5ac Add testing.expectf 2024-01-25 10:08:09 +01:00
Colin Davidson f93f2dfd5c Add support for basic EGL on Linux 2024-01-24 13:24:25 -08:00
Laytan Laats 9ac619f4a2 vendor/raylib: change to non-universal binaries
We already have 2 different folders for the different architectures, so
this does should not have any usage impact.

Main motivation for doing this is hombrew requiring non-universal
binaries in their installation, so this is a step to getting homebrew
and vendor to play nice.
2024-01-24 20:58:14 +01:00
Jeroen van Rijn 9cfd4a953e Merge pull request #3132 from KyleNBurke/patch-1
Remove mention of `map` in builtin resize proc group
2024-01-24 16:41:27 +01:00
Kyle Burke 14e2cc17d6 Remove mention of map in builtin resize proc group 2024-01-24 09:39:47 -06:00
gingerBill 5f41741e8c Merge pull request #3126 from DanielGavin/parser-fix-paran
Improve recovery from faulty parameters in parse_proc_type
2024-01-24 11:23:49 +00:00
gingerBill 8a067bc1fc Merge pull request #3127 from laytan/fix-wasm-and-llvm-17
fix for wasm on llvm 17
2024-01-24 11:23:16 +00:00
gingerBill cfdf2bfb77 Merge pull request #3129 from DragosPopse/assert-fix
`fmt.assertf` now correctly gets disabled on `-disable-assert`. `log.assert/f` procs. `@cold` trick on everything fixed.
2024-01-24 11:21:37 +00:00
gingerBill 2f8316840e Merge pull request #3131 from flysand7/non-zeroed
os2: Add .Resize_Non_Zeroed allocation mode to os2/heap_windows
2024-01-24 11:21:09 +00:00
flysand7 a660098106 os2: Add .Resize_Non_Zeroed allocation mode to os2/heap_windows 2024-01-24 15:51:47 +11:00
Dragos Popescu 90d1f9ab27 Removed return value of assertf. assertf now correctly responds to -disable-assert. Added log.assert and log.assertf. All asserts now do the @cold trick, first added to builtin.assert 2024-01-23 20:56:13 +02:00
Laytan Laats 2097b09abb fix for wasm on llvm 17 2024-01-22 21:07:17 +01:00
DanielGavin f63f28302e Recover from faulty parameter in parse_proc_type 2024-01-22 20:35:26 +01:00
gingerBill 98b539ac5c Merge pull request #2912 from karl-zylinski/marshal-sort-maps-by-key-and-clone-value
JSON: Option to sort marshaled maps before outputting + clone_value proc + small improvements
2024-01-22 14:05:15 +00:00
Karl Zylinski 9d067ae562 Made sure temp guard for sorting map keys in json marshal code ignores temp allocator 2024-01-22 14:35:05 +01:00
Jeroen van Rijn 5a542c7ad5 Merge pull request #3119 from Kelimion/location_call
Clarify #location error message when not a call.
2024-01-20 14:42:42 +01:00
Jeroen van Rijn 73f57c5933 Clarify #location error message when not a call. 2024-01-20 14:27:50 +01:00
Jeroen van Rijn 2071d7ba84 Merge pull request #3116 from Kelimion/hot_reload
Add hot reload support to `dynlib.initialize_symbols`
2024-01-19 18:51:34 +01:00
Jeroen van Rijn e8102a40d0 Add hot reload support to dynlib.initialize_symbols 2024-01-19 18:43:02 +01:00
gingerBill 737677f1b6 Merge pull request #3108 from Kelimion/subsystem
Add WINDOWS_SUBSYSTEM constant
2024-01-19 15:38:13 +00:00
Jeroen van Rijn fc047a8043 Expand -subsystem option on Windows
W:\Odin>odin run sketch.odin -file -subsystem:foo
Invalid -subsystem string, got oo. Expected one of:
        BOOT_APPLICATION, CONSOLE (default), EFI_APPLICATION, EFI_BOOT_SERVICE_DRIVER, EFI_ROM, EFI_RUNTIME_DRIVER, NATIVE, POSIX, WINDOWS (or WINDOW), WINDOWSCE

We now also set the constant ODIN_WINDOWS_SUBSYSTEM, which is "" for non-Windows targets.
2024-01-18 19:12:39 +01:00
Jeroen van Rijn ae52e245ea Add WINDOWS_SUBSYSTEM constant bool
true when -subsystem:windows for Windows targets, false otherwise.
2024-01-18 17:42:03 +01:00
gingerBill b8bfc715bf Merge pull request #3109 from flysand7/sys-linux-tiny-fix
[sys/linux]: Remove +build comments in files with documentation
2024-01-18 15:59:50 +00:00
Damian Tarnawski b0aa08f85b Correct wasm page_allocator switch cases 2024-01-18 10:33:40 +01:00
Damian Tarnawski d6ee5e89fa Merge branch 'odin-lang:master' into patch-2 2024-01-18 10:30:21 +01:00
Damian Tarnawski a263da0bbe Fix window_get_scroll proc not returning loaded values 2024-01-18 10:27:09 +01:00
Damian Tarnawski 9cb02aa51d Add missing Resize_Non_Zeroed case to page allocator 2024-01-18 10:26:43 +01:00
gingerBill 799f4379d8 Keep vet happy 2024-01-17 22:51:49 +00:00
gingerBill bd51b21386 Fix typo 2024-01-17 22:47:23 +00:00
gingerBill 276284cbec Fix typo 2024-01-17 22:44:28 +00:00
gingerBill a8021f03a6 Rename to Map_File_* 2024-01-17 22:43:35 +00:00
gingerBill c35d5d4c42 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-01-17 22:41:28 +00:00
gingerBill 248a0bfa5f Add virtual.map_file 2024-01-17 22:41:22 +00:00
flysand7 34791707fd [sys/linux]: Remove +build comments in files with documentation 2024-01-18 09:16:40 +11:00
gingerBill 37ae9eb609 Merge pull request #3001 from colrdavidson/unsafe_mem
add non-zeroing append and resize
2024-01-17 21:39:27 +00:00
Colin Davidson b6838731f5 oops, indentation 2024-01-17 13:30:03 -08:00
Colin Davidson 991c1d4446 add resize_non_zeroed to query features 2024-01-17 13:27:19 -08:00
Colin Davidson d0bb1fb844 bring log allocator up to date 2024-01-17 13:11:10 -08:00
Jeroen van Rijn ea43c030aa Merge pull request #3107 from ktsiligkiris/documentation/fix_xml_docs
Fix comments for proper rendering in documentation in encoding/xml
2024-01-17 21:10:49 +01:00
Kostas Tsiligkiris d54f34a162 Fix comments in xml_reader.odin for better rendering in documentation 2024-01-17 21:58:38 +02:00
Kostas Tsiligkiris a86cfa6e97 Fix filename in example 2024-01-17 21:38:33 +02:00
Jeroen van Rijn 1b83f4a18b Merge pull request #3082 from edyu/master
Fix math/fixed floor/ceil/round
2024-01-17 19:13:22 +01:00
gingerBill 90ac400ec5 stdcall -> system 2024-01-17 17:25:23 +00:00
gingerBill 75c659fa41 Change stdcall -> system 2024-01-17 17:04:54 +00:00
gingerBill 8cfff254c9 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-01-17 16:54:58 +00:00
gingerBill 8c2eb5df78 stdcall -> system 2024-01-17 16:54:50 +00:00
gingerBill a2f0ac0fd2 Merge pull request #3093 from avanspector/master
Add shell environment for Nix
2024-01-17 16:48:14 +00:00
gingerBill 2987fc65a1 Merge pull request #3043 from laytan/check-float-value-succeeded
check if string could be converted from float
2024-01-17 16:47:41 +00:00
gingerBill c5bab58180 Merge pull request #3076 from xb-bx/mprotect-fix-for-linux-and-darwin
virtual.protect returns inverted result on linux and darwin platforms
2024-01-17 16:46:39 +00:00
gingerBill 5ad88ea169 Merge pull request #3104 from codename-irvin/dev
Add freestanding aarch64 target
2024-01-17 16:45:34 +00:00
gingerBill 72d6b9b683 Replace stdcall with system 2024-01-17 16:43:27 +00:00
gingerBill 2f2c086382 Fix foreign import names 2024-01-17 16:35:28 +00:00
gingerBill d9fafa7000 Have default foreign import system paths 2024-01-17 16:32:26 +00:00
gingerBill 12e53f2336 Fix imports to be case sensitive correct 2024-01-17 16:26:18 +00:00
gingerBill a2e729c303 Remove //+build darwin 2024-01-17 16:06:59 +00:00
gingerBill 7b89174a26 Remove //+build windows tag 2024-01-17 15:57:37 +00:00
gingerBill 1d7f7a55d2 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-01-17 15:51:34 +00:00
gingerBill 766485ccab Add README.md 2024-01-17 15:51:29 +00:00
gingerBill 6642aa94d5 Change examples/all 2024-01-17 15:50:00 +00:00
Jeroen van Rijn 1c9ec27d36 Merge pull request #3105 from FourteenBrush/patch-1
Fix typo in bytes.scrub
2024-01-17 13:54:37 +01:00
FourteenBrush 05e27fa92d Fix typo in bytes.scrub 2024-01-17 13:37:06 +01:00
gingerBill 7954a7a6f3 Add darwin libraries back to normal examples/all to fix documentation generation 2024-01-17 12:27:03 +00:00
gingerBill 1d621295b1 Fix #1934 raylib IsGestureDetected 2024-01-17 12:26:44 +00:00
Kostas Tsiligkiris 02c2aff41b Fix formatting of package documentation string 2024-01-17 07:04:00 +02:00
Kostas Tsiligkiris 5476d43441 Move package xml before copyright
Having the same copyright on all files made the documentation script
to include it multiple times in the package information.
2024-01-17 07:00:25 +02:00
Laytan Laats b25e85a8bb check if string could be converted from float 2024-01-17 00:15:24 +01:00
Damian Tarnawski 190103883c Fix uniform matrix functions in WebGLInterface 2024-01-16 21:45:52 +01:00
codename-irvin d460dd2bdc Merge branch 'master' into dev 2024-01-16 15:42:47 -05:00
gingerBill 7ee7f4b064 Merge pull request #3077 from laytan/add-libc-to-stream
c/libc: add `to_stream` proc
2024-01-16 18:09:44 +00:00
gingerBill f2d3376c0b Merge pull request #3084 from stan680/semaphore-fix
Fix loop condition in semaphore_wait
2024-01-16 18:09:02 +00:00
codename-irvin 0fcd2f1d88 Use default calling convention for arm target for now - not 100% sure this is correct 2024-01-16 10:47:25 -05:00
codename-irvin 76f52dd6c9 Add freestanding aarch64 target 2024-01-15 19:49:34 -05:00
Jeroen van Rijn ae0be9c785 Merge pull request #3096 from ktsiligkiris/documentation/fix-format
[DOC] Fix documentation formatting in site
2024-01-14 16:03:57 +01:00
Kostas Tsiligkiris 3f6f00d8e5 [DOC] Fix documentation formatting in site
The comments that were added automatically in odin site, contained
tabs, so the first line of a two line comment was properly rendered in
the site, but the second line of the comment (because it included tabs
in the beginning of the line) was rendered as preformattted text. I
think that the proposed changes will fix this problem in the
documentation site.

An example of the problematic rendering of documentation is
https://pkg.odin-lang.org/core/compress/#COMPRESS_OUTPUT_ALLOCATE_MAX
2024-01-14 13:22:18 +02:00
Jeroen van Rijn c58eeca1b2 Merge pull request #3095 from laytan/macos-add-common-library-paths
darwin: add library paths for default Homebrew and MacPorts locations
2024-01-13 21:51:07 +01:00
Laytan Laats 5032839abc darwin: add library paths for default Homebrew and MacPorts locations 2024-01-13 21:38:30 +01:00
Jeroen van Rijn 2b1d85968d Merge pull request #3094 from laytan/fix-miniaudio-import
vendor/miniaudio: fix import for MacOS
2024-01-13 21:31:13 +01:00
Laytan Laats 5896469f3b vendor/miniaudio: fix import for macos
Using `system:miniaudio` is suboptimal, we already provide the
`Makefile` that builds the `lib/miniaudio.a` and this works on MacOS.
This PR makes linking with that library the default.
2024-01-13 21:14:02 +01:00
avanspector 70c150fc83 Fix gcc build
Although gcc is not officially supported, this little fix lets it to build Odin
2024-01-13 19:27:42 +01:00
avanspector 2411febf83 add shell environment for Nix 2024-01-13 19:25:13 +01:00
Jeroen van Rijn 5e7b031a1d Add RAD Debugger file to .gitignore. 2024-01-13 16:10:32 +01:00
gingerBill ef05e0858d Merge pull request #3092 from jon-lipstate/cpu_features_fix
cpu_features - fix shift direction
2024-01-13 11:54:31 +00:00
Jon Lipstate 880a18f124 fix shift direction 2024-01-12 22:28:38 -08:00
gingerBill 5d94887e76 Merge pull request #3083 from Lperlind/master
Fix linalg shadowing error
2024-01-13 00:05:14 +00:00
gingerBill 577049c69e Merge pull request #3086 from karl-zylinski/patch-1
Added comment on SetConfigFlags in Raylib bindings that it must be called before window creation
2024-01-13 00:04:46 +00:00
Karl Zylinski 46f46e645c Added comment on SetConfigFlags in Raylib bindings that it must be called before window creation 2024-01-11 11:20:14 +01:00
Jeroen van Rijn b13aa5db37 Merge pull request #3085 from Platin21/fix/macos-versions
Adds new MacOS Versions and Fixes Kernel Matching
2024-01-10 18:31:17 +01:00
Jeroen van Rijn 2990747cf8 Reindent and align and f ix Ventura kernel+version swap. 2024-01-10 18:26:14 +01:00
Platin21 62c30795e6 Fixed indentation 2024-01-10 17:27:31 +01:00
Platin21 bb94f4d129 Fixed version matching 2024-01-10 17:24:53 +01:00
Stan Irvin-Wilmot 7b53dbeb8a fix loop condition on compare_exhange_strong result in semaphore_wait - it was backwards so would loop on success and bail on fail 2024-01-10 15:53:00 +00:00
Platin21 120ef168bf Added macOS versions for a lot of revisions 2024-01-10 16:42:25 +01:00
gingerBill 72dfb73c9d Merge branch 'master' of https://github.com/odin-lang/Odin 2024-01-09 11:01:24 +00:00
gingerBill 67dcd916e8 Update instrumentation signature to support runtime.Source_Code_Location as last parameter. 2024-01-09 11:01:18 +00:00
Ed Yu 7f6f971284 Fix math/fixed floor/ceil/round 2024-01-08 18:56:12 -08:00
Lucas Perlind 67d5b97ff9 Fix linalg shadowing error 2024-01-09 10:24:12 +11:00
Jeroen van Rijn efb2b05040 Merge pull request #3078 from Kelimion/pq_peek
Add `peek` to priority queue.
2024-01-08 19:39:57 +01:00
Jeroen van Rijn 656e62d724 Add peek to priority queue. 2024-01-08 19:33:30 +01:00
Laytan Laats ce8801c37f c/libc: add to_stream proc
Adds the `to_stream` procedure to `core:c/libc` to improve usability of
the core collection when you have to use libc.
2024-01-08 19:20:06 +01:00
xb-bx c6c710465a fix 2024-01-08 19:54:39 +02:00
gingerBill f3dc1f6e3b Merge pull request #3075 from FrancisTheCat/fix-sort_by_indices_overwrite
Fixed type of temporary slice in sort_by_indices_overwrite
2024-01-08 16:39:08 +00:00
Franz Höltermann 873b7f8588 Fixed type of temporary slice in sort_by_indices_overwrite 2024-01-08 17:11:06 +01:00
Jeroen van Rijn 7d3dfb1046 Merge pull request #3006 from hwchen/hwchen/last_index_any
fix strings.last_index_any for single char
2024-01-08 15:57:36 +01:00
gingerBill f4782157d3 Implement instrumentation pass 2024-01-07 21:34:44 +00:00
Damian Tarnawski 8de7d2f18f Hoist STRING_SIZE constant 2024-01-07 22:25:27 +01:00
gingerBill aff8f06e3c Add frontend stuff instrumentation tooling
//+no-instrumentation
@(no_instrumentation)
@(instrumentation_enter)
@(instrumentation_exit)
2024-01-07 19:56:00 +00:00
Damian Tarnawski 0bf1b6c2f1 Fix typo in WebGLInterface class 2024-01-07 20:19:44 +01:00
Damian Tarnawski 2017ebc1b5 Fix copyTexSubImage2D and copyTexSubImage3D method calls 2024-01-07 16:49:51 +01:00
Damian Tarnawski da56a75ad6 Fix WebGLInterface function names 2024-01-07 16:49:12 +01:00
gingerBill 1e1228fb37 Merge pull request #3024 from Yawning/fix/simd-x86
core:simd/x86: Various fixes
2024-01-07 11:57:22 +00:00
Yawning Angel 8d7c37e384 core/simd/x86: Use the none calling convention for intrinsics
The LLVM intrinsics that live under `llvm.x86` are not actual functions,
so trying to invoke them as such using the platform's native C
calling convention causes incorrect types to be emitted in the IR.

Thanks to laytanl for assistance in testing.
2024-01-07 20:04:40 +09:00
Yawning Angel cd65a15d81 src: enable_target_feature should add features, not overwrite
`llvm_features` being empty is the default state, and implies the
presence of certain features.

Previously if any target features were explicitly enabled by the
`enable_target_feature` attribute, they were added comma separated
to `llvm_features`.

For example: `lzcnt,popcnt,...,sse4.2,sse`

This was causing LLVM to try to target a CPU that *ONLY* has the
explicitly enabled features.  This now will prefix explicitly enabled
features with a `+`, and preserve the existing `llvm_features` string
by appending to it if it is set.
2024-01-07 20:04:40 +09:00
Yawning Angel 9235e82451 core/simd/x86: Correct a target feature name 2024-01-07 20:04:40 +09:00
Yawning Angel ecee0e2db2 repo: Add more test binaries to .gitignore 2024-01-07 20:04:40 +09:00
Damian Tarnawski 0580eebd2a Pass height to webgl.readPixels 2024-01-06 22:28:24 +01:00
Damian Tarnawski 909a5016ee Correct glIsEnabled in wasm.webgl 2024-01-06 22:17:01 +01:00
Damian Tarnawski c2c89e54a5 Correct spelling of FramebufferRenderbuffer 2024-01-06 21:03:27 +01:00
Damian Tarnawski 6389d9c11f Merge branch 'master' into patch-2 2024-01-06 21:02:37 +01:00
Jeroen van Rijn 2784e8ea51 Merge pull request #3072 from laytan/add-dynlib-last_error
dynlib: add last_error procedure
2024-01-06 02:13:53 +01:00
Laytan Laats 85b71708dd dynlib: add last_error procedure 2024-01-06 02:08:11 +01:00
Jeroen van Rijn 649b5fa528 Add bool return to dynlib.initialize_symbols. 2024-01-06 02:04:09 +01:00
Jeroen van Rijn d6a89d667d Add dynlib.initialize_symbols (#3071)
```
package example

import "core:dynlib"
import "core:fmt"

Symbols :: struct {
	// `foo_` is prefixed, so we look for the symbol `foo_add`.
	add: proc "c" (int, int) -> int,
	// We use the tag here to override the symbol to look for, namely `bar_sub`.
	sub: proc "c" (int, int) -> int `dynlib:"bar_sub"`,

	// Exported global (if exporting an i32, the type must be ^i32 because the symbol is a pointer to the export.)
	// If it's not a pointer or procedure type, we'll skip the struct field.
	hellope: ^i32,

	// Handle to free library.
	// We can have more than one of these so we can match symbols for more than one DLL with one struct.
	_my_lib_handle: dynlib.Library,
}

main :: proc() {
	sym: Symbols

	// Load symbols from `lib.dll` into Symbols struct.
	// Each struct field is prefixed with `foo_` before lookup in the DLL's symbol table.
	// The library's Handle (to unload) will be stored in `sym._my_lib_handle`. This way you can load multiple DLLs in one struct.
	count := dynlib.initialize_symbols(&sym, "lib.dll", "foo_", "_my_lib_handle")
	defer dynlib.unload_library(sym._my_lib_handle)
	fmt.printf("%v symbols loaded from lib.dll (%p).\n", count, sym._my_lib_handle)

	if count > 0 {
		fmt.println("42 + 42 =", sym.add(42, 42))
		fmt.println("84 - 13 =", sym.sub(84, 13))
		fmt.println("hellope =", sym.hellope^)
	}
}
```
2024-01-06 01:31:27 +01:00
gingerBill b408ec6bac Remove distinct from the specific types 2024-01-05 14:48:39 +00:00
gingerBill 8545f316ff Fix the type inference in builtin.quaternion 2024-01-05 14:45:03 +00:00
gingerBill 3bf7b416e7 Fix builtin.quaternion generation 2024-01-05 14:36:58 +00:00
gingerBill 0b83e3dae5 Enforce naming the parameters with builtin.quaternion to reduce confusion 2024-01-05 14:29:14 +00:00
gingerBill d7d23e65ea Clean up error block usage 2024-01-05 13:47:00 +00:00
gingerBill 2820bbc269 Add @(entry_point_only) for procedures 2024-01-05 13:38:30 +00:00
Patrick Cleavelin 59aa05170d respect -lld CLI arg 2024-01-04 13:55:36 -06:00
gingerBill 70c5153471 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-01-03 21:00:35 +00:00
gingerBill 5961d4b316 Merge pull request #2983 from perogycook/raylib5
Raylib5 bindings with fixes
2024-01-03 18:32:45 +00:00
Jeroen van Rijn b59c80d6fd Merge pull request #3068 from laytan/json-unmarshal-union
encoding/json: try to unmarshal into union variants
2024-01-03 19:13:36 +01:00
Laytan Laats 8c10f4cdde encoding/json: try to unmarshal into union variants 2024-01-03 19:02:30 +01:00
gingerBill 0cc72b536f Merge pull request #3066 from laytan/darwin-actually-honor-no-crt
darwin: actually honor no-crt by not linking with `-lSystem -lm`
2024-01-03 17:25:41 +00:00
Laytan Laats 8a7c2ea9d0 darwin: actually honor no-crt by not linking with -lSystem -lm 2024-01-02 21:44:51 +01:00
Jeroen van Rijn cb1c10ce83 Merge pull request #3067 from Platin21/fix/macos-no-duplicated-linkage
Fix/macos no duplicated linkage
2024-01-02 21:35:41 +01:00
Platin21 37c2e9bec3 Fixed Typo / Added check for 1 2024-01-02 21:14:17 +01:00
Platin21 4626cd03da Adds missing space 2024-01-02 21:04:44 +01:00
Platin21 3850be2e11 Fixed git issue.. 2024-01-02 21:04:03 +01:00
Platin21 4c9aa30a1e Merge remote-tracking branch 'origin/master' into fix/macos-min-version 2024-01-02 20:55:20 +01:00
Platin21 da977cf1e6 Adds new flag for linker to know if it should link the system library or not 2024-01-02 20:55:15 +01:00
Jeroen van Rijn ee97c5958f Merge pull request #3065 from Platin21/fix/macos-min-version
Removes macOS min version and supports default latest
2024-01-02 20:07:26 +01:00
Platin21 778bbee17c Removes macOS min version and supports default latest 2024-01-02 19:49:44 +01:00
Jeroen van Rijn 4efef08c94 Update core:encoding to Unicode 15.1 table. 2024-01-02 18:03:32 +01:00
gingerBill 87c835268a Merge pull request #2917 from flysand7/sys-linux-additions
[sys/linux]: Fixes and additions
2024-01-02 14:23:40 +00:00
gingerBill 83ed0b37cd Merge pull request #3036 from laytan/error-when-c-vararg-is-not-on-last-param
error when #c_vararg is not applied to the last parameter
2024-01-02 14:22:24 +00:00
gingerBill dc49cf766f Merge pull request #3048 from ThomasL81/master
Fixing a pdb linker error when the path contains spaces
2024-01-02 14:18:44 +00:00
gingerBill 933754193a Merge pull request #3049 from igordreher/dxgi_bit_set
[vendor:directx/dxgi] change u32 flags to bit_sets
2024-01-02 14:18:09 +00:00
gingerBill 76eef47491 Merge pull request #3054 from igordreher/win_error
[core:sys/windows] add System Error Codes enum
2024-01-02 14:16:36 +00:00
gingerBill 0e21f45076 Merge pull request #3057 from korvahkh/fix-nil-default-arg
Fix #3056
2024-01-02 14:14:35 +00:00
gingerBill 9bfe3a94f4 Merge pull request #3061 from flysand7/glfw-set-joystick-callback-fix
Fix the declaration of SetJoystickCallback
2024-01-02 14:13:53 +00:00
gingerBill a2009220a2 Merge pull request #3063 from aragalie/patch-1
remove duplication
2024-01-02 14:13:42 +00:00
gingerBill b410383aaf Merge branch 'master' of https://github.com/odin-lang/Odin 2024-01-01 16:11:13 +00:00
Alex Ragalie b47736260a remove duplication 2023-12-31 21:57:39 +01:00
flysand7 5154bb551a Fix the declaration of glfwSetJoystickCallback 2023-12-31 15:03:50 +11:00
Jeroen van Rijn 89084befb0 Remove unnecessary []byte -> []byte conversion. 2023-12-30 21:59:33 +01:00
gingerBill f3caa4aee3 Add bin/lld-link.exe 2023-12-30 13:53:15 +00:00
gingerBill 3ec253f385 Add bin/wasm-ld.exe 2023-12-30 13:52:37 +00:00
korvahkh 759e342872 Fix #3056 2023-12-29 22:39:34 -06:00
Igor Dreher 120b1101fb [core:sys/windows] add System Error Codes enum
Copied error values from https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
and subsequent pages to an enum
2023-12-29 11:06:50 -03:00
Jeroen van Rijn 252fd0e928 Merge pull request #3052 from laytan/fix-type-assign-at
fix typo in assign_at_elems
2023-12-28 17:44:20 +01:00
Laytan Laats 1fa2af213d fix typo in assign_at_elems 2023-12-28 17:10:08 +01:00
Igor Dreher de84db85cb [vendor:directx/dxgi] change u32 flags to bit_sets 2023-12-28 09:42:37 -03:00
Jeroen van Rijn 33d85adf34 Merge pull request #3051 from laytan/fix-double-execution-of-tests
fix double execution of tests
2023-12-27 15:58:19 +01:00
Laytan Laats 383d485e2a fix double execution of tests 2023-12-27 15:34:11 +01:00
Jeroen van Rijn 68d2b7bb89 Disable doc tests for now. 2023-12-27 15:29:40 +01:00
Jeroen van Rijn d667809e0a Merge pull request #3050 from laytan/fix-load-directive-with-absolute-paths
fix load directive with absolute paths
2023-12-27 15:21:43 +01:00
Laytan Laats 64ed4389ff fix load directive with absolute paths 2023-12-27 15:00:33 +01:00
Thomas Louis 4701b31b55 Fixing a pdb linker error when the path contains spaces 2023-12-27 11:36:38 +01:00
Jeroen van Rijn e52cc73d50 Fix generic_float.odin 2023-12-21 22:37:26 +01:00
Jeroen van Rijn ac0ed13b35 Merge pull request #3039 from chikega/patch-1
Update demo.odin
2023-12-21 22:32:09 +01:00
Gary Chike 269957b9fb Update demo.odin
Appears that 'to' and 'abstract' were inverted.
2023-12-21 16:23:00 -05:00
gingerBill 464a675adc Merge branch 'master' of https://github.com/odin-lang/Odin 2023-12-21 17:05:31 +00:00
gingerBill 55f3e99f63 Fix %g in fmt, and make %v default to %g for floats 2023-12-21 17:05:24 +00:00
Jeroen van Rijn 49fb0acfc9 Merge pull request #3037 from laytan/fix-wrong-string-type-assert
fix wrong string type assert
2023-12-20 01:05:10 +01:00
Laytan Laats 09db245e4c fix wrong string type assert
Fixes #2846
2023-12-20 00:56:36 +01:00
Laytan Laats bc7972fbaf error when #c_vararg is not applied to the last parameter
Fixes #2981
2023-12-20 00:17:11 +01:00
Jeroen van Rijn 6f80d2dc36 Merge pull request #3033 from laytan/use-stack-buffer-for-log-allocator
use stack buffer for log allocator to avoid logging it's own allocations
2023-12-20 00:06:51 +01:00
Laytan Laats 46250168d6 use stack buffer for log allocator to avoid logging it's own allocations 2023-12-19 23:26:23 +01:00
gingerBill 509712f771 Merge pull request #3031 from Kithuppi/fix-vulkan-bindings
Fix vulkan bindings
2023-12-19 12:32:26 +00:00
gingerBill 4b38dbe133 Merge branch 'master' of https://github.com/odin-lang/Odin 2023-12-19 12:32:10 +00:00
gingerBill ad0ffa4833 Update .gitattributes with * text=auto 2023-12-19 12:32:05 +00:00
gingerBill b89fc9191c Merge pull request #3030 from keyle/patch-1
Add vendor:cmark support for macOS
2023-12-18 22:27:27 +00:00
gingerBill 829e4cc67e Fix assign_at_elems to match the same logic as assign_at_elem_string 2023-12-18 22:22:08 +00:00
gingerBill beb4699b46 Check test procedures after all minimum dependency set calls are done 2023-12-18 22:09:10 +00:00
Walther Chen 031b0cc534 fix strings.last_index_any for single char 2023-12-18 11:55:45 -05:00
gingerBill ee504aa596 Merge pull request #3032 from laytan/runtime-arena-edge-cases
Runtime arena edge cases
2023-12-18 15:51:00 +00:00
Laytan baa5ea9258 fix not passing arg everywhere 2023-12-18 16:41:55 +01:00
Laytan 9a490e4e0d fix big alignment 2023-12-18 16:38:51 +01:00
Laytan Laats 252de70b0f fix same problem in virtual arena 2023-12-18 15:41:36 +01:00
Laytan Laats 4ae021cd4c add other failing test and fix them 2023-12-18 15:17:27 +01:00
Laytan Laats af962526df switch tests around 2023-12-18 14:46:37 +01:00
Laytan Laats 6024af172c add failing test for runtime arena edge case 2023-12-18 14:40:49 +01:00
Kithuppi 8bd5a9bb9e generate new bindings 2023-12-18 13:38:57 +02:00
Karl Zylinski a9166f52f8 Raylib 5.0 IsMouseButtonUp workaround: Better use of when clause to make sure we remove the workaround later. 2023-12-18 11:30:20 +01:00
Karl Zylinski 9bdd4c73a5 Raylib workaround: Fix comment typo 2023-12-18 11:20:15 +01:00
Karl Zylinski 2362be11bf Raylib 5.0 bug workaround: Check VERSION and panic if VERSION != 5.0, in which case there is info in the message about how to remove the workaround. 2023-12-18 11:19:11 +01:00
keyle 5b8a76c583 Add support for macOS 2023-12-18 16:50:41 +10:00
Karl Zylinski 2a0e4f7a8c Workaround for bug in Raylib 5 making IsMouseButtonUp not work properly. 2023-12-17 19:48:19 +01:00
Kithuppi ece82eecc3 fix C bit field parsing 2023-12-17 16:39:03 +02:00
gingerBill 67d02043fe Merge pull request #3027 from Yawning/fix/build-constraints
core: Fixed build constraints
2023-12-17 14:28:50 +00:00
Yawning Angel 29c80c238d core: Fixed build constraints
Multiple constraints on the same line are combined with logical OR,
while combining multiple negated constraints needs to be done with
logical AND (each constraint on a separate line).
2023-12-17 23:02:46 +09:00
Michael a4606e4da8 IsMouseButtonUp hack for now 2023-12-16 16:50:22 -07:00
Jeroen van Rijn d4df3f6383 Merge pull request #3025 from laytan/log-allocator-memory-format
log allocator: use %m to format size and fix formatting bugs
2023-12-16 01:32:18 +01:00
Laytan Laats 58ff3dd1ed log allocator: add option to switch between bytes and human format 2023-12-16 01:27:38 +01:00
Laytan Laats cf8c9a6be4 log allocator: fix the formatting for query info/features and errors 2023-12-16 00:55:59 +01:00
Laytan Laats ea709451e8 log allocator: use %m to format size 2023-12-15 23:43:35 +01:00
gingerBill d47a403d29 Fix: Bill was a numpty 2023-12-15 11:02:40 +00:00
gingerBill 1606f756b3 Remove neighbouring duplicates from neighbouring sorted array of entities; fixes duplicate tests 2023-12-15 10:59:34 +00:00
Laytan Laats 0b2f357bbe fix eof logic 2023-12-14 18:05:06 +01:00
Laytan Laats 9a1c4dc56d implement a max read/write at a time for non-windows (windows already has this) 2023-12-14 18:05:06 +01:00
Laytan Laats 7eabeda870 make sure an eof is also returned from the file streams on non-windows 2023-12-14 18:05:06 +01:00
gingerBill 2e9298891e Merge pull request #3019 from DanielGavin/parser-fix
Fixed crash in `core:odin/parser` with `#reverse`
2023-12-14 15:16:01 +00:00
gingerBill f8b85339af Merge pull request #3020 from Lperlind/master
Format hidpi.odin
2023-12-14 15:15:51 +00:00
Lucas Perlind 12b8f91249 Format hidpi.odin 2023-12-14 10:29:50 +11:00
DanielGavin 8e395cc6e9 Fixed crash in core:odin/parser with #reverse 2023-12-13 20:08:26 +01:00
gingerBill feba52002e Reduce repetition on initializing global type info member arrays 2023-12-13 17:46:00 +00:00
gingerBill ca2b2c498e Add -obfuscate-source-code-locations 2023-12-13 16:47:34 +00:00
gingerBill 6e9e469abd Merge pull request #3008 from laytan/fix-stat-struct-layout-linux-arm64
fix struct stat layout linux arm64
2023-12-13 15:24:38 +00:00
gingerBill 0490ba46f4 Merge pull request #3015 from Lperlind/master
Add Hidpi to Windows
2023-12-13 15:24:25 +00:00
gingerBill e0652ee2f4 Minor fix to call expr in tilde with variadic parameters 2023-12-13 13:10:51 +00:00
gingerBill bc99bacb21 Update Tilde 2023-12-13 12:38:01 +00:00
gingerBill 173527d631 Remove random tag 2023-12-13 01:53:15 +00:00
gingerBill f8cb2bcad2 Add slice.unique and slice.unique_proc 2023-12-13 01:50:26 +00:00
gingerBill b011487778 Reimplement binary_search_by to be simpler 2023-12-13 01:37:15 +00:00
gingerBill c8cc130744 Fix the implementation of binary_search_by to work with a normal ordering call, rather than the backwards version.
WHY THE HECK WAS IT THIS WAY IN THE FIRST PLACE?!
2023-12-13 01:24:03 +00:00
gingerBill fe0244606b Revert 2023-12-13 01:20:53 +00:00
gingerBill 036fa6482c Use cmp_proc in binary_search 2023-12-13 01:18:05 +00:00
gingerBill 04ca22b9ea Add to core:slice reduce_reverse, filter_reverse, repeat 2023-12-13 00:35:23 +00:00
gingerBill bf9ae77fbd Remove duplicates from init/fini procedure list 2023-12-12 17:29:52 +00:00
gingerBill 4adfc120ba Merge branch 'master' of https://github.com/odin-lang/Odin 2023-12-12 17:11:42 +00:00
gingerBill d8bb93accc Fix race condition caused by lack of checking specialized parapoly procedures as a dependency (#2968) 2023-12-12 17:10:59 +00:00
Lucas Perlind e410908ce8 Add Hidpi to Windows 2023-12-12 12:14:18 +11:00
Laytan Laats d278c852cc clean up field names 2023-12-08 23:43:30 +01:00
Michael 364b64718f Merge branch 'odin-lang:master' into raylib5 2023-12-08 00:06:31 +01:00
Michael 61335089c6 added some commas 2023-12-08 00:05:51 +01:00
Jeroen van Rijn 040b90ce76 Merge pull request #3011 from xtactis/binary_search_by_fix/3007
Fix for bug in binary_search_by implementation
2023-12-07 18:26:34 +01:00
Matija Dizdar 843b2350eb added #no_bounds_check back into binary_search_by 2023-12-06 21:48:37 +01:00
Matija Dizdar 526d338300 removed incorrect requirement for key type to be ordered in binary_search_by 2023-12-06 21:29:18 +01:00
Laytan Laats a6aca5d6d1 fix struct stat layout linux arm64 2023-12-06 17:17:45 +01:00
Michael 05c67c3243 Merge branch 'odin-lang:master' into raylib5 2023-12-05 23:51:34 +01:00
flysand7 5665ae02bc type error 2023-12-06 00:33:09 +11:00
flysand7 92d3a681cd Merge branch 'master' into sys-linux-additions 2023-12-06 00:23:41 +11:00
flysand7 cb66ed52ce [sys/linux]: Fix epoll_wait on arm64 2023-12-06 00:09:10 +11:00
Michael 30ad923558 Update raygui.odin for Mac targets 2023-12-04 20:14:05 +01:00
Michael a31ab31e96 Add files via upload 2023-12-04 20:09:12 +01:00
Michael ac760a0bdd MacOS-arm64 Raygui libs 2023-12-04 20:08:31 +01:00
Michael fbf0180411 Delete vendor/raylib/macos-arm64/libraygui.a 2023-12-04 20:07:29 +01:00
Michael 198ac00994 New Raygui libs for Windows 2023-12-04 17:31:32 +01:00
Michael 603764dbca Delete vendor/raylib/windows/raygui.lib 2023-12-04 17:30:51 +01:00
Michael cb04333480 Delete vendor/raylib/windows/raygui.dll 2023-12-04 17:30:38 +01:00
Michael 0e169fd1c2 Delete vendor/raylib/windows/rayguidll.lib 2023-12-04 17:30:13 +01:00
Michael 68cf51c8f8 Merge branch 'odin-lang:master' into raylib5 2023-12-04 16:49:35 +01:00
Colin Davidson bfbeb23f54 add resize non zeroed in more places 2023-12-04 03:09:13 -08:00
Colin Davidson 58e4a011c7 add non-zeroing append and resize 2023-12-04 00:08:13 -08:00
Michael 3de15987bd Merge branch 'odin-lang:master' into raylib5 2023-12-03 22:07:23 +01:00
Michael 39f8437f4d Merge branch 'odin-lang:master' into raylib5 2023-11-29 13:12:02 +01:00
Michael 058132e7e6 fixed names 2023-11-26 07:50:11 -07:00
Michael 9b7c5f2b1b Delete vendor/raylib/linux/libraygui.so.3.6 2023-11-26 07:49:12 -07:00
Michael 06e61c7315 Delete vendor/raylib/linux/raygui.a 2023-11-26 07:48:47 -07:00
Michael 1b23dbb228 Delete vendor/raylib/linux/libraygui.a 2023-11-26 07:48:36 -07:00
Michael cc2ba146a6 Delete vendor/raylib/linux/raygui.so 2023-11-26 07:48:26 -07:00
Michael 3bbdc93882 Updated dynlibs 2023-11-26 07:45:42 -07:00
Michael 0091193c04 added missing enums
GuiTextAlignmentVertical and GuiTextWrapMode
2023-11-26 01:45:55 -07:00
Michael 1b5bcc1a99 Added GuiToggleSlider 2023-11-26 08:29:29 +00:00
Michael fb48131f3c More minor fixes 2023-11-26 07:25:53 +00:00
Michael 9300c99d65 Merge branch 'odin-lang:master' into raylib5 2023-11-26 00:00:47 -07:00
Michael 9366bf44a6 Fixed a bunch of tab/space issues 2023-11-26 06:55:56 +00:00
Damian Tarnawski 1e726bb3e0 Fix scroll and visibilitychange event handling 2023-11-25 16:07:36 +01:00
Damian Tarnawski e0ecae66fd Fix set_element_value_string parameter name 2023-11-25 14:35:48 +01:00
Damian Tarnawski 0df7fe4247 Fix alignment 2023-11-25 14:23:41 +01:00
Damian Tarnawski 84a8e17482 Correct some typos in runtime.js 2023-11-25 14:22:17 +01:00
flysand7 03282c1234 [sys/linux]: Add epoll syscalls 2023-11-24 09:39:36 +11:00
sean arooni b21b5ef222 Updated bindings and libs for Raylib 5.0 2023-11-19 13:43:26 -05:00
flysand7 4e145cf69c [sys/linux]: Fix time(2) syscall not taking a pointer on ARM64 2023-11-10 08:32:49 +11:00
flysand7 341087a82b [sys/linux]: Fix creat(2) syscall not returning file descriptor 2023-11-10 08:31:52 +11:00
flysand7 851fd1f8d1 Fix missing return statement 2023-11-10 08:30:38 +11:00
flysand7 ce43b04688 time on arm64 2023-11-10 05:33:25 +11:00
flysand7 ff1ab74b3c [sys/linux]: Fix missing return; Remove TODO for select() 2023-11-10 05:24:24 +11:00
flysand7 aed67ba665 [sys/linux]: Fix arch-specific issues 2023-11-10 05:14:42 +11:00
flysand7 548ab2e1b6 [sys/linux]: utimensat takes array of two 2023-11-08 11:07:50 +11:00
flysand7 13a3c0e57c [sys/linux]: Fix syscalls: lseek, preadv, pwritev; Make read*/write* syscalls take byte slice instead of generic slice 2023-11-08 11:01:28 +11:00
flysand7 f26ed39e86 [sys/linux]: Fix compilation errors and -strict-style errors 2023-11-04 13:57:28 +11:00
flysand7 574d2baf09 [sys/linux]: Documentation improvements 2023-11-04 13:35:13 +11:00
flysand7 1e622979f8 [sys/linux]: Add more syscalls 2023-11-04 12:46:45 +11:00
flysand7 7faa146004 WIP 2023-11-03 00:56:20 +11:00
Karl Zylinski 75cb2c68cc Cleanup of json.clone_value 2023-11-01 00:57:27 +01:00
Karl Zylinski 942e91f94c Added temp allocator guard to json.marshal, in case we temp alloc when sorting map kesy 2023-11-01 00:46:01 +01:00
Karl Zylinski d8f06ed557 Reversed order of sort_maps_by_key check in marshal.odin to make PR comparison clearer. 2023-11-01 00:37:27 +01:00
Karl Zylinski a73ff00b02 Indentation fix. 2023-11-01 00:33:59 +01:00
Karl Zylinski a58a08c0c3 JSON: Option to sort marshaled maps before outputting. Also added a json.clone_value proc 2023-11-01 00:23:17 +01:00
640 changed files with 74708 additions and 56014 deletions
+1
View File
@@ -1 +1,2 @@
*.odin linguist-language=Odin
* text=auto
+53 -12
View File
@@ -3,11 +3,16 @@ on: [push, pull_request, workflow_dispatch]
jobs:
build_linux:
name: Ubuntu Build, Check, and Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Download LLVM, botan
run: sudo apt-get install llvm-11 clang-11 libbotan-2-dev botan
- name: Download LLVM
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 17
echo "/usr/lib/llvm-17/bin" >> $GITHUB_PATH
- name: build odin
run: ./build_odin.sh release
- name: Odin version
@@ -46,6 +51,9 @@ jobs:
- name: Odin check examples/all for Linux i386
run: ./odin check examples/all -vet -strict-style -target:linux_i386
timeout-minutes: 10
- name: Odin check examples/all for Linux arm64
run: ./odin check examples/all -vet -strict-style -target:linux_arm64
timeout-minutes: 10
- name: Odin check examples/all for FreeBSD amd64
run: ./odin check examples/all -vet -strict-style -target:freebsd_amd64
timeout-minutes: 10
@@ -53,15 +61,14 @@ jobs:
run: ./odin check examples/all -vet -strict-style -target:openbsd_amd64
timeout-minutes: 10
build_macOS:
name: MacOS Build, Check, and Test
runs-on: macos-latest
steps:
- uses: actions/checkout@v1
- name: Download LLVM, botan and setup PATH
- name: Download LLVM, and setup PATH
run: |
brew install llvm@13 botan
echo "/usr/local/opt/llvm@13/bin" >> $GITHUB_PATH
TMP_PATH=$(xcrun --show-sdk-path)/user/include
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
brew install llvm@17
echo "/usr/local/opt/llvm@17/bin" >> $GITHUB_PATH
- name: build odin
run: ./build_odin.sh release
- name: Odin version
@@ -92,13 +99,47 @@ jobs:
cd tests/internal
make
timeout-minutes: 10
- name: Odin check examples/all for Darwin arm64
run: ./odin check examples/all -vet -strict-style -target:darwin_arm64
build_macOS_arm:
name: MacOS ARM Build, Check, and Test
runs-on: macos-14 # This is an arm/m1 runner.
steps:
- uses: actions/checkout@v1
- name: Download LLVM and setup PATH
run: |
brew install llvm@17
echo "/opt/homebrew/opt/llvm@17/bin" >> $GITHUB_PATH
- name: build odin
run: ./build_odin.sh release
- name: Odin version
run: ./odin version
timeout-minutes: 1
- name: Odin report
run: ./odin report
timeout-minutes: 1
- name: Odin check
run: ./odin check examples/demo -vet
timeout-minutes: 10
- name: Odin check examples/all for Linux arm64
run: ./odin check examples/all -vet -strict-style -target:linux_arm64
- name: Odin run
run: ./odin run examples/demo
timeout-minutes: 10
- name: Odin run -debug
run: ./odin run examples/demo -debug
timeout-minutes: 10
- name: Odin check examples/all
run: ./odin check examples/all -strict-style
timeout-minutes: 10
- name: Core library tests
run: |
cd tests/core
make
timeout-minutes: 10
- name: Odin internals tests
run: |
cd tests/internal
make
timeout-minutes: 10
build_windows:
name: Windows Build, Check, and Test
runs-on: windows-2022
steps:
- uses: actions/checkout@v1
@@ -163,7 +204,7 @@ jobs:
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
cd tests\documentation
call build.bat
rem call build.bat
timeout-minutes: 10
- name: core:math/big tests
shell: cmd
+70 -15
View File
@@ -7,6 +7,7 @@ on:
jobs:
build_windows:
name: Windows Build
if: github.repository == 'odin-lang/Odin'
runs-on: windows-2022
steps:
@@ -29,6 +30,7 @@ jobs:
cp LICENSE dist
cp LLVM-C.dll dist
cp -r shared dist
cp -r base dist
cp -r core dist
cp -r vendor dist
cp -r bin dist
@@ -39,12 +41,17 @@ jobs:
name: windows_artifacts
path: dist
build_ubuntu:
name: Ubuntu Build
if: github.repository == 'odin-lang/Odin'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: (Linux) Download LLVM
run: sudo apt-get install llvm-11 clang-11
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 17
echo "/usr/lib/llvm-17/bin" >> $GITHUB_PATH
- name: build odin
run: make nightly
- name: Odin run
@@ -56,46 +63,88 @@ jobs:
cp LICENSE dist
cp libLLVM* dist
cp -r shared dist
cp -r base dist
cp -r core dist
cp -r vendor dist
cp -r examples dist
# Zipping so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
zip -r dist.zip dist
- name: Upload artifact
uses: actions/upload-artifact@v1
with:
name: ubuntu_artifacts
path: dist
path: dist.zip
build_macos:
name: MacOS Build
if: github.repository == 'odin-lang/Odin'
runs-on: macOS-latest
runs-on: macos-latest
steps:
- uses: actions/checkout@v1
- name: Download LLVM and setup PATH
run: |
brew install llvm@13
echo "/usr/local/opt/llvm@13/bin" >> $GITHUB_PATH
TMP_PATH=$(xcrun --show-sdk-path)/user/include
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
brew install llvm@17 dylibbundler
echo "/usr/local/opt/llvm@17/bin" >> $GITHUB_PATH
- name: build odin
run: make nightly
- name: Odin run
run: ./odin run examples/demo
- name: Copy artifacts
# These -L makes the linker prioritize system libraries over LLVM libraries, this is mainly to
# not link with libunwind bundled with LLVM but link with libunwind on the system.
run: CXXFLAGS="-L/usr/lib/system -L/usr/lib" make nightly
- name: Bundle
run: |
mkdir dist
cp odin dist
cp LICENSE dist
cp -r shared dist
cp -r base dist
cp -r core dist
cp -r vendor dist
cp -r examples dist
dylibbundler -b -x dist/odin -d dist/libs -od -p @executable_path/libs
# Zipping so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
zip -r dist.zip dist
- name: Odin run
run: ./dist/odin run examples/demo
- name: Upload artifact
uses: actions/upload-artifact@v1
with:
name: macos_artifacts
path: dist
path: dist.zip
build_macos_arm:
name: MacOS ARM Build
if: github.repository == 'odin-lang/Odin'
runs-on: macos-14 # ARM machine
steps:
- uses: actions/checkout@v1
- name: Download LLVM and setup PATH
run: |
brew install llvm@17 dylibbundler
echo "/opt/homebrew/opt/llvm@17/bin" >> $GITHUB_PATH
- name: build odin
# These -L makes the linker prioritize system libraries over LLVM libraries, this is mainly to
# not link with libunwind bundled with LLVM but link with libunwind on the system.
run: CXXFLAGS="-L/usr/lib/system -L/usr/lib" make nightly
- name: Bundle
run: |
mkdir dist
cp odin dist
cp LICENSE dist
cp -r shared dist
cp -r base dist
cp -r core dist
cp -r vendor dist
cp -r examples dist
dylibbundler -b -x dist/odin -d dist/libs -od -p @executable_path/libs
# Zipping so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38
zip -r dist.zip dist
- name: Odin run
run: ./dist/odin run examples/demo
- name: Upload artifact
uses: actions/upload-artifact@v1
with:
name: macos_arm_artifacts
path: dist.zip
upload_b2:
runs-on: [ubuntu-latest]
needs: [build_windows, build_macos, build_ubuntu]
needs: [build_windows, build_macos, build_macos_arm, build_ubuntu]
steps:
- uses: actions/checkout@v1
- uses: actions/setup-python@v2
@@ -126,6 +175,11 @@ jobs:
with:
name: macos_artifacts
- name: Download macOS arm artifacts
uses: actions/download-artifact@v1
with:
name: macos_arm_artifacts
- name: Create archives and upload
shell: bash
env:
@@ -140,8 +194,9 @@ jobs:
echo Uploading artifcates to B2
chmod +x ./ci/upload_create_nightly.sh
./ci/upload_create_nightly.sh "$BUCKET" windows-amd64 windows_artifacts/
./ci/upload_create_nightly.sh "$BUCKET" ubuntu-amd64 ubuntu_artifacts/
./ci/upload_create_nightly.sh "$BUCKET" macos-amd64 macos_artifacts/
./ci/upload_create_nightly.sh "$BUCKET" ubuntu-amd64 ubuntu_artifacts/dist.zip
./ci/upload_create_nightly.sh "$BUCKET" macos-amd64 macos_artifacts/dist.zip
./ci/upload_create_nightly.sh "$BUCKET" macos-arm64 macos_arm_artifacts/dist.zip
echo Deleting old artifacts in B2
python3 ci/delete_old_binaries.py "$BUCKET" "$DAYS_TO_KEEP"
+8 -1
View File
@@ -28,6 +28,7 @@ tests/internal/test_map
tests/internal/test_pow
tests/internal/test_rtti
tests/core/test_core_compress
tests/core/test_core_container
tests/core/test_core_filepath
tests/core/test_core_fmt
tests/core/test_core_i18n
@@ -39,7 +40,7 @@ tests/core/test_core_net
tests/core/test_core_os_exit
tests/core/test_core_reflect
tests/core/test_core_strings
tests/core/test_crypto_hash
tests/core/test_crypto
tests/core/test_hash
tests/core/test_hxa
tests/core/test_json
@@ -47,6 +48,9 @@ tests/core/test_linalg_glsl_math
tests/core/test_noise
tests/core/test_varint
tests/core/test_xml
tests/core/test_core_slice
tests/core/test_core_thread
tests/core/test_core_runtime
tests/vendor/vendor_botan
# Visual Studio 2015 cache/options directory
.vs/
@@ -312,3 +316,6 @@ shared/
examples/bug/
build.sh
!core/debug/
# RAD debugger project file
*.raddbg
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2016-2022 Ginger Bill. All rights reserved.
Copyright (c) 2016-2024 Ginger Bill. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -110,7 +110,7 @@ typeid_of :: proc($T: typeid) -> typeid ---
swizzle :: proc(x: [N]T, indices: ..int) -> [len(indices)]T ---
complex :: proc(real, imag: Float) -> Complex_Type ---
quaternion :: proc(real, imag, jmag, kmag: Float) -> Quaternion_Type ---
quaternion :: proc(imag, jmag, kmag, real: Float) -> Quaternion_Type --- // fields must be named
real :: proc(value: Complex_Or_Quaternion) -> Float ---
imag :: proc(value: Complex_Or_Quaternion) -> Float ---
jmag :: proc(value: Quaternion) -> Float ---
@@ -5,6 +5,12 @@ package intrinsics
// Package-Related
is_package_imported :: proc(package_name: string) -> bool ---
// Matrix Related Procedures
transpose :: proc(m: $T/matrix[$R, $C]$E) -> matrix[C, R]E ---
outer_product :: proc(a: $A/[$X]$E, b: $B/[$Y]E) -> matrix[X, Y]E ---
hadamard_product :: proc(a, b: $T/matrix[$R, $C]$E) -> T ---
matrix_flatten :: proc(m: $T/matrix[$R, $C]$E) -> [R*C]E ---
// Types
soa_struct :: proc($N: int, $T: typeid) -> type/#soa[N]T
@@ -287,7 +293,9 @@ wasm_memory_size :: proc(index: uintptr) -> int ---
// 0 - indicates that the thread blocked and then was woken up
// 1 - the loaded value from `ptr` did not match `expected`, the thread did not block
// 2 - the thread blocked, but the timeout
@(enable_target_feature="atomics")
wasm_memory_atomic_wait32 :: proc(ptr: ^u32, expected: u32, timeout_ns: i64) -> u32 ---
@(enable_target_feature="atomics")
wasm_memory_atomic_notify32 :: proc(ptr: ^u32, waiters: u32) -> (waiters_woken_up: u32) ---
// x86 Targets (i386, amd64)
@@ -18,9 +18,10 @@
// This could change at a later date if the all these data structures are
// implemented within the compiler rather than in this "preload" file
//
//+no-instrumentation
package runtime
import "core:intrinsics"
import "base:intrinsics"
// NOTE(bill): This must match the compiler's
Calling_Convention :: enum u8 {
@@ -176,10 +177,22 @@ Type_Info_Matrix :: struct {
row_count: int,
column_count: int,
// Total element count = column_count * elem_stride
layout: enum u8 {
Column_Major, // array of column vectors
Row_Major, // array of row vectors
},
}
Type_Info_Soa_Pointer :: struct {
elem: ^Type_Info,
}
Type_Info_Bit_Field :: struct {
backing_type: ^Type_Info,
names: []string,
types: []^Type_Info,
bit_sizes: []uintptr,
bit_offsets: []uintptr,
tags: []string,
}
Type_Info_Flag :: enum u8 {
Comparable = 0,
@@ -222,6 +235,7 @@ Type_Info :: struct {
Type_Info_Relative_Multi_Pointer,
Type_Info_Matrix,
Type_Info_Soa_Pointer,
Type_Info_Bit_Field,
},
}
@@ -255,6 +269,7 @@ Typeid_Kind :: enum u8 {
Relative_Multi_Pointer,
Matrix,
Soa_Pointer,
Bit_Field,
}
#assert(len(Typeid_Kind) < 32)
@@ -269,7 +284,7 @@ Typeid_Kind :: enum u8 {
// NOTE(bill): only the ones that are needed (not all types)
// This will be set by the compiler
type_table: []Type_Info
type_table: []^Type_Info
args__: []cstring
@@ -295,6 +310,14 @@ Source_Code_Location :: struct {
procedure: string,
}
/*
Used by the built-in directory `#load_directory(path: string) -> []Load_Directory_File`
*/
Load_Directory_File :: struct {
name: string,
data: []byte, // immutable data
}
Assertion_Failure_Proc :: #type proc(prefix, message: string, loc: Source_Code_Location) -> !
// Allocation Stuff
@@ -306,6 +329,7 @@ Allocator_Mode :: enum byte {
Query_Features,
Query_Info,
Alloc_Non_Zeroed,
Resize_Non_Zeroed,
}
Allocator_Mode_Set :: distinct bit_set[Allocator_Mode]
@@ -589,7 +613,7 @@ __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check
if n < 0 || n >= len(type_table) {
n = 0
}
return &type_table[n]
return type_table[n]
}
when !ODIN_NO_RTTI {
@@ -1,6 +1,6 @@
package runtime
import "core:intrinsics"
import "base:intrinsics"
@builtin
Maybe :: union($T: typeid) {T}
@@ -122,7 +122,7 @@ pop :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bou
// `pop_safe` trys to remove and return the end value of dynamic array `array` and reduces the length of `array` by 1.
// If the operation is not possible, it will return false.
@builtin
pop_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check {
pop_safe :: proc "contextless" (array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check {
if len(array) == 0 {
return
}
@@ -148,7 +148,7 @@ pop_front :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #
// `pop_front_safe` trys to return and remove the first value of dynamic array `array` and reduces the length of `array` by 1.
// If the operation is not possible, it will return false.
@builtin
pop_front_safe :: proc(array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check {
pop_front_safe :: proc "contextless" (array: ^$T/[dynamic]$E) -> (res: E, ok: bool) #no_bounds_check {
if len(array) == 0 {
return
}
@@ -169,10 +169,16 @@ clear :: proc{clear_dynamic_array, clear_map}
@builtin
reserve :: proc{reserve_dynamic_array, reserve_map}
// `resize` will try to resize memory of a passed dynamic array or map to the requested element count (setting the `len`, and possibly `cap`).
@builtin
non_zero_reserve :: proc{non_zero_reserve_dynamic_array}
// `resize` will try to resize memory of a passed dynamic array to the requested element count (setting the `len`, and possibly `cap`).
@builtin
resize :: proc{resize_dynamic_array}
@builtin
non_zero_resize :: proc{non_zero_resize_dynamic_array}
// Shrinks the capacity of a dynamic array or map down to the current length, or the given capacity.
@builtin
shrink :: proc{shrink_dynamic_array, shrink_map}
@@ -234,6 +240,8 @@ delete :: proc{
delete_dynamic_array,
delete_slice,
delete_map,
delete_soa_slice,
delete_soa_dynamic_array,
}
@@ -304,6 +312,7 @@ make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, alloca
@(builtin, require_results)
make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
make_dynamic_array_error_loc(loc, len, cap)
array.allocator = allocator // initialize allocator before just in case it fails to allocate any memory
data := mem_alloc_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return
s := Raw_Dynamic_Array{raw_data(data), len, cap, allocator}
if data == nil && size_of(E) != 0 {
@@ -346,7 +355,7 @@ make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := con
//
// Similar to `new`, the first argument is a type, not a value. Unlike new, make's return type is the same as the
// type of its argument, not a pointer to it.
// Make uses the specified allocator, default is context.allocator, default is context.allocator
// Make uses the specified allocator, default is context.allocator.
@builtin
make :: proc{
make_slice,
@@ -404,10 +413,7 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
return
}
@builtin
append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
_append_elem :: #force_inline proc(array: ^$T/[dynamic]$E, arg: E, should_zero: bool, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
if array == nil {
return 0, nil
}
@@ -418,7 +424,13 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) ->
} else {
if cap(array) < len(array)+1 {
cap := 2 * cap(array) + max(8, 1)
err = reserve(array, cap, loc) // do not 'or_return' here as it could be a partial success
// do not 'or_return' here as it could be a partial success
if should_zero {
err = reserve(array, cap, loc)
} else {
err = non_zero_reserve(array, cap, loc)
}
}
if cap(array)-len(array) > 0 {
a := (^Raw_Dynamic_Array)(array)
@@ -435,7 +447,16 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) ->
}
@builtin
append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
append_elem :: proc(array: ^$T/[dynamic]$E, #no_broadcast arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
return _append_elem(array, arg, true, loc=loc)
}
@builtin
non_zero_append_elem :: proc(array: ^$T/[dynamic]$E, #no_broadcast arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
return _append_elem(array, arg, false, loc=loc)
}
_append_elems :: #force_inline proc(array: ^$T/[dynamic]$E, should_zero: bool, loc := #caller_location, args: ..E) -> (n: int, err: Allocator_Error) #optional_allocator_error {
if array == nil {
return 0, nil
}
@@ -452,7 +473,13 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
} else {
if cap(array) < len(array)+arg_len {
cap := 2 * cap(array) + max(8, arg_len)
err = reserve(array, cap, loc) // do not 'or_return' here as it could be a partial success
// do not 'or_return' here as it could be a partial success
if should_zero {
err = reserve(array, cap, loc)
} else {
err = non_zero_reserve(array, cap, loc)
}
}
arg_len = min(cap(array)-len(array), arg_len)
if arg_len > 0 {
@@ -468,11 +495,33 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
}
}
@builtin
append_elems :: proc(array: ^$T/[dynamic]$E, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
return _append_elems(array, true, loc, ..args)
}
@builtin
non_zero_append_elems :: proc(array: ^$T/[dynamic]$E, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
return _append_elems(array, false, loc, ..args)
}
// The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type
_append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, should_zero: bool, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
args := transmute([]E)arg
if should_zero {
return append_elems(array, ..args, loc=loc)
} else {
return non_zero_append_elems(array, ..args, loc=loc)
}
}
@builtin
append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
args := transmute([]E)arg
return append_elems(array, ..args, loc=loc)
return _append_elem_string(array, arg, true, loc)
}
@builtin
non_zero_append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
return _append_elem_string(array, arg, false, loc)
}
@@ -492,6 +541,7 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_
// The append built-in procedure appends elements to the end of a dynamic array
@builtin append :: proc{append_elem, append_elems, append_elem_string}
@builtin non_zero_append :: proc{non_zero_append_elem, non_zero_append_elems, non_zero_append_elem_string}
@builtin
@@ -506,7 +556,7 @@ append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (n: i
@builtin
inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, #no_broadcast arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
if array == nil {
return
}
@@ -524,7 +574,7 @@ inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
}
@builtin
inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
if array == nil {
return
}
@@ -587,11 +637,14 @@ assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
@builtin
assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
if index+len(args) < len(array) {
new_size := index + len(args)
if len(args) == 0 {
ok = true
} else if new_size < len(array) {
copy(array[index:], args)
ok = true
} else {
resize(array, index+1+len(args), loc) or_return
resize(array, new_size, loc) or_return
copy(array[index:], args)
ok = true
}
@@ -633,8 +686,7 @@ clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
// `reserve_dynamic_array` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`).
//
// Note: Prefer the procedure group `reserve`.
@builtin
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
_reserve_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, capacity: int, should_zero: bool, loc := #caller_location) -> Allocator_Error {
if array == nil {
return nil
}
@@ -653,7 +705,12 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
new_size := capacity * size_of(E)
allocator := a.allocator
new_data := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
new_data: []byte
if should_zero {
new_data = mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
} else {
new_data = non_zero_mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
}
if new_data == nil && new_size > 0 {
return .Out_Of_Memory
}
@@ -663,17 +720,29 @@ reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #cal
return nil
}
@builtin
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
return _reserve_dynamic_array(array, capacity, true, loc)
}
@builtin
non_zero_reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
return _reserve_dynamic_array(array, capacity, false, loc)
}
// `resize_dynamic_array` will try to resize memory of a passed dynamic array or map to the requested element count (setting the `len`, and possibly `cap`).
//
// Note: Prefer the procedure group `resize`
@builtin
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
_resize_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, length: int, should_zero: bool, loc := #caller_location) -> Allocator_Error {
if array == nil {
return nil
}
a := (^Raw_Dynamic_Array)(array)
if length <= a.cap {
if should_zero && a.len < length {
intrinsics.mem_zero(([^]E)(a.data)[a.len:], (length-a.len)*size_of(E))
}
a.len = max(length, 0)
return nil
}
@@ -687,7 +756,12 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller
new_size := length * size_of(E)
allocator := a.allocator
new_data := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
new_data : []byte
if should_zero {
new_data = mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
} else {
new_data = non_zero_mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
}
if new_data == nil && new_size > 0 {
return .Out_Of_Memory
}
@@ -698,6 +772,16 @@ resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller
return nil
}
@builtin
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
return _resize_dynamic_array(array, length, true, loc=loc)
}
@builtin
non_zero_resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
return _resize_dynamic_array(array, length, false, loc=loc)
}
/*
Shrinks the capacity of a dynamic array down to the current length, or the given capacity.
@@ -743,42 +827,25 @@ map_insert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location)
return (^V)(__dynamic_map_set_without_hash((^Raw_Map)(m), map_info(T), rawptr(&key), rawptr(&value), loc))
}
@builtin
incl_elem :: proc(s: ^$S/bit_set[$E; $U], elem: E) {
s^ |= {elem}
}
@builtin
incl_elems :: proc(s: ^$S/bit_set[$E; $U], elems: ..E) {
for elem in elems {
s^ |= {elem}
// Explicitly inserts a key and value into a map `m`, the same as `map_insert`, but the return values differ.
// - `prev_key` will return the previous pointer of a key if it exists, check `found_previous` if was previously found
// - `value_ptr` will return the pointer of the memory where the insertion happens, and `nil` if the map failed to resize
// - `found_previous` will be true a previous key was found
@(builtin, require_results)
map_upsert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (prev_key: K, value_ptr: ^V, found_previous: bool) {
key, value := key, value
kp, vp := __dynamic_map_set_extra_without_hash((^Raw_Map)(m), map_info(T), rawptr(&key), rawptr(&value), loc)
if kp != nil {
prev_key = (^K)(kp)^
found_previous = true
}
value_ptr = (^V)(vp)
return
}
@builtin
incl_bit_set :: proc(s: ^$S/bit_set[$E; $U], other: S) {
s^ |= other
}
@builtin
excl_elem :: proc(s: ^$S/bit_set[$E; $U], elem: E) {
s^ &~= {elem}
}
@builtin
excl_elems :: proc(s: ^$S/bit_set[$E; $U], elems: ..E) {
for elem in elems {
s^ &~= {elem}
}
}
@builtin
excl_bit_set :: proc(s: ^$S/bit_set[$E; $U], other: S) {
s^ &~= other
}
@builtin incl :: proc{incl_elem, incl_elems, incl_bit_set}
@builtin excl :: proc{excl_elem, excl_elems, excl_bit_set}
@builtin
card :: proc(s: $S/bit_set[$E; $U]) -> int {
card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int {
when size_of(S) == 1 {
return int(intrinsics.count_ones(transmute(u8)s))
} else when size_of(S) == 2 {
@@ -1,6 +1,6 @@
package runtime
import "core:intrinsics"
import "base:intrinsics"
_ :: intrinsics
/*
@@ -425,4 +425,97 @@ clear_soa_dynamic_array :: proc(array: ^$T/#soa[dynamic]$E) {
@builtin
clear_soa :: proc{
clear_soa_dynamic_array,
}
}
// Converts soa slice into a soa dynamic array without cloning or allocating memory
@(require_results)
into_dynamic_soa :: proc(array: $T/#soa[]$E) -> #soa[dynamic]E {
d: #soa[dynamic]E
footer := raw_soa_footer_dynamic_array(&d)
footer^ = {
cap = len(array),
len = 0,
allocator = nil_allocator(),
}
field_count: uintptr
when intrinsics.type_is_array(E) {
field_count = len(E)
} else {
field_count = uintptr(intrinsics.type_struct_field_count(E))
}
array := array
dynamic_data := ([^]rawptr)(&d)[:field_count]
slice_data := ([^]rawptr)(&array)[:field_count]
copy(dynamic_data, slice_data)
return d
}
// `unordered_remove_soa` removed the element at the specified `index`. It does so by replacing the current end value
// with the old value, and reducing the length of the dynamic array by 1.
//
// Note: This is an O(1) operation.
// Note: If you the elements to remain in their order, use `ordered_remove_soa`.
// Note: If the index is out of bounds, this procedure will panic.
@builtin
unordered_remove_soa :: proc(array: ^$T/#soa[dynamic]$E, index: int, loc := #caller_location) #no_bounds_check {
bounds_check_error_loc(loc, index, len(array))
if index+1 < len(array) {
ti := type_info_of(typeid_of(T))
ti = type_info_base(ti)
si := &ti.variant.(Type_Info_Struct)
field_count: uintptr
when intrinsics.type_is_array(E) {
field_count = len(E)
} else {
field_count = uintptr(intrinsics.type_struct_field_count(E))
}
data := uintptr(array)
for i in 0..<field_count {
type := si.types[i].variant.(Type_Info_Pointer).elem
offset := rawptr((^uintptr)(data)^ + uintptr(index*type.size))
final := rawptr((^uintptr)(data)^ + uintptr((len(array)-1)*type.size))
mem_copy(offset, final, type.size)
data += size_of(rawptr)
}
}
raw_soa_footer_dynamic_array(array).len -= 1
}
// `ordered_remove_soa` removed the element at the specified `index` whilst keeping the order of the other elements.
//
// Note: This is an O(N) operation.
// Note: If you the elements do not have to remain in their order, prefer `unordered_remove_soa`.
// Note: If the index is out of bounds, this procedure will panic.
@builtin
ordered_remove_soa :: proc(array: ^$T/#soa[dynamic]$E, index: int, loc := #caller_location) #no_bounds_check {
bounds_check_error_loc(loc, index, len(array))
if index+1 < len(array) {
ti := type_info_of(typeid_of(T))
ti = type_info_base(ti)
si := &ti.variant.(Type_Info_Struct)
field_count: uintptr
when intrinsics.type_is_array(E) {
field_count = len(E)
} else {
field_count = uintptr(intrinsics.type_struct_field_count(E))
}
data := uintptr(array)
for i in 0..<field_count {
type := si.types[i].variant.(Type_Info_Pointer).elem
offset := (^uintptr)(data)^ + uintptr(index*type.size)
length := type.size*(len(array) - index - 1)
mem_copy(rawptr(offset), rawptr(offset + uintptr(type.size)), length)
data += size_of(rawptr)
}
}
raw_soa_footer_dynamic_array(array).len -= 1
}
@@ -1,6 +1,6 @@
package runtime
import "core:intrinsics"
import "base:intrinsics"
DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE :: uint(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE)
@@ -28,11 +28,11 @@ safe_add :: #force_inline proc "contextless" (x, y: uint) -> (uint, bool) {
}
@(require_results)
memory_block_alloc :: proc(allocator: Allocator, capacity: uint, loc := #caller_location) -> (block: ^Memory_Block, err: Allocator_Error) {
total_size := uint(capacity + size_of(Memory_Block))
base_offset := uintptr(size_of(Memory_Block))
memory_block_alloc :: proc(allocator: Allocator, capacity: uint, alignment: uint, loc := #caller_location) -> (block: ^Memory_Block, err: Allocator_Error) {
total_size := uint(capacity + max(alignment, size_of(Memory_Block)))
base_offset := uintptr(max(alignment, size_of(Memory_Block)))
min_alignment: int = max(16, align_of(Memory_Block))
min_alignment: int = max(16, align_of(Memory_Block), int(alignment))
data := mem_alloc(int(total_size), min_alignment, allocator, loc) or_return
block = (^Memory_Block)(raw_data(data))
end := uintptr(raw_data(data)[len(data):])
@@ -102,20 +102,20 @@ arena_alloc :: proc(arena: ^Arena, size, alignment: uint, loc := #caller_locatio
if size == 0 {
return
}
if arena.curr_block == nil || (safe_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.capacity {
size = align_forward_uint(size, alignment)
needed := align_forward_uint(size, alignment)
if arena.curr_block == nil || (safe_add(arena.curr_block.used, needed) or_else 0) > arena.curr_block.capacity {
if arena.minimum_block_size == 0 {
arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE
}
block_size := max(size, arena.minimum_block_size)
block_size := max(needed, arena.minimum_block_size)
if arena.backing_allocator.procedure == nil {
arena.backing_allocator = default_allocator()
}
new_block := memory_block_alloc(arena.backing_allocator, block_size, loc) or_return
new_block := memory_block_alloc(arena.backing_allocator, block_size, alignment, loc) or_return
new_block.prev = arena.curr_block
arena.curr_block = new_block
arena.total_capacity += new_block.capacity
@@ -134,7 +134,7 @@ arena_init :: proc(arena: ^Arena, size: uint, backing_allocator: Allocator, loc
arena^ = {}
arena.backing_allocator = backing_allocator
arena.minimum_block_size = max(size, 1<<12) // minimum block size of 4 KiB
new_block := memory_block_alloc(arena.backing_allocator, arena.minimum_block_size, loc) or_return
new_block := memory_block_alloc(arena.backing_allocator, arena.minimum_block_size, 0, loc) or_return
arena.curr_block = new_block
arena.total_capacity += new_block.capacity
return nil
@@ -195,7 +195,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
err = .Mode_Not_Implemented
case .Free_All:
arena_free_all(arena, location)
case .Resize:
case .Resize, .Resize_Non_Zeroed:
old_data := ([^]byte)(old_memory)
switch {
@@ -0,0 +1,12 @@
package runtime
when ODIN_DEFAULT_TO_NIL_ALLOCATOR {
default_allocator_proc :: nil_allocator_proc
default_allocator :: nil_allocator
} else when ODIN_DEFAULT_TO_PANIC_ALLOCATOR {
default_allocator_proc :: panic_allocator_proc
default_allocator :: panic_allocator
} else {
default_allocator :: heap_allocator
default_allocator_proc :: heap_allocator_proc
}
@@ -10,7 +10,7 @@ nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
return nil, .None
case .Free_All:
return nil, .Mode_Not_Implemented
case .Resize:
case .Resize, .Resize_Non_Zeroed:
if size == 0 {
return nil, .None
}
@@ -31,14 +31,6 @@ nil_allocator :: proc() -> Allocator {
}
when ODIN_OS == .Freestanding {
default_allocator_proc :: nil_allocator_proc
default_allocator :: nil_allocator
}
panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
@@ -55,6 +47,10 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
if size > 0 {
panic("panic allocator, .Resize called", loc=loc)
}
case .Resize_Non_Zeroed:
if size > 0 {
panic("panic allocator, .Alloc_Non_Zeroed called", loc=loc)
}
case .Free:
if old_memory != nil {
panic("panic allocator, .Free called", loc=loc)
@@ -44,7 +44,7 @@ memcpy
memove
## Procedures required by the LLVM backend
## Procedures required by the LLVM backend if u128/i128 is used
umodti3
udivti3
modti3
@@ -59,11 +59,12 @@ truncdfhf2
gnu_h2f_ieee
gnu_f2h_ieee
extendhfsf2
## Procedures required by the LLVM backend if f16 is used
__ashlti3 // wasm specific
__multi3 // wasm specific
## Required an entry point is defined (i.e. 'main')
args__
@@ -1,6 +1,6 @@
package runtime
import "core:intrinsics"
import "base:intrinsics"
_ :: intrinsics
// High performance, cache-friendly, open-addressed Robin Hood hashing hash map
@@ -391,7 +391,8 @@ map_alloc_dynamic :: proc "odin" (info: ^Map_Info, log2_capacity: uintptr, alloc
// arrays to reduce variance. This swapping can only be done with memcpy since
// there is no type information.
//
// This procedure returns the address of the just inserted value.
// This procedure returns the address of the just inserted value, and will
// return 'nil' if there was no room to insert the entry
@(require_results)
map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, h: Map_Hash, ik: uintptr, iv: uintptr) -> (result: uintptr) {
h := h
@@ -415,6 +416,11 @@ map_insert_hash_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^
tv := map_cell_index_dynamic(sv, info.vs, 1)
swap_loop: for {
if distance > mask {
// Failed to find an empty slot and prevent infinite loop
panic("unable to insert into a map")
}
element_hash := hs[pos]
if map_hash_is_empty(element_hash) {
@@ -841,6 +847,33 @@ __dynamic_map_get :: proc "contextless" (#no_alias m: ^Raw_Map, #no_alias info:
}
}
__dynamic_map_get_key_and_value :: proc "contextless" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, h: Map_Hash, key: rawptr) -> (key_ptr, value_ptr: rawptr) {
if m.len == 0 {
return nil, nil
}
pos := map_desired_position(m^, h)
distance := uintptr(0)
mask := (uintptr(1) << map_log2_cap(m^)) - 1
ks, vs, hs, _, _ := map_kvh_data_dynamic(m^, info)
for {
element_hash := hs[pos]
if map_hash_is_empty(element_hash) {
return nil, nil
} else if distance > map_probe_distance(m^, element_hash, pos) {
return nil, nil
} else if element_hash == h {
other_key := rawptr(map_cell_index_dynamic(ks, info.ks, pos))
if info.key_equal(key, other_key) {
key_ptr = other_key
value_ptr = rawptr(map_cell_index_dynamic(vs, info.vs, pos))
return
}
}
pos = (pos + 1) & mask
distance += 1
}
}
// IMPORTANT: USED WITHIN THE COMPILER
__dynamic_map_check_grow :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, loc := #caller_location) -> (err: Allocator_Error, has_grown: bool) {
if m.len >= map_resize_threshold(m^) {
@@ -871,9 +904,37 @@ __dynamic_map_set :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_In
}
result := map_insert_hash_dynamic(m, info, hash, uintptr(key), uintptr(value))
m.len += 1
if result != 0 {
m.len += 1
}
return rawptr(result)
}
__dynamic_map_set_extra_without_hash :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, key, value: rawptr, loc := #caller_location) -> (prev_key_ptr, value_ptr: rawptr) {
return __dynamic_map_set_extra(m, info, info.key_hasher(key, map_seed(m^)), key, value, loc)
}
__dynamic_map_set_extra :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, hash: Map_Hash, key, value: rawptr, loc := #caller_location) -> (prev_key_ptr, value_ptr: rawptr) {
if prev_key_ptr, value_ptr = __dynamic_map_get_key_and_value(m, info, hash, key); value_ptr != nil {
intrinsics.mem_copy_non_overlapping(value_ptr, value, info.vs.size_of_type)
return
}
hash := hash
err, has_grown := __dynamic_map_check_grow(m, info, loc)
if err != nil {
return nil, nil
}
if has_grown {
hash = info.key_hasher(key, map_seed(m^))
}
result := map_insert_hash_dynamic(m, info, hash, uintptr(key), uintptr(value))
if result != 0 {
m.len += 1
}
return nil, rawptr(result)
}
// IMPORTANT: USED WITHIN THE COMPILER
@(private)
@@ -1,8 +1,9 @@
//+private
//+build linux, darwin, freebsd, openbsd
//+build linux, darwin, freebsd, openbsd, haiku
//+no-instrumentation
package runtime
import "core:intrinsics"
import "base:intrinsics"
when ODIN_BUILD_MODE == .Dynamic {
@(link_name="_odin_entry_point", linkage="strong", require/*, link_section=".init"*/)
@@ -1,8 +1,9 @@
//+private
//+build wasm32, wasm64p32
//+no-instrumentation
package runtime
import "core:intrinsics"
import "base:intrinsics"
when !ODIN_TEST && !ODIN_NO_ENTRY_POINT {
@(link_name="_start", linkage="strong", require, export)
@@ -1,12 +1,13 @@
//+private
//+build windows
//+no-instrumentation
package runtime
import "core:intrinsics"
import "base:intrinsics"
when ODIN_BUILD_MODE == .Dynamic {
@(link_name="DllMain", linkage="strong", require)
DllMain :: proc "stdcall" (hinstDLL: rawptr, fdwReason: u32, lpReserved: rawptr) -> b32 {
DllMain :: proc "system" (hinstDLL: rawptr, fdwReason: u32, lpReserved: rawptr) -> b32 {
context = default_context()
// Populate Windows DLL-specific global
@@ -28,7 +29,7 @@ when ODIN_BUILD_MODE == .Dynamic {
} else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT {
when ODIN_ARCH == .i386 || ODIN_NO_CRT {
@(link_name="mainCRTStartup", linkage="strong", require)
mainCRTStartup :: proc "stdcall" () -> i32 {
mainCRTStartup :: proc "system" () -> i32 {
context = default_context()
#force_no_inline _startup_runtime()
intrinsics.__entry_point()
@@ -1,5 +1,6 @@
package runtime
@(no_instrumentation)
bounds_trap :: proc "contextless" () -> ! {
when ODIN_OS == .Windows {
windows_trap_array_bounds()
@@ -8,6 +9,7 @@ bounds_trap :: proc "contextless" () -> ! {
}
}
@(no_instrumentation)
type_assertion_trap :: proc "contextless" () -> ! {
when ODIN_OS == .Windows {
windows_trap_type_assertion()
@@ -21,7 +23,7 @@ bounds_check_error :: proc "contextless" (file: string, line, column: i32, index
if uint(index) < uint(count) {
return
}
@(cold)
@(cold, no_instrumentation)
handle_error :: proc "contextless" (file: string, line, column: i32, index, count: int) -> ! {
print_caller_location(Source_Code_Location{file, line, column, ""})
print_string(" Index ")
@@ -34,6 +36,7 @@ bounds_check_error :: proc "contextless" (file: string, line, column: i32, index
handle_error(file, line, column, index, count)
}
@(no_instrumentation)
slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int, len: int) -> ! {
print_caller_location(Source_Code_Location{file, line, column, ""})
print_string(" Invalid slice indices ")
@@ -46,6 +49,7 @@ slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, h
bounds_trap()
}
@(no_instrumentation)
multi_pointer_slice_handle_error :: proc "contextless" (file: string, line, column: i32, lo, hi: int) -> ! {
print_caller_location(Source_Code_Location{file, line, column, ""})
print_string(" Invalid slice indices ")
@@ -82,7 +86,7 @@ dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32,
if 0 <= low && low <= high && high <= max {
return
}
@(cold)
@(cold, no_instrumentation)
handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) -> ! {
print_caller_location(Source_Code_Location{file, line, column, ""})
print_string(" Invalid dynamic array indices ")
@@ -103,7 +107,7 @@ matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32
uint(column_index) < uint(column_count) {
return
}
@(cold)
@(cold, no_instrumentation)
handle_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) -> ! {
print_caller_location(Source_Code_Location{file, line, column, ""})
print_string(" Matrix indices [")
@@ -127,7 +131,7 @@ when ODIN_NO_RTTI {
if ok {
return
}
@(cold)
@(cold, no_instrumentation)
handle_error :: proc "contextless" (file: string, line, column: i32) -> ! {
print_caller_location(Source_Code_Location{file, line, column, ""})
print_string(" Invalid type assertion\n")
@@ -140,7 +144,7 @@ when ODIN_NO_RTTI {
if ok {
return
}
@(cold)
@(cold, no_instrumentation)
handle_error :: proc "contextless" (file: string, line, column: i32) -> ! {
print_caller_location(Source_Code_Location{file, line, column, ""})
print_string(" Invalid type assertion\n")
@@ -153,7 +157,7 @@ when ODIN_NO_RTTI {
if ok {
return
}
@(cold)
@(cold, no_instrumentation)
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid) -> ! {
print_caller_location(Source_Code_Location{file, line, column, ""})
print_string(" Invalid type assertion from ")
@@ -198,7 +202,7 @@ when ODIN_NO_RTTI {
return id
}
@(cold)
@(cold, no_instrumentation)
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) -> ! {
actual := variant_type(from, from_data)
@@ -224,7 +228,7 @@ make_slice_error_loc :: #force_inline proc "contextless" (loc := #caller_locatio
if 0 <= len {
return
}
@(cold)
@(cold, no_instrumentation)
handle_error :: proc "contextless" (loc: Source_Code_Location, len: int) -> ! {
print_caller_location(loc)
print_string(" Invalid slice length for make: ")
@@ -239,7 +243,7 @@ make_dynamic_array_error_loc :: #force_inline proc "contextless" (loc := #caller
if 0 <= len && len <= cap {
return
}
@(cold)
@(cold, no_instrumentation)
handle_error :: proc "contextless" (loc: Source_Code_Location, len, cap: int) -> ! {
print_caller_location(loc)
print_string(" Invalid dynamic array parameters for make: ")
@@ -256,7 +260,7 @@ make_map_expr_error_loc :: #force_inline proc "contextless" (loc := #caller_loca
if 0 <= cap {
return
}
@(cold)
@(cold, no_instrumentation)
handle_error :: proc "contextless" (loc: Source_Code_Location, cap: int) -> ! {
print_caller_location(loc)
print_string(" Invalid map capacity for make: ")
+110
View File
@@ -0,0 +1,110 @@
package runtime
import "base:intrinsics"
heap_allocator :: proc() -> Allocator {
return Allocator{
procedure = heap_allocator_proc,
data = nil,
}
}
heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
//
// NOTE(tetra, 2020-01-14): The heap doesn't respect alignment.
// Instead, we overallocate by `alignment + size_of(rawptr) - 1`, and insert
// padding. We also store the original pointer returned by heap_alloc right before
// the pointer we return to the user.
//
aligned_alloc :: proc(size, alignment: int, old_ptr: rawptr = nil, zero_memory := true) -> ([]byte, Allocator_Error) {
a := max(alignment, align_of(rawptr))
space := size + a - 1
allocated_mem: rawptr
if old_ptr != nil {
original_old_ptr := ([^]rawptr)(old_ptr)[-1]
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr))
} else {
allocated_mem = heap_alloc(space+size_of(rawptr), zero_memory)
}
aligned_mem := rawptr(([^]u8)(allocated_mem)[size_of(rawptr):])
ptr := uintptr(aligned_mem)
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
diff := int(aligned_ptr - ptr)
if (size + diff) > space || allocated_mem == nil {
return nil, .Out_Of_Memory
}
aligned_mem = rawptr(aligned_ptr)
([^]rawptr)(aligned_mem)[-1] = allocated_mem
return byte_slice(aligned_mem, size), nil
}
aligned_free :: proc(p: rawptr) {
if p != nil {
heap_free(([^]rawptr)(p)[-1])
}
}
aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int, zero_memory := true) -> (new_memory: []byte, err: Allocator_Error) {
if p == nil {
return nil, nil
}
new_memory = aligned_alloc(new_size, new_alignment, p, zero_memory) or_return
// NOTE: heap_resize does not zero the new memory, so we do it
if zero_memory && new_size > old_size {
new_region := raw_data(new_memory[old_size:])
intrinsics.mem_zero(new_region, new_size - old_size)
}
return
}
switch mode {
case .Alloc, .Alloc_Non_Zeroed:
return aligned_alloc(size, alignment, nil, mode == .Alloc)
case .Free:
aligned_free(old_memory)
case .Free_All:
return nil, .Mode_Not_Implemented
case .Resize, .Resize_Non_Zeroed:
if old_memory == nil {
return aligned_alloc(size, alignment, nil, mode == .Resize)
}
return aligned_resize(old_memory, old_size, size, alignment, mode == .Resize)
case .Query_Features:
set := (^Allocator_Mode_Set)(old_memory)
if set != nil {
set^ = {.Alloc, .Alloc_Non_Zeroed, .Free, .Resize, .Resize_Non_Zeroed, .Query_Features}
}
return nil, nil
case .Query_Info:
return nil, .Mode_Not_Implemented
}
return nil, nil
}
heap_alloc :: proc(size: int, zero_memory := true) -> rawptr {
return _heap_alloc(size, zero_memory)
}
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
return _heap_resize(ptr, new_size)
}
heap_free :: proc(ptr: rawptr) {
_heap_free(ptr)
}
+15
View File
@@ -0,0 +1,15 @@
//+build js, wasi, freestanding, essence
//+private
package runtime
_heap_alloc :: proc(size: int, zero_memory := true) -> rawptr {
unimplemented("base:runtime 'heap_alloc' procedure is not supported on this platform")
}
_heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
unimplemented("base:runtime 'heap_resize' procedure is not supported on this platform")
}
_heap_free :: proc(ptr: rawptr) {
unimplemented("base:runtime 'heap_free' procedure is not supported on this platform")
}
+38
View File
@@ -0,0 +1,38 @@
//+build linux, darwin, freebsd, openbsd, haiku
//+private
package runtime
when ODIN_OS == .Darwin {
foreign import libc "system:System.framework"
} else {
foreign import libc "system:c"
}
@(default_calling_convention="c")
foreign libc {
@(link_name="malloc") _unix_malloc :: proc(size: int) -> rawptr ---
@(link_name="calloc") _unix_calloc :: proc(num, size: int) -> rawptr ---
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---
}
_heap_alloc :: proc(size: int, zero_memory := true) -> rawptr {
if size <= 0 {
return nil
}
if zero_memory {
return _unix_calloc(1, size)
} else {
return _unix_malloc(size)
}
}
_heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
// NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on
// POSIX platforms. Ensure your caller takes this into account.
return _unix_realloc(ptr, new_size)
}
_heap_free :: proc(ptr: rawptr) {
_unix_free(ptr)
}
+39
View File
@@ -0,0 +1,39 @@
package runtime
foreign import kernel32 "system:Kernel32.lib"
@(private="file")
@(default_calling_convention="system")
foreign kernel32 {
// NOTE(bill): The types are not using the standard names (e.g. DWORD and LPVOID) to just minimizing the dependency
// default_allocator
GetProcessHeap :: proc() -> rawptr ---
HeapAlloc :: proc(hHeap: rawptr, dwFlags: u32, dwBytes: uint) -> rawptr ---
HeapReAlloc :: proc(hHeap: rawptr, dwFlags: u32, lpMem: rawptr, dwBytes: uint) -> rawptr ---
HeapFree :: proc(hHeap: rawptr, dwFlags: u32, lpMem: rawptr) -> b32 ---
}
_heap_alloc :: proc(size: int, zero_memory := true) -> rawptr {
HEAP_ZERO_MEMORY :: 0x00000008
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY if zero_memory else 0, uint(size))
}
_heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
if new_size == 0 {
_heap_free(ptr)
return nil
}
if ptr == nil {
return _heap_alloc(new_size)
}
HEAP_ZERO_MEMORY :: 0x00000008
return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptr, uint(new_size))
}
_heap_free :: proc(ptr: rawptr) {
if ptr == nil {
return
}
HeapFree(GetProcessHeap(), 0, ptr)
}
@@ -1,6 +1,6 @@
package runtime
import "core:intrinsics"
import "base:intrinsics"
@(private="file")
IS_WASM :: ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
@@ -11,7 +11,7 @@ RUNTIME_LINKAGE :: "strong" when (
ODIN_BUILD_MODE == .Dynamic ||
!ODIN_NO_CRT) &&
!IS_WASM) else "internal"
RUNTIME_REQUIRE :: !ODIN_TILDE
RUNTIME_REQUIRE :: false // !ODIN_TILDE
@(private)
__float16 :: f16 when __ODIN_LLVM_F16_SUPPORTED else u16
@@ -22,51 +22,7 @@ byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byt
return ([^]byte)(data)[:max(len, 0)]
}
bswap_16 :: proc "contextless" (x: u16) -> u16 {
return x>>8 | x<<8
}
bswap_32 :: proc "contextless" (x: u32) -> u32 {
return x>>24 | (x>>8)&0xff00 | (x<<8)&0xff0000 | x<<24
}
bswap_64 :: proc "contextless" (x: u64) -> u64 {
z := x
z = (z & 0x00000000ffffffff) << 32 | (z & 0xffffffff00000000) >> 32
z = (z & 0x0000ffff0000ffff) << 16 | (z & 0xffff0000ffff0000) >> 16
z = (z & 0x00ff00ff00ff00ff) << 8 | (z & 0xff00ff00ff00ff00) >> 8
return z
}
bswap_128 :: proc "contextless" (x: u128) -> u128 {
z := transmute([4]u32)x
z[0], z[3] = bswap_32(z[3]), bswap_32(z[0])
z[1], z[2] = bswap_32(z[2]), bswap_32(z[1])
return transmute(u128)z
}
bswap_f16 :: proc "contextless" (f: f16) -> f16 {
x := transmute(u16)f
z := bswap_16(x)
return transmute(f16)z
}
bswap_f32 :: proc "contextless" (f: f32) -> f32 {
x := transmute(u32)f
z := bswap_32(x)
return transmute(f32)z
}
bswap_f64 :: proc "contextless" (f: f64) -> f64 {
x := transmute(u64)f
z := bswap_64(x)
return transmute(f64)z
}
is_power_of_two_int :: #force_inline proc(x: int) -> bool {
is_power_of_two_int :: #force_inline proc "contextless" (x: int) -> bool {
if x <= 0 {
return false
}
@@ -84,7 +40,7 @@ align_forward_int :: #force_inline proc(ptr, align: int) -> int {
return p
}
is_power_of_two_uintptr :: #force_inline proc(x: uintptr) -> bool {
is_power_of_two_uintptr :: #force_inline proc "contextless" (x: uintptr) -> bool {
if x <= 0 {
return false
}
@@ -187,7 +143,7 @@ mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #calle
return
}
mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
_mem_resize :: #force_inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, should_zero: bool, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
if allocator.procedure == nil {
return nil, nil
}
@@ -198,15 +154,27 @@ mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAUL
}
return
} else if ptr == nil {
return allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
if should_zero {
return allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
} else {
return allocator.procedure(allocator.data, .Alloc_Non_Zeroed, new_size, alignment, nil, 0, loc)
}
} else if old_size == new_size && uintptr(ptr) % uintptr(alignment) == 0 {
data = ([^]byte)(ptr)[:old_size]
return
}
data, err = allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc)
if should_zero {
data, err = allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc)
} else {
data, err = allocator.procedure(allocator.data, .Resize_Non_Zeroed, new_size, alignment, ptr, old_size, loc)
}
if err == .Mode_Not_Implemented {
data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
if should_zero {
data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
} else {
data, err = allocator.procedure(allocator.data, .Alloc_Non_Zeroed, new_size, alignment, nil, 0, loc)
}
if err != nil {
return
}
@@ -216,6 +184,13 @@ mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAUL
return
}
mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
return _mem_resize(ptr, old_size, new_size, alignment, allocator, true, loc)
}
non_zero_mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
return _mem_resize(ptr, old_size, new_size, alignment, allocator, false, loc)
}
memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
switch {
case n == 0: return true
@@ -589,36 +564,6 @@ string_decode_last_rune :: proc "contextless" (s: string) -> (rune, int) {
return r, size
}
abs_f16 :: #force_inline proc "contextless" (x: f16) -> f16 {
return -x if x < 0 else x
}
abs_f32 :: #force_inline proc "contextless" (x: f32) -> f32 {
return -x if x < 0 else x
}
abs_f64 :: #force_inline proc "contextless" (x: f64) -> f64 {
return -x if x < 0 else x
}
min_f16 :: #force_inline proc "contextless" (a, b: f16) -> f16 {
return a if a < b else b
}
min_f32 :: #force_inline proc "contextless" (a, b: f32) -> f32 {
return a if a < b else b
}
min_f64 :: #force_inline proc "contextless" (a, b: f64) -> f64 {
return a if a < b else b
}
max_f16 :: #force_inline proc "contextless" (a, b: f16) -> f16 {
return a if a > b else b
}
max_f32 :: #force_inline proc "contextless" (a, b: f32) -> f32 {
return a if a > b else b
}
max_f64 :: #force_inline proc "contextless" (a, b: f64) -> f64 {
return a if a > b else b
}
abs_complex32 :: #force_inline proc "contextless" (x: complex32) -> f16 {
p, q := abs(real(x)), abs(imag(x))
if p < q {
@@ -730,7 +675,7 @@ mul_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
return quaternion(t0, t1, t2, t3)
return quaternion(w=t0, x=t1, y=t2, z=t3)
}
mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
@@ -742,7 +687,7 @@ mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
return quaternion(t0, t1, t2, t3)
return quaternion(w=t0, x=t1, y=t2, z=t3)
}
mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
@@ -754,7 +699,7 @@ mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
return quaternion(t0, t1, t2, t3)
return quaternion(w=t0, x=t1, y=t2, z=t3)
}
quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
@@ -768,7 +713,7 @@ quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
return quaternion(t0, t1, t2, t3)
return quaternion(w=t0, x=t1, y=t2, z=t3)
}
quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
@@ -782,7 +727,7 @@ quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
return quaternion(t0, t1, t2, t3)
return quaternion(w=t0, x=t1, y=t2, z=t3)
}
quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
@@ -796,7 +741,7 @@ quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
return quaternion(t0, t1, t2, t3)
return quaternion(w=t0, x=t1, y=t2, z=t3)
}
@(link_name="__truncsfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
@@ -1017,9 +962,11 @@ udivmodti4 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
return udivmod128(a, b, rem)
}
@(link_name="__udivti3", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
udivti3 :: proc "c" (a, b: u128) -> u128 {
return udivmodti4(a, b, nil)
when !IS_WASM {
@(link_name="__udivti3", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
udivti3 :: proc "c" (a, b: u128) -> u128 {
return udivmodti4(a, b, nil)
}
}
@@ -1089,3 +1036,25 @@ fixdfti :: proc(a: u64) -> i128 {
}
}
__write_bits :: proc "contextless" (dst, src: [^]byte, offset: uintptr, size: uintptr) {
for i in 0..<size {
j := offset+i
the_bit := byte((src[i/8]) & (1<<(i&7)) != 0)
b := the_bit<<(j&7)
dst[j/8] &~= b
dst[j/8] |= b
}
}
__read_bits :: proc "contextless" (dst, src: [^]byte, offset: uintptr, size: uintptr) {
for j in 0..<size {
i := offset+j
the_bit := byte((src[i/8]) & (1<<(i&7)) != 0)
b := the_bit<<(j&7)
dst[j/8] &~= b
dst[j/8] |= b
}
}
+7
View File
@@ -0,0 +1,7 @@
package runtime
_OS_Errno :: distinct int
stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
return _stderr_write(data)
}
+22
View File
@@ -0,0 +1,22 @@
//+build freebsd, openbsd
//+private
package runtime
foreign import libc "system:c"
@(default_calling_convention="c")
foreign libc {
@(link_name="write")
_unix_write :: proc(fd: i32, buf: rawptr, size: int) -> int ---
__error :: proc() -> ^i32 ---
}
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
ret := _unix_write(2, raw_data(data), len(data))
if ret < len(data) {
err := __error()
return int(ret), _OS_Errno(err^ if err != nil else 0)
}
return int(ret), 0
}
+15
View File
@@ -0,0 +1,15 @@
//+build darwin
//+private
package runtime
import "base:intrinsics"
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
WRITE :: 0x2000004
STDERR :: 2
ret := intrinsics.syscall(WRITE, STDERR, uintptr(raw_data(data)), uintptr(len(data)))
if ret < 0 {
return 0, _OS_Errno(-ret)
}
return int(ret), 0
}
@@ -1,7 +1,8 @@
//+build freestanding
//+private
package runtime
// TODO(bill): reimplement `os.write`
_os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
return 0, -1
}
+21
View File
@@ -0,0 +1,21 @@
//+build haiku
//+private
package runtime
foreign import libc "system:c"
foreign libc {
@(link_name="write")
_unix_write :: proc(fd: i32, buf: rawptr, size: int) -> int ---
_errnop :: proc() -> ^i32 ---
}
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
ret := _unix_write(2, raw_data(data), len(data))
if ret < len(data) {
err := _errnop()
return int(ret), _OS_Errno(err^ if err != nil else 0)
}
return int(ret), 0
}
@@ -1,9 +1,10 @@
//+build js
//+private
package runtime
foreign import "odin_env"
_os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
foreign odin_env {
write :: proc "contextless" (fd: u32, p: []byte) ---
}
+24
View File
@@ -0,0 +1,24 @@
//+private
package runtime
import "base:intrinsics"
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
when ODIN_ARCH == .amd64 {
SYS_write :: uintptr(1)
} else when ODIN_ARCH == .arm64 {
SYS_write :: uintptr(64)
} else when ODIN_ARCH == .i386 {
SYS_write :: uintptr(4)
} else when ODIN_ARCH == .arm32 {
SYS_write :: uintptr(4)
}
stderr :: 2
ret := int(intrinsics.syscall(SYS_write, uintptr(stderr), uintptr(raw_data(data)), uintptr(len(data))))
if ret < 0 && ret > -4096 {
return 0, _OS_Errno(-ret)
}
return ret, 0
}
@@ -1,9 +1,10 @@
//+build wasi
//+private
package runtime
import "core:sys/wasm/wasi"
_os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
data := (wasi.ciovec_t)(data)
n, err := wasi.fd_write(1, {data})
return int(n), _OS_Errno(err)
+51
View File
@@ -0,0 +1,51 @@
//+build windows
//+private
package runtime
foreign import kernel32 "system:Kernel32.lib"
@(private="file")
@(default_calling_convention="system")
foreign kernel32 {
// NOTE(bill): The types are not using the standard names (e.g. DWORD and LPVOID) to just minimizing the dependency
// stderr_write
GetStdHandle :: proc(which: u32) -> rawptr ---
SetHandleInformation :: proc(hObject: rawptr, dwMask: u32, dwFlags: u32) -> b32 ---
WriteFile :: proc(hFile: rawptr, lpBuffer: rawptr, nNumberOfBytesToWrite: u32, lpNumberOfBytesWritten: ^u32, lpOverlapped: rawptr) -> b32 ---
GetLastError :: proc() -> u32 ---
}
_stderr_write :: proc "contextless" (data: []byte) -> (n: int, err: _OS_Errno) #no_bounds_check {
if len(data) == 0 {
return 0, 0
}
STD_ERROR_HANDLE :: ~u32(0) -12 + 1
HANDLE_FLAG_INHERIT :: 0x00000001
MAX_RW :: 1<<30
h := GetStdHandle(STD_ERROR_HANDLE)
when size_of(uintptr) == 8 {
SetHandleInformation(h, HANDLE_FLAG_INHERIT, 0)
}
single_write_length: u32
total_write: i64
length := i64(len(data))
for total_write < length {
remaining := length - total_write
to_write := u32(min(i32(remaining), MAX_RW))
e := WriteFile(h, &data[total_write], to_write, &single_write_length, nil)
if single_write_length <= 0 || !e {
err = _OS_Errno(GetLastError())
n = int(total_write)
return
}
total_write += i64(single_write_length)
}
n = int(total_write)
return
}
@@ -123,13 +123,13 @@ encode_rune :: proc "contextless" (c: rune) -> ([4]u8, int) {
}
print_string :: proc "contextless" (str: string) -> (n: int) {
n, _ = os_write(transmute([]byte)str)
n, _ = stderr_write(transmute([]byte)str)
return
}
print_strings :: proc "contextless" (args: ..string) -> (n: int) {
for str in args {
m, err := os_write(transmute([]byte)str)
m, err := stderr_write(transmute([]byte)str)
n += m
if err != 0 {
break
@@ -139,7 +139,7 @@ print_strings :: proc "contextless" (args: ..string) -> (n: int) {
}
print_byte :: proc "contextless" (b: byte) -> (n: int) {
n, _ = os_write([]byte{b})
n, _ = stderr_write([]byte{b})
return
}
@@ -178,7 +178,7 @@ print_rune :: proc "contextless" (r: rune) -> int #no_bounds_check {
}
b, n := encode_rune(r)
m, _ := os_write(b[:n])
m, _ := stderr_write(b[:n])
return m
}
@@ -194,7 +194,7 @@ print_u64 :: proc "contextless" (x: u64) #no_bounds_check {
}
i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b]
os_write(a[i:])
stderr_write(a[i:])
}
@@ -216,7 +216,7 @@ print_i64 :: proc "contextless" (x: i64) #no_bounds_check {
i -= 1; a[i] = '-'
}
os_write(a[i:])
stderr_write(a[i:])
}
print_uint :: proc "contextless" (x: uint) { print_u64(u64(x)) }
@@ -459,6 +459,20 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
}
print_byte(']')
case Type_Info_Bit_Field:
print_string("bit_field ")
print_type(info.backing_type)
print_string(" {")
for name, i in info.names {
if i > 0 { print_string(", ") }
print_string(name)
print_string(": ")
print_type(info.types[i])
print_string(" | ")
print_u64(u64(info.bit_sizes[i]))
}
print_byte('}')
case Type_Info_Simd_Vector:
print_string("#simd[")
@@ -4,7 +4,7 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
foreign import lib "system:NtDll.lib"
@(private="file")
@(default_calling_convention="stdcall")
@(default_calling_convention="system")
foreign lib {
RtlMoveMemory :: proc(dst, s: rawptr, length: int) ---
RtlFillMemory :: proc(dst: rawptr, length: int, fill: i32) ---
@@ -37,7 +37,18 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
}
return ptr
}
@(link_name="bzero", linkage="strong", require)
bzero :: proc "c" (ptr: rawptr, len: int) -> rawptr {
if ptr != nil && len != 0 {
p := ([^]byte)(ptr)
for i := 0; i < len; i += 1 {
p[i] = 0
}
}
return ptr
}
@(link_name="memmove", linkage="strong", require)
memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
d, s := ([^]byte)(dst), ([^]byte)(src)
@@ -3,7 +3,7 @@ package runtime
foreign import "system:Foundation.framework"
import "core:intrinsics"
import "base:intrinsics"
objc_id :: ^intrinsics.objc_object
objc_Class :: ^intrinsics.objc_class
@@ -7,19 +7,25 @@ ti_int :: struct #raw_union {
all: i128,
}
@(private="file")
ti_uint :: struct #raw_union {
using s: struct { lo, hi: u64 },
all: u128,
}
@(link_name="__ashlti3", linkage="strong")
__ashlti3 :: proc "contextless" (a: i128, b_: u32) -> i128 {
__ashlti3 :: proc "contextless" (la, ha: u64, b_: u32) -> i128 {
bits_in_dword :: size_of(u32)*8
b := u32(b_)
input, result: ti_int
input.all = a
input.lo, input.hi = la, ha
if b & bits_in_dword != 0 {
result.lo = 0
result.hi = input.lo << (b-bits_in_dword)
} else {
if b == 0 {
return a
return input.all
}
result.lo = input.lo<<b
result.hi = (input.hi<<b) | (input.lo>>(bits_in_dword-b))
@@ -29,12 +35,20 @@ __ashlti3 :: proc "contextless" (a: i128, b_: u32) -> i128 {
@(link_name="__multi3", linkage="strong")
__multi3 :: proc "contextless" (a, b: i128) -> i128 {
__multi3 :: proc "contextless" (la, ha, lb, hb: u64) -> i128 {
x, y, r: ti_int
x.all = a
y.all = b
x.lo, x.hi = la, ha
y.lo, y.hi = lb, hb
r.all = i128(x.lo * y.lo) // TODO this is incorrect
r.hi += x.hi*y.lo + x.lo*y.hi
return r.all
}
}
@(link_name="__udivti3", linkage="strong")
udivti3 :: proc "c" (la, ha, lb, hb: u64) -> u128 {
a, b: ti_uint
a.lo, a.hi = la, ha
b.lo, b.hi = lb, hb
return udivmodti4(a.all, b.all, nil)
}
@@ -1,11 +1,12 @@
//+private
//+no-instrumentation
package runtime
foreign import kernel32 "system:Kernel32.lib"
@(private)
foreign kernel32 {
RaiseException :: proc "stdcall" (dwExceptionCode, dwExceptionFlags, nNumberOfArguments: u32, lpArguments: ^uint) -> ! ---
RaiseException :: proc "system" (dwExceptionCode, dwExceptionFlags, nNumberOfArguments: u32, lpArguments: ^uint) -> ! ---
}
windows_trap_array_bounds :: proc "contextless" () -> ! {
@@ -1,4 +1,5 @@
//+private
//+no-instrumentation
package runtime
@require foreign import "system:int64.lib"
@@ -12,7 +13,7 @@ windows_trap_array_bounds :: proc "contextless" () -> ! {
EXCEPTION_ARRAY_BOUNDS_EXCEEDED :: 0xC000008C
foreign kernel32 {
RaiseException :: proc "stdcall" (dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD, lpArguments: ^ULONG_PTR) -> ! ---
RaiseException :: proc "system" (dwExceptionCode, dwExceptionFlags, nNumberOfArguments: DWORD, lpArguments: ^ULONG_PTR) -> ! ---
}
RaiseException(EXCEPTION_ARRAY_BOUNDS_EXCEEDED, 0, 0, nil)
@@ -1,6 +1,6 @@
package runtime
import "core:intrinsics"
import "base:intrinsics"
udivmod128 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
_ctz :: intrinsics.count_trailing_zeros
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+8 -4
View File
@@ -56,15 +56,14 @@ fi
case "$OS_NAME" in
Darwin)
if [ "$OS_ARCH" == "arm64" ]; then
if [ "$OS_ARCH" = "arm64" ]; then
if [ $LLVM_VERSION_MAJOR -lt 13 ] || [ $LLVM_VERSION_MAJOR -gt 17 ]; then
error "Darwin Arm64 requires LLVM 13, 14 or 17"
fi
fi
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
LDFLAGS="$LDFLAGS -liconv -ldl -framework System"
LDFLAGS="$LDFLAGS -lLLVM-C"
LDFLAGS="$LDFLAGS -liconv -ldl -framework System -lLLVM"
;;
FreeBSD)
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
@@ -83,6 +82,11 @@ OpenBSD)
LDFLAGS="$LDFLAGS -liconv"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
;;
Haiku)
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags) -I/system/develop/headers/private/shared -I/system/develop/headers/private/kernel"
LDFLAGS="$LDFLAGS -liconv"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
;;
*)
error "Platform \"$OS_NAME\" unsupported"
;;
@@ -97,7 +101,7 @@ build_odin() {
EXTRAFLAGS="-O3"
;;
release-native)
if [ "$OS_ARCH" == "arm64" ]; then
if [ "$OS_ARCH" = "arm64" ]; then
# Use preferred flag for Arm (ie arm64 / aarch64 / etc)
EXTRAFLAGS="-O3 -mcpu=native"
else
Regular → Executable
+14 -2
View File
@@ -1,5 +1,7 @@
#!/bin/bash
set -e
bucket=$1
platform=$2
artifact=$3
@@ -9,5 +11,15 @@ filename="odin-$platform-nightly+$now.zip"
echo "Creating archive $filename from $artifact and uploading to $bucket"
7z a -bd "output/$filename" -r "$artifact"
b2 upload-file --noProgress "$bucket" "output/$filename" "nightly/$filename"
# If this is already zipped up (done before artifact upload to keep permissions in tact), just move it.
if [ "${artifact: -4}" == ".zip" ]
then
echo "Artifact already a zip"
mkdir -p "output"
mv "$artifact" "output/$filename"
else
echo "Artifact needs to be zipped"
7z a -bd "output/$filename" -r "$artifact"
fi
b2 upload-file --noProgress "$bucket" "output/$filename" "nightly/$filename"
+1 -1
View File
@@ -4,7 +4,7 @@ import "core:bytes"
import "core:io"
import "core:mem"
import "core:unicode/utf8"
import "core:intrinsics"
import "base:intrinsics"
// Extra errors returns by scanning procedures
Scanner_Extra_Error :: enum i32 {
-1
View File
@@ -226,7 +226,6 @@ writer_to_writer :: proc(b: ^Writer) -> (s: io.Writer) {
@(private)
_writer_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
b := (^Writer)(stream_data)
#partial switch mode {
+1 -1
View File
@@ -895,7 +895,7 @@ split_multi_iterator :: proc(s: ^[]byte, substrs: [][]byte, skip_empty := false)
// scrub scruvs invalid utf-8 characters and replaces them with the replacement string
// Scrubs invalid utf-8 characters and replaces them with the replacement string
// Adjacent invalid bytes are only replaced once
scrub :: proc(s: []byte, replacement: []byte, allocator := context.allocator) -> []byte {
str := s
+11 -1
View File
@@ -1,6 +1,6 @@
package c
import builtin "core:builtin"
import builtin "base:builtin"
char :: builtin.u8 // assuming -funsigned-char
@@ -104,3 +104,13 @@ NULL :: rawptr(uintptr(0))
NDEBUG :: !ODIN_DEBUG
CHAR_BIT :: 8
// Since there are no types in C with an alignment larger than that of
// max_align_t, which cannot be larger than sizeof(long double) as any other
// exposed type wouldn't be valid C, the maximum alignment possible in a
// strictly conformant C implementation is 16 on the platforms we care about.
// The choice of 4096 bytes for storage of this type is more than enough on all
// relevant platforms.
va_list :: struct #align(16) {
_: [4096]u8,
}
+1 -1
View File
@@ -67,7 +67,7 @@ foreign libc {
crealf :: proc(z: complex_float) -> float ---
}
import builtin "core:builtin"
import builtin "base:builtin"
complex_float :: distinct builtin.complex64
complex_double :: distinct builtin.complex128
+18
View File
@@ -80,6 +80,24 @@ when ODIN_OS == .Darwin {
ERANGE :: 34
}
when ODIN_OS == .Haiku {
@(private="file")
@(default_calling_convention="c")
foreign libc {
@(link_name="_errnop")
_get_errno :: proc() -> ^int ---
}
@(private="file")
B_GENERAL_ERROR_BASE :: min(i32)
@(private="file")
B_POSIX_ERROR_BASE :: B_GENERAL_ERROR_BASE + 0x7000
EDOM :: B_POSIX_ERROR_BASE + 16
EILSEQ :: B_POSIX_ERROR_BASE + 38
ERANGE :: B_POSIX_ERROR_BASE + 17
}
// Odin has no way to make an identifier "errno" behave as a function call to
// read the value, or to produce an lvalue such that you can assign a different
// error value to errno. To work around this, just expose it as a function like
+1 -1
View File
@@ -2,7 +2,7 @@ package libc
// 7.12 Mathematics
import "core:intrinsics"
import "base:intrinsics"
when ODIN_OS == .Windows {
foreign import libc "system:libucrt.lib"
+4 -10
View File
@@ -2,7 +2,9 @@ package libc
// 7.16 Variable arguments
import "core:intrinsics"
import "base:intrinsics"
import "core:c"
@(private="file")
@(default_calling_convention="none")
@@ -12,15 +14,7 @@ foreign _ {
@(link_name="llvm.va_copy") _va_copy :: proc(dst, src: ^i8) ---
}
// Since there are no types in C with an alignment larger than that of
// max_align_t, which cannot be larger than sizeof(long double) as any other
// exposed type wouldn't be valid C, the maximum alignment possible in a
// strictly conformant C implementation is 16 on the platforms we care about.
// The choice of 4096 bytes for storage of this type is more than enough on all
// relevant platforms.
va_list :: struct #align(16) {
_: [4096]u8,
}
va_list :: c.va_list
va_start :: #force_inline proc(ap: ^va_list, _: any) {
_va_start(cast(^i8)ap)
+1 -1
View File
@@ -2,7 +2,7 @@ package libc
// 7.17 Atomics
import "core:intrinsics"
import "base:intrinsics"
ATOMIC_BOOL_LOCK_FREE :: true
ATOMIC_CHAR_LOCK_FREE :: true
+131
View File
@@ -1,5 +1,7 @@
package libc
import "core:io"
when ODIN_OS == .Windows {
foreign import libc {
"system:libucrt.lib",
@@ -161,6 +163,36 @@ when ODIN_OS == .Darwin {
}
}
when ODIN_OS == .Haiku {
fpos_t :: distinct i64
_IOFBF :: 0
_IOLBF :: 1
_IONBF :: 2
BUFSIZ :: 8192
EOF :: int(-1)
FOPEN_MAX :: 128
FILENAME_MAX :: 256
L_tmpnam :: 512
SEEK_SET :: 0
SEEK_CUR :: 1
SEEK_END :: 2
TMP_MAX :: 32768
foreign libc {
stderr: ^FILE
stdin: ^FILE
stdout: ^FILE
}
}
@(default_calling_convention="c")
foreign libc {
// 7.21.4 Operations on files
@@ -218,3 +250,102 @@ foreign libc {
ferror :: proc(stream: ^FILE) -> int ---
perror :: proc(s: cstring) ---
}
to_stream :: proc(file: ^FILE) -> io.Stream {
stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
unknown_or_eof :: proc(f: ^FILE) -> io.Error {
switch {
case ferror(f) != 0:
return .Unknown
case feof(f) != 0:
return .EOF
case:
return nil
}
}
file := (^FILE)(stream_data)
switch mode {
case .Close:
if fclose(file) != 0 {
return 0, unknown_or_eof(file)
}
case .Flush:
if fflush(file) != 0 {
return 0, unknown_or_eof(file)
}
case .Read:
n = i64(fread(raw_data(p), size_of(byte), len(p), file))
if n == 0 { err = unknown_or_eof(file) }
case .Read_At:
curr := ftell(file)
if curr == -1 {
return 0, unknown_or_eof(file)
}
if fseek(file, long(offset), SEEK_SET) != 0 {
return 0, unknown_or_eof(file)
}
defer fseek(file, long(curr), SEEK_SET)
n = i64(fread(raw_data(p), size_of(byte), len(p), file))
if n == 0 { err = unknown_or_eof(file) }
case .Write:
n = i64(fwrite(raw_data(p), size_of(byte), len(p), file))
if n == 0 { err = unknown_or_eof(file) }
case .Write_At:
curr := ftell(file)
if curr == -1 {
return 0, unknown_or_eof(file)
}
if fseek(file, long(offset), SEEK_SET) != 0 {
return 0, unknown_or_eof(file)
}
defer fseek(file, long(curr), SEEK_SET)
n = i64(fwrite(raw_data(p), size_of(byte), len(p), file))
if n == 0 { err = unknown_or_eof(file) }
case .Seek:
if fseek(file, long(offset), int(whence)) != 0 {
return 0, unknown_or_eof(file)
}
case .Size:
curr := ftell(file)
if curr == -1 {
return 0, unknown_or_eof(file)
}
defer fseek(file, curr, SEEK_SET)
if fseek(file, 0, SEEK_END) != 0 {
return 0, unknown_or_eof(file)
}
n = i64(ftell(file))
if n == -1 {
return 0, unknown_or_eof(file)
}
case .Destroy:
return 0, .Empty
case .Query:
return io.query_utility({ .Close, .Flush, .Read, .Read_At, .Write, .Write_At, .Seek, .Size })
}
return
}
return {
data = file,
procedure = stream_proc,
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
package libc
import "core:runtime"
import "base:runtime"
// 7.24 String handling
+1 -1
View File
@@ -45,7 +45,7 @@ when ODIN_OS == .Windows {
}
}
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD {
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD || ODIN_OS == .Haiku {
@(default_calling_convention="c")
foreign libc {
// 7.27.2 Time manipulation functions
+5 -1
View File
@@ -29,7 +29,11 @@ when ODIN_OS == .Windows {
} else when ODIN_OS == .FreeBSD {
wctrans_t :: distinct int
wctype_t :: distinct ulong
} else when ODIN_OS == .Haiku {
wctrans_t :: distinct i32
wctype_t :: distinct i32
}
@(default_calling_convention="c")
+33 -43
View File
@@ -12,7 +12,7 @@ package compress
import "core:io"
import "core:bytes"
import "core:runtime"
import "base:runtime"
/*
These settings bound how much compression algorithms will allocate for their output buffer.
@@ -20,10 +20,9 @@ import "core:runtime"
*/
/*
When a decompression routine doesn't stream its output, but writes to a buffer,
we pre-allocate an output buffer to speed up decompression. The default is 1 MiB.
*/
// When a decompression routine doesn't stream its output, but writes to a buffer,
// we pre-allocate an output buffer to speed up decompression. The default is 1 MiB.
COMPRESS_OUTPUT_ALLOCATE_MIN :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MIN, 1 << 20))
/*
@@ -34,16 +33,14 @@ COMPRESS_OUTPUT_ALLOCATE_MIN :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MIN, 1 << 2
*/
when size_of(uintptr) == 8 {
/*
For 64-bit platforms, we set the default max buffer size to 4 GiB,
which is GZIP and PKZIP's max payload size.
*/
// For 64-bit platforms, we set the default max buffer size to 4 GiB,
// which is GZIP and PKZIP's max payload size.
COMPRESS_OUTPUT_ALLOCATE_MAX :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MAX, 1 << 32))
} else {
/*
For 32-bit platforms, we set the default max buffer size to 512 MiB.
*/
COMPRESS_OUTPUT_ALLOCATE_MAX :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MAX, 1 << 29))
// For 32-bit platforms, we set the default max buffer size to 512 MiB.
COMPRESS_OUTPUT_ALLOCATE_MAX :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MAX, 1 << 29))
}
@@ -69,9 +66,8 @@ General_Error :: enum {
Incompatible_Options,
Unimplemented,
/*
Memory errors
*/
// Memory errors
Allocation_Failed,
Resize_Failed,
}
@@ -86,17 +82,16 @@ GZIP_Error :: enum {
Payload_Length_Invalid,
Payload_CRC_Invalid,
/*
GZIP's payload can be a maximum of max(u32le), or 4 GiB.
If you tell it you expect it to contain more, that's obviously an error.
*/
Payload_Size_Exceeds_Max_Payload,
/*
For buffered instead of streamed output, the payload size can't exceed
the max set by the `COMPRESS_OUTPUT_ALLOCATE_MAX` switch in compress/common.odin.
// GZIP's payload can be a maximum of max(u32le), or 4 GiB.
// If you tell it you expect it to contain more, that's obviously an error.
Payload_Size_Exceeds_Max_Payload,
// For buffered instead of streamed output, the payload size can't exceed
// the max set by the `COMPRESS_OUTPUT_ALLOCATE_MAX` switch in compress/common.odin.
//
// You can tweak this setting using `-define:COMPRESS_OUTPUT_ALLOCATE_MAX=size_in_bytes`
You can tweak this setting using `-define:COMPRESS_OUTPUT_ALLOCATE_MAX=size_in_bytes`
*/
Output_Exceeds_COMPRESS_OUTPUT_ALLOCATE_MAX,
}
@@ -137,9 +132,8 @@ Context_Memory_Input :: struct #packed {
code_buffer: u64,
num_bits: u64,
/*
If we know the data size, we can optimize the reads and writes.
*/
// If we know the data size, we can optimize the reads and writes.
size_packed: i64,
size_unpacked: i64,
}
@@ -159,18 +153,16 @@ Context_Stream_Input :: struct #packed {
code_buffer: u64,
num_bits: u64,
/*
If we know the data size, we can optimize the reads and writes.
*/
// If we know the data size, we can optimize the reads and writes.
size_packed: i64,
size_unpacked: i64,
/*
Flags:
`input_fully_in_memory`
true = This tells us we read input from `input_data` exclusively. [] = EOF.
false = Try to refill `input_data` from the `input` stream.
*/
// Flags:
// `input_fully_in_memory`
// true = This tells us we read input from `input_data` exclusively. [] = EOF.
// false = Try to refill `input_data` from the `input` stream.
input_fully_in_memory: b8,
padding: [1]u8,
@@ -214,7 +206,7 @@ read_slice_from_memory :: #force_inline proc(z: ^Context_Memory_Input, size: int
@(optimization_mode="speed")
read_slice_from_stream :: #force_inline proc(z: ^Context_Stream_Input, size: int) -> (res: []u8, err: io.Error) {
// TODO: REMOVE ALL USE OF context.temp_allocator here
// the is literally no need for it
// there is literally no need for it
b := make([]u8, size, context.temp_allocator)
_ = io.read(z.input, b[:]) or_return
return b, nil
@@ -248,10 +240,8 @@ read_u8_from_stream :: #force_inline proc(z: ^Context_Stream_Input) -> (res: u8,
read_u8 :: proc{read_u8_from_memory, read_u8_from_stream}
/*
You would typically only use this at the end of Inflate, to drain bits from the code buffer
preferentially.
*/
// You would typically only use this at the end of Inflate, to drain bits from the code buffer
// preferentially.
@(optimization_mode="speed")
read_u8_prefer_code_buffer_lsb :: #force_inline proc(z: ^$C) -> (res: u8, err: io.Error) {
if z.num_bits >= 8 {
+1 -1
View File
@@ -11,7 +11,7 @@
// package shoco is an implementation of the shoco short string compressor
package shoco
import "core:intrinsics"
import "base:intrinsics"
import "core:compress"
Shoco_Pack :: struct {
+678
View File
@@ -0,0 +1,678 @@
/*
package avl implements an AVL tree.
The implementation is non-intrusive, and non-recursive.
*/
package container_avl
import "base:intrinsics"
import "base:runtime"
import "core:slice"
_ :: intrinsics
_ :: runtime
// Originally based on the CC0 implementation by Eric Biggers
// See: https://github.com/ebiggers/avl_tree/
// Direction specifies the traversal direction for a tree iterator.
Direction :: enum i8 {
// Backward is the in-order backwards direction.
Backward = -1,
// Forward is the in-order forwards direction.
Forward = 1,
}
// Ordering specifies order when inserting/finding values into the tree.
Ordering :: slice.Ordering
// Tree is an AVL tree.
Tree :: struct($Value: typeid) {
// user_data is a parameter that will be passed to the on_remove
// callback.
user_data: rawptr,
// on_remove is an optional callback that can be called immediately
// after a node is removed from the tree.
on_remove: proc(value: Value, user_data: rawptr),
_root: ^Node(Value),
_node_allocator: runtime.Allocator,
_cmp_fn: proc(a, b: Value) -> Ordering,
_size: int,
}
// Node is an AVL tree node.
//
// WARNING: It is unsafe to mutate value if the node is part of a tree
// if doing so will alter the Node's sort position relative to other
// elements in the tree.
Node :: struct($Value: typeid) {
value: Value,
_parent: ^Node(Value),
_left: ^Node(Value),
_right: ^Node(Value),
_balance: i8,
}
// Iterator is a tree iterator.
//
// WARNING: It is unsafe to modify the tree while iterating, except via
// the iterator_remove method.
Iterator :: struct($Value: typeid) {
_tree: ^Tree(Value),
_cur: ^Node(Value),
_next: ^Node(Value),
_direction: Direction,
_called_next: bool,
}
// init initializes a tree.
init :: proc {
init_ordered,
init_cmp,
}
// init_cmp initializes a tree.
init_cmp :: proc(
t: ^$T/Tree($Value),
cmp_fn: proc(a, b: Value) -> Ordering,
node_allocator := context.allocator,
) {
t._root = nil
t._node_allocator = node_allocator
t._cmp_fn = cmp_fn
t._size = 0
}
// init_ordered initializes a tree containing ordered items, with
// a comparison function that results in an ascending order sort.
init_ordered :: proc(
t: ^$T/Tree($Value),
node_allocator := context.allocator,
) where intrinsics.type_is_ordered_numeric(Value) {
init_cmp(t, slice.cmp_proc(Value), node_allocator)
}
// destroy de-initializes a tree.
destroy :: proc(t: ^$T/Tree($Value), call_on_remove: bool = true) {
iter := iterator(t, Direction.Forward)
for _ in iterator_next(&iter) {
iterator_remove(&iter, call_on_remove)
}
}
// len returns the number of elements in the tree.
len :: proc "contextless" (t: ^$T/Tree($Value)) -> int {
return t._size
}
// first returns the first node in the tree (in-order) or nil iff
// the tree is empty.
first :: proc "contextless" (t: ^$T/Tree($Value)) -> ^Node(Value) {
return tree_first_or_last_in_order(t, Direction.Backward)
}
// last returns the last element in the tree (in-order) or nil iff
// the tree is empty.
last :: proc "contextless" (t: ^$T/Tree($Value)) -> ^Node(Value) {
return tree_first_or_last_in_order(t, Direction.Forward)
}
// find finds the value in the tree, and returns the corresponding
// node or nil iff the value is not present.
find :: proc(t: ^$T/Tree($Value), value: Value) -> ^Node(Value) {
cur := t._root
descend_loop: for cur != nil {
switch t._cmp_fn(value, cur.value) {
case .Less:
cur = cur._left
case .Greater:
cur = cur._right
case .Equal:
break descend_loop
}
}
return cur
}
// find_or_insert attempts to insert the value into the tree, and returns
// the node, a boolean indicating if the value was inserted, and the
// node allocator error if relevant. If the value is already
// present, the existing node is returned un-altered.
find_or_insert :: proc(
t: ^$T/Tree($Value),
value: Value,
) -> (
n: ^Node(Value),
inserted: bool,
err: runtime.Allocator_Error,
) {
n_ptr := &t._root
for n_ptr^ != nil {
n = n_ptr^
switch t._cmp_fn(value, n.value) {
case .Less:
n_ptr = &n._left
case .Greater:
n_ptr = &n._right
case .Equal:
return
}
}
parent := n
n = new(Node(Value), t._node_allocator) or_return
n.value = value
n._parent = parent
n_ptr^ = n
tree_rebalance_after_insert(t, n)
t._size += 1
inserted = true
return
}
// remove removes a node or value from the tree, and returns true iff the
// removal was successful. While the node's value will be left intact,
// the node itself will be freed via the tree's node allocator.
remove :: proc {
remove_value,
remove_node,
}
// remove_value removes a value from the tree, and returns true iff the
// removal was successful. While the node's value will be left intact,
// the node itself will be freed via the tree's node allocator.
remove_value :: proc(t: ^$T/Tree($Value), value: Value, call_on_remove: bool = true) -> bool {
n := find(t, value)
if n == nil {
return false
}
return remove_node(t, n, call_on_remove)
}
// remove_node removes a node from the tree, and returns true iff the
// removal was successful. While the node's value will be left intact,
// the node itself will be freed via the tree's node allocator.
remove_node :: proc(t: ^$T/Tree($Value), node: ^Node(Value), call_on_remove: bool = true) -> bool {
if node._parent == node || (node._parent == nil && t._root != node) {
return false
}
defer {
if call_on_remove && t.on_remove != nil {
t.on_remove(node.value, t.user_data)
}
free(node, t._node_allocator)
}
parent: ^Node(Value)
left_deleted: bool
t._size -= 1
if node._left != nil && node._right != nil {
parent, left_deleted = tree_swap_with_successor(t, node)
} else {
child := node._left
if child == nil {
child = node._right
}
parent = node._parent
if parent != nil {
if node == parent._left {
parent._left = child
left_deleted = true
} else {
parent._right = child
left_deleted = false
}
if child != nil {
child._parent = parent
}
} else {
if child != nil {
child._parent = parent
}
t._root = child
node_reset(node)
return true
}
}
for {
if left_deleted {
parent = tree_handle_subtree_shrink(t, parent, +1, &left_deleted)
} else {
parent = tree_handle_subtree_shrink(t, parent, -1, &left_deleted)
}
if parent == nil {
break
}
}
node_reset(node)
return true
}
// iterator returns a tree iterator in the specified direction.
iterator :: proc "contextless" (t: ^$T/Tree($Value), direction: Direction) -> Iterator(Value) {
it: Iterator(Value)
it._tree = transmute(^Tree(Value))t
it._direction = direction
iterator_first(&it)
return it
}
// iterator_from_pos returns a tree iterator in the specified direction,
// spanning the range [pos, last] (inclusive).
iterator_from_pos :: proc "contextless" (
t: ^$T/Tree($Value),
pos: ^Node(Value),
direction: Direction,
) -> Iterator(Value) {
it: Iterator(Value)
it._tree = transmute(^Tree(Value))t
it._direction = direction
it._next = nil
it._called_next = false
if it._cur = pos; pos != nil {
it._next = node_next_or_prev_in_order(it._cur, it._direction)
}
return it
}
// iterator_get returns the node currently pointed to by the iterator,
// or nil iff the node has been removed, the tree is empty, or the end
// of the tree has been reached.
iterator_get :: proc "contextless" (it: ^$I/Iterator($Value)) -> ^Node(Value) {
return it._cur
}
// iterator_remove removes the node currently pointed to by the iterator,
// and returns true iff the removal was successful. Semantics are the
// same as the Tree remove.
iterator_remove :: proc(it: ^$I/Iterator($Value), call_on_remove: bool = true) -> bool {
if it._cur == nil {
return false
}
ok := remove_node(it._tree, it._cur, call_on_remove)
if ok {
it._cur = nil
}
return ok
}
// iterator_next advances the iterator and returns the (node, true) or
// or (nil, false) iff the end of the tree has been reached.
//
// Note: The first call to iterator_next will return the first node instead
// of advancing the iterator.
iterator_next :: proc "contextless" (it: ^$I/Iterator($Value)) -> (^Node(Value), bool) {
// This check is needed so that the first element gets returned from
// a brand-new iterator, and so that the somewhat contrived case where
// iterator_remove is called before the first call to iterator_next
// returns the correct value.
if !it._called_next {
it._called_next = true
// There can be the contrived case where iterator_remove is
// called before ever calling iterator_next, which needs to be
// handled as an actual call to next.
//
// If this happens it._cur will be nil, so only return the
// first value, if it._cur is valid.
if it._cur != nil {
return it._cur, true
}
}
if it._next == nil {
return nil, false
}
it._cur = it._next
it._next = node_next_or_prev_in_order(it._cur, it._direction)
return it._cur, true
}
@(private)
tree_first_or_last_in_order :: proc "contextless" (
t: ^$T/Tree($Value),
direction: Direction,
) -> ^Node(Value) {
first, sign := t._root, i8(direction)
if first != nil {
for {
tmp := node_get_child(first, +sign)
if tmp == nil {
break
}
first = tmp
}
}
return first
}
@(private)
tree_replace_child :: proc "contextless" (
t: ^$T/Tree($Value),
parent, old_child, new_child: ^Node(Value),
) {
if parent != nil {
if old_child == parent._left {
parent._left = new_child
} else {
parent._right = new_child
}
} else {
t._root = new_child
}
}
@(private)
tree_rotate :: proc "contextless" (t: ^$T/Tree($Value), a: ^Node(Value), sign: i8) {
b := node_get_child(a, -sign)
e := node_get_child(b, +sign)
p := a._parent
node_set_child(a, -sign, e)
a._parent = b
node_set_child(b, +sign, a)
b._parent = p
if e != nil {
e._parent = a
}
tree_replace_child(t, p, a, b)
}
@(private)
tree_double_rotate :: proc "contextless" (
t: ^$T/Tree($Value),
b, a: ^Node(Value),
sign: i8,
) -> ^Node(Value) {
e := node_get_child(b, +sign)
f := node_get_child(e, -sign)
g := node_get_child(e, +sign)
p := a._parent
e_bal := e._balance
node_set_child(a, -sign, g)
a_bal := -e_bal
if sign * e_bal >= 0 {
a_bal = 0
}
node_set_parent_balance(a, e, a_bal)
node_set_child(b, +sign, f)
b_bal := -e_bal
if sign * e_bal <= 0 {
b_bal = 0
}
node_set_parent_balance(b, e, b_bal)
node_set_child(e, +sign, a)
node_set_child(e, -sign, b)
node_set_parent_balance(e, p, 0)
if g != nil {
g._parent = a
}
if f != nil {
f._parent = b
}
tree_replace_child(t, p, a, e)
return e
}
@(private)
tree_handle_subtree_growth :: proc "contextless" (
t: ^$T/Tree($Value),
node, parent: ^Node(Value),
sign: i8,
) -> bool {
old_balance_factor := parent._balance
if old_balance_factor == 0 {
node_adjust_balance_factor(parent, sign)
return false
}
new_balance_factor := old_balance_factor + sign
if new_balance_factor == 0 {
node_adjust_balance_factor(parent, sign)
return true
}
if sign * node._balance > 0 {
tree_rotate(t, parent, -sign)
node_adjust_balance_factor(parent, -sign)
node_adjust_balance_factor(node, -sign)
} else {
tree_double_rotate(t, node, parent, -sign)
}
return true
}
@(private)
tree_rebalance_after_insert :: proc "contextless" (t: ^$T/Tree($Value), inserted: ^Node(Value)) {
node, parent := inserted, inserted._parent
switch {
case parent == nil:
return
case node == parent._left:
node_adjust_balance_factor(parent, -1)
case:
node_adjust_balance_factor(parent, +1)
}
if parent._balance == 0 {
return
}
for done := false; !done; {
node = parent
if parent = node._parent; parent == nil {
return
}
if node == parent._left {
done = tree_handle_subtree_growth(t, node, parent, -1)
} else {
done = tree_handle_subtree_growth(t, node, parent, +1)
}
}
}
@(private)
tree_swap_with_successor :: proc "contextless" (
t: ^$T/Tree($Value),
x: ^Node(Value),
) -> (
^Node(Value),
bool,
) {
ret: ^Node(Value)
left_deleted: bool
y := x._right
if y._left == nil {
ret = y
} else {
q: ^Node(Value)
for {
q = y
if y = y._left; y._left == nil {
break
}
}
if q._left = y._right; q._left != nil {
q._left._parent = q
}
y._right = x._right
x._right._parent = y
ret = q
left_deleted = true
}
y._left = x._left
x._left._parent = y
y._parent = x._parent
y._balance = x._balance
tree_replace_child(t, x._parent, x, y)
return ret, left_deleted
}
@(private)
tree_handle_subtree_shrink :: proc "contextless" (
t: ^$T/Tree($Value),
parent: ^Node(Value),
sign: i8,
left_deleted: ^bool,
) -> ^Node(Value) {
old_balance_factor := parent._balance
if old_balance_factor == 0 {
node_adjust_balance_factor(parent, sign)
return nil
}
node: ^Node(Value)
new_balance_factor := old_balance_factor + sign
if new_balance_factor == 0 {
node_adjust_balance_factor(parent, sign)
node = parent
} else {
node = node_get_child(parent, sign)
if sign * node._balance >= 0 {
tree_rotate(t, parent, -sign)
if node._balance == 0 {
node_adjust_balance_factor(node, -sign)
return nil
}
node_adjust_balance_factor(parent, -sign)
node_adjust_balance_factor(node, -sign)
} else {
node = tree_double_rotate(t, node, parent, -sign)
}
}
parent := parent
if parent = node._parent; parent != nil {
left_deleted^ = node == parent._left
}
return parent
}
@(private)
node_reset :: proc "contextless" (n: ^Node($Value)) {
// Mostly pointless as n will be deleted after this is called, but
// attempt to be able to catch cases of n not being in the tree.
n._parent = n
n._left = nil
n._right = nil
n._balance = 0
}
@(private)
node_set_parent_balance :: #force_inline proc "contextless" (
n, parent: ^Node($Value),
balance: i8,
) {
n._parent = parent
n._balance = balance
}
@(private)
node_get_child :: #force_inline proc "contextless" (n: ^Node($Value), sign: i8) -> ^Node(Value) {
if sign < 0 {
return n._left
}
return n._right
}
@(private)
node_next_or_prev_in_order :: proc "contextless" (
n: ^Node($Value),
direction: Direction,
) -> ^Node(Value) {
next, tmp: ^Node(Value)
sign := i8(direction)
if next = node_get_child(n, +sign); next != nil {
for {
tmp = node_get_child(next, -sign)
if tmp == nil {
break
}
next = tmp
}
} else {
tmp, next = n, n._parent
for next != nil && tmp == node_get_child(next, +sign) {
tmp, next = next, next._parent
}
}
return next
}
@(private)
node_set_child :: #force_inline proc "contextless" (
n: ^Node($Value),
sign: i8,
child: ^Node(Value),
) {
if sign < 0 {
n._left = child
} else {
n._right = child
}
}
@(private)
node_adjust_balance_factor :: #force_inline proc "contextless" (n: ^Node($Value), amount: i8) {
n._balance += amount
}
@(private)
iterator_first :: proc "contextless" (it: ^Iterator($Value)) {
// This is private because behavior when the user manually calls
// iterator_first followed by iterator_next is unintuitive, since
// the first call to iterator_next MUST return the first node
// instead of advancing so that `for node in iterator_next(&next)`
// works as expected.
switch it._direction {
case .Forward:
it._cur = tree_first_or_last_in_order(it._tree, .Backward)
case .Backward:
it._cur = tree_first_or_last_in_order(it._tree, .Forward)
}
it._next = nil
it._called_next = false
if it._cur != nil {
it._next = node_next_or_prev_in_order(it._cur, it._direction)
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
package dynamic_bit_array
import "core:intrinsics"
import "base:intrinsics"
import "core:mem"
/*
@@ -1,6 +1,6 @@
package container_intrusive_list
import "core:intrinsics"
import "base:intrinsics"
// An intrusive doubly-linked list
//
+2 -2
View File
@@ -1,7 +1,7 @@
package container_lru
import "core:runtime"
import "core:intrinsics"
import "base:runtime"
import "base:intrinsics"
_ :: runtime
_ :: intrinsics
@@ -1,6 +1,6 @@
package container_priority_queue
import "core:builtin"
import "base:builtin"
Priority_Queue :: struct($T: typeid) {
queue: [dynamic]T,
@@ -140,3 +140,18 @@ remove :: proc(pq: ^$Q/Priority_Queue($T), i: int) -> (value: T, ok: bool) {
return
}
peek_safe :: proc(pq: $Q/Priority_Queue($T), loc := #caller_location) -> (res: T, ok: bool) {
if builtin.len(pq.queue) > 0 {
return pq.queue[0], true
}
return
}
peek :: proc(pq: $Q/Priority_Queue($T), loc := #caller_location) -> (res: T) {
assert(condition=builtin.len(pq.queue)>0, loc=loc)
if builtin.len(pq.queue) > 0 {
return pq.queue[0]
}
return
}
+2 -2
View File
@@ -1,7 +1,7 @@
package container_queue
import "core:builtin"
import "core:runtime"
import "base:builtin"
import "base:runtime"
_ :: runtime
// Dynamically resizable double-ended queue/ring-buffer
+2 -2
View File
@@ -1,7 +1,7 @@
package container_small_array
import "core:builtin"
import "core:runtime"
import "base:builtin"
import "base:runtime"
_ :: runtime
Small_Array :: struct($N: int, $T: typeid) where N >= 0 {
@@ -3,8 +3,8 @@
// map type is being used to accelerate lookups.
package container_topological_sort
import "core:intrinsics"
import "core:runtime"
import "base:intrinsics"
import "base:runtime"
_ :: intrinsics
_ :: runtime
+8 -70
View File
@@ -1,84 +1,22 @@
# crypto
A cryptography library for the Odin language
A cryptography library for the Odin language.
## Supported
This library offers various algorithms implemented in Odin.
Please see the chart below for some of the options.
## Hashing algorithms
| Algorithm | |
|:-------------------------------------------------------------------------------------------------------------|:-----------------|
| [BLAKE2B](https://datatracker.ietf.org/doc/html/rfc7693) | &#10004;&#65039; |
| [BLAKE2S](https://datatracker.ietf.org/doc/html/rfc7693) | &#10004;&#65039; |
| [SHA-2](https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf) | &#10004;&#65039; |
| [SHA-3](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | &#10004;&#65039; |
| [SHAKE](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | &#10004;&#65039; |
| [SM3](https://datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02) | &#10004;&#65039; |
| legacy/[Keccak](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) | &#10004;&#65039; |
| legacy/[MD5](https://datatracker.ietf.org/doc/html/rfc1321) | &#10004;&#65039; |
| legacy/[SHA-1](https://datatracker.ietf.org/doc/html/rfc3174) | &#10004;&#65039; |
#### High level API
Each hash algorithm contains a procedure group named `hash`, or if the algorithm provides more than one digest size `hash_<size>`\*.
Included in these groups are six procedures.
- `hash_string` - Hash a given string and return the computed hash. Just calls `hash_bytes` internally
- `hash_bytes` - Hash a given byte slice and return the computed hash
- `hash_string_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. Just calls `hash_bytes_to_buffer` internally
- `hash_bytes_to_buffer` - Hash a given string and put the computed hash in the second proc parameter. The destination buffer has to be at least as big as the digest size of the hash
- `hash_stream` - Takes a stream from io.Stream and returns the computed hash from it
- `hash_file` - Takes a file handle and returns the computed hash from it. A second optional boolean parameter controls if the file is streamed (this is the default) or read at once (set to true)
\* On some algorithms there is another part to the name, since they might offer control about additional parameters.
For instance, `SHA-2` offers different sizes.
Computing a 512-bit hash is therefore achieved by calling `sha2.hash_512(...)`.
#### Low level API
The above mentioned procedures internally call three procedures: `init`, `update` and `final`.
You may also directly call them, if you wish.
#### Example
```odin
package crypto_example
// Import the desired package
import "core:crypto/blake2b"
main :: proc() {
input := "foo"
// Compute the hash, using the high level API
computed_hash := blake2b.hash(input)
// Variant that takes a destination buffer, instead of returning the computed hash
hash := make([]byte, sha2.DIGEST_SIZE) // @note: Destination buffer has to be at least as big as the digest size of the hash
blake2b.hash(input, hash[:])
// Compute the hash, using the low level API
ctx: blake2b.Context
computed_hash_low: [blake2b.DIGEST_SIZE]byte
blake2b.init(&ctx)
blake2b.update(&ctx, transmute([]byte)input)
blake2b.final(&ctx, computed_hash_low[:])
}
```
For example uses of all available algorithms, please see the tests within `tests/core/crypto`.
This package offers various algorithms implemented in Odin, along with
useful helpers such as access to the system entropy source, and a
constant-time byte comparison.
## Implementation considerations
- The crypto packages are not thread-safe.
- Best-effort is make to mitigate timing side-channels on reasonable
architectures. Architectures that are known to be unreasonable include
architectures. Architectures that are known to be unreasonable include
but are not limited to i386, i486, and WebAssembly.
- Some but not all of the packages attempt to santize sensitive data,
however this is not done consistently through the library at the moment.
As Thomas Pornin puts it "In general, such memory cleansing is a fool's
quest."
- The packages attempt to santize sensitive data, however this is, and
will remain a "best-effort" implementation decision. As Thomas Pornin
puts it "In general, such memory cleansing is a fool's quest."
- All of these packages have not received independent third party review.
## License
+58 -39
View File
@@ -11,6 +11,7 @@ package _blake2
*/
import "core:encoding/endian"
import "core:mem"
BLAKE2S_BLOCK_SIZE :: 64
BLAKE2S_SIZE :: 32
@@ -28,7 +29,6 @@ Blake2s_Context :: struct {
is_keyed: bool,
size: byte,
is_last_node: bool,
cfg: Blake2_Config,
is_initialized: bool,
}
@@ -44,7 +44,6 @@ Blake2b_Context :: struct {
is_keyed: bool,
size: byte,
is_last_node: bool,
cfg: Blake2_Config,
is_initialized: bool,
}
@@ -83,62 +82,61 @@ BLAKE2B_IV := [8]u64 {
0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
}
init :: proc(ctx: ^$T) {
init :: proc(ctx: ^$T, cfg: ^Blake2_Config) {
when T == Blake2s_Context {
block_size :: BLAKE2S_BLOCK_SIZE
max_size :: BLAKE2S_SIZE
} else when T == Blake2b_Context {
block_size :: BLAKE2B_BLOCK_SIZE
max_size :: BLAKE2B_SIZE
}
if ctx.cfg.size > max_size {
if cfg.size > max_size {
panic("blake2: requested output size exceeeds algorithm max")
}
p := make([]byte, block_size)
defer delete(p)
// To save having to allocate a scratch buffer, use the internal
// data buffer (`ctx.x`), as it is exactly the correct size.
p := ctx.x[:]
p[0] = ctx.cfg.size
p[1] = byte(len(ctx.cfg.key))
p[0] = cfg.size
p[1] = byte(len(cfg.key))
if ctx.cfg.salt != nil {
if cfg.salt != nil {
when T == Blake2s_Context {
copy(p[16:], ctx.cfg.salt)
copy(p[16:], cfg.salt)
} else when T == Blake2b_Context {
copy(p[32:], ctx.cfg.salt)
copy(p[32:], cfg.salt)
}
}
if ctx.cfg.person != nil {
if cfg.person != nil {
when T == Blake2s_Context {
copy(p[24:], ctx.cfg.person)
copy(p[24:], cfg.person)
} else when T == Blake2b_Context {
copy(p[48:], ctx.cfg.person)
copy(p[48:], cfg.person)
}
}
if ctx.cfg.tree != nil {
p[2] = ctx.cfg.tree.(Blake2_Tree).fanout
p[3] = ctx.cfg.tree.(Blake2_Tree).max_depth
endian.unchecked_put_u32le(p[4:], ctx.cfg.tree.(Blake2_Tree).leaf_size)
if cfg.tree != nil {
p[2] = cfg.tree.(Blake2_Tree).fanout
p[3] = cfg.tree.(Blake2_Tree).max_depth
endian.unchecked_put_u32le(p[4:], cfg.tree.(Blake2_Tree).leaf_size)
when T == Blake2s_Context {
p[8] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset)
p[9] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 8)
p[10] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 16)
p[11] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 24)
p[12] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 32)
p[13] = byte(ctx.cfg.tree.(Blake2_Tree).node_offset >> 40)
p[14] = ctx.cfg.tree.(Blake2_Tree).node_depth
p[15] = ctx.cfg.tree.(Blake2_Tree).inner_hash_size
p[8] = byte(cfg.tree.(Blake2_Tree).node_offset)
p[9] = byte(cfg.tree.(Blake2_Tree).node_offset >> 8)
p[10] = byte(cfg.tree.(Blake2_Tree).node_offset >> 16)
p[11] = byte(cfg.tree.(Blake2_Tree).node_offset >> 24)
p[12] = byte(cfg.tree.(Blake2_Tree).node_offset >> 32)
p[13] = byte(cfg.tree.(Blake2_Tree).node_offset >> 40)
p[14] = cfg.tree.(Blake2_Tree).node_depth
p[15] = cfg.tree.(Blake2_Tree).inner_hash_size
} else when T == Blake2b_Context {
endian.unchecked_put_u64le(p[8:], ctx.cfg.tree.(Blake2_Tree).node_offset)
p[16] = ctx.cfg.tree.(Blake2_Tree).node_depth
p[17] = ctx.cfg.tree.(Blake2_Tree).inner_hash_size
endian.unchecked_put_u64le(p[8:], cfg.tree.(Blake2_Tree).node_offset)
p[16] = cfg.tree.(Blake2_Tree).node_depth
p[17] = cfg.tree.(Blake2_Tree).inner_hash_size
}
} else {
p[2], p[3] = 1, 1
}
ctx.size = ctx.cfg.size
ctx.size = cfg.size
for i := 0; i < 8; i += 1 {
when T == Blake2s_Context {
ctx.h[i] = BLAKE2S_IV[i] ~ endian.unchecked_get_u32le(p[i * 4:])
@@ -147,11 +145,14 @@ init :: proc(ctx: ^$T) {
ctx.h[i] = BLAKE2B_IV[i] ~ endian.unchecked_get_u64le(p[i * 8:])
}
}
if ctx.cfg.tree != nil && ctx.cfg.tree.(Blake2_Tree).is_last_node {
mem.zero(&ctx.x, size_of(ctx.x)) // Done with the scratch space, no barrier.
if cfg.tree != nil && cfg.tree.(Blake2_Tree).is_last_node {
ctx.is_last_node = true
}
if len(ctx.cfg.key) > 0 {
copy(ctx.padded_key[:], ctx.cfg.key)
if len(cfg.key) > 0 {
copy(ctx.padded_key[:], cfg.key)
update(ctx, ctx.padded_key[:])
ctx.is_keyed = true
}
@@ -194,22 +195,40 @@ update :: proc(ctx: ^$T, p: []byte) {
ctx.nx += copy(ctx.x[ctx.nx:], p)
}
final :: proc(ctx: ^$T, hash: []byte) {
final :: proc(ctx: ^$T, hash: []byte, finalize_clone: bool = false) {
assert(ctx.is_initialized)
ctx := ctx
if finalize_clone {
tmp_ctx: T
clone(&tmp_ctx, ctx)
ctx = &tmp_ctx
}
defer(reset(ctx))
when T == Blake2s_Context {
if len(hash) < int(ctx.cfg.size) {
if len(hash) < int(ctx.size) {
panic("crypto/blake2s: invalid destination digest size")
}
blake2s_final(ctx, hash)
} else when T == Blake2b_Context {
if len(hash) < int(ctx.cfg.size) {
if len(hash) < int(ctx.size) {
panic("crypto/blake2b: invalid destination digest size")
}
blake2b_final(ctx, hash)
}
}
ctx.is_initialized = false
clone :: proc(ctx, other: ^$T) {
ctx^ = other^
}
reset :: proc(ctx: ^$T) {
if !ctx.is_initialized {
return
}
mem.zero_explicit(ctx, size_of(ctx^))
}
@(private)
+109 -78
View File
@@ -7,50 +7,69 @@ package _sha3
List of contributors:
zhibog, dotbmp: Initial implementation.
Implementation of the Keccak hashing algorithm, standardized as SHA3 in <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf>
To use the original Keccak padding, set the is_keccak bool to true, otherwise it will use SHA3 padding.
Implementation of the Keccak hashing algorithm, standardized as SHA3
in <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf>.
As the only difference between the legacy Keccak and SHA3 is the domain
separation byte, set dsbyte to the appropriate value to pick the desired
algorithm.
*/
import "core:math/bits"
import "core:mem"
ROUNDS :: 24
Sha3_Context :: struct {
st: struct #raw_union {
RATE_128 :: 1344 / 8 // ONLY for SHAKE128.
RATE_224 :: 1152 / 8
RATE_256 :: 1088 / 8
RATE_384 :: 832 / 8
RATE_512 :: 576 / 8
DS_KECCAK :: 0x01
DS_SHA3 :: 0x06
DS_SHAKE :: 0x1f
DS_CSHAKE :: 0x04
Context :: struct {
st: struct #raw_union {
b: [200]u8,
q: [25]u64,
},
pt: int,
rsiz: int,
mdlen: int,
is_keccak: bool,
pt: int,
rsiz: int,
mdlen: int,
dsbyte: byte,
is_initialized: bool,
is_finalized: bool, // For SHAKE (unlimited squeeze is allowed)
}
@(private)
keccakf_rndc := [?]u64 {
0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
}
@(private)
keccakf_rotc := [?]int {
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
}
@(private)
keccakf_piln := [?]i32 {
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
}
@(private)
keccakf :: proc "contextless" (st: ^[25]u64) {
keccakf_rndc := [?]u64 {
0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
0x8000000000008080, 0x0000000080000001, 0x8000000080008008,
}
keccakf_rotc := [?]int {
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
}
keccakf_piln := [?]i32 {
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
}
i, j, r: i32 = ---, ---, ---
t: u64 = ---
bc: [5]u64 = ---
@@ -103,81 +122,93 @@ keccakf :: proc "contextless" (st: ^[25]u64) {
}
}
init :: proc(c: ^Sha3_Context) {
init :: proc(ctx: ^Context) {
for i := 0; i < 25; i += 1 {
c.st.q[i] = 0
ctx.st.q[i] = 0
}
c.rsiz = 200 - 2 * c.mdlen
c.pt = 0
ctx.rsiz = 200 - 2 * ctx.mdlen
ctx.pt = 0
c.is_initialized = true
c.is_finalized = false
ctx.is_initialized = true
ctx.is_finalized = false
}
update :: proc(c: ^Sha3_Context, data: []byte) {
assert(c.is_initialized)
assert(!c.is_finalized)
update :: proc(ctx: ^Context, data: []byte) {
assert(ctx.is_initialized)
assert(!ctx.is_finalized)
j := c.pt
j := ctx.pt
for i := 0; i < len(data); i += 1 {
c.st.b[j] ~= data[i]
ctx.st.b[j] ~= data[i]
j += 1
if j >= c.rsiz {
keccakf(&c.st.q)
if j >= ctx.rsiz {
keccakf(&ctx.st.q)
j = 0
}
}
c.pt = j
ctx.pt = j
}
final :: proc(c: ^Sha3_Context, hash: []byte) {
assert(c.is_initialized)
final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) {
assert(ctx.is_initialized)
if len(hash) < c.mdlen {
if c.is_keccak {
panic("crypto/keccac: invalid destination digest size")
}
if len(hash) < ctx.mdlen {
panic("crypto/sha3: invalid destination digest size")
}
if c.is_keccak {
c.st.b[c.pt] ~= 0x01
} else {
c.st.b[c.pt] ~= 0x06
}
c.st.b[c.rsiz - 1] ~= 0x80
keccakf(&c.st.q)
for i := 0; i < c.mdlen; i += 1 {
hash[i] = c.st.b[i]
ctx := ctx
if finalize_clone {
tmp_ctx: Context
clone(&tmp_ctx, ctx)
ctx = &tmp_ctx
}
defer (reset(ctx))
c.is_initialized = false // No more absorb, no more squeeze.
ctx.st.b[ctx.pt] ~= ctx.dsbyte
ctx.st.b[ctx.rsiz - 1] ~= 0x80
keccakf(&ctx.st.q)
for i := 0; i < ctx.mdlen; i += 1 {
hash[i] = ctx.st.b[i]
}
}
shake_xof :: proc(c: ^Sha3_Context) {
assert(c.is_initialized)
assert(!c.is_finalized)
c.st.b[c.pt] ~= 0x1F
c.st.b[c.rsiz - 1] ~= 0x80
keccakf(&c.st.q)
c.pt = 0
c.is_finalized = true // No more absorb, unlimited squeeze.
clone :: proc(ctx, other: ^Context) {
ctx^ = other^
}
shake_out :: proc(c: ^Sha3_Context, hash: []byte) {
assert(c.is_initialized)
assert(c.is_finalized)
reset :: proc(ctx: ^Context) {
if !ctx.is_initialized {
return
}
j := c.pt
mem.zero_explicit(ctx, size_of(ctx^))
}
shake_xof :: proc(ctx: ^Context) {
assert(ctx.is_initialized)
assert(!ctx.is_finalized)
ctx.st.b[ctx.pt] ~= ctx.dsbyte
ctx.st.b[ctx.rsiz - 1] ~= 0x80
keccakf(&ctx.st.q)
ctx.pt = 0
ctx.is_finalized = true // No more absorb, unlimited squeeze.
}
shake_out :: proc(ctx: ^Context, hash: []byte) {
assert(ctx.is_initialized)
assert(ctx.is_finalized)
j := ctx.pt
for i := 0; i < len(hash); i += 1 {
if j >= c.rsiz {
keccakf(&c.st.q)
if j >= ctx.rsiz {
keccakf(&ctx.st.q)
j = 0
}
hash[i] = c.st.b[j]
hash[i] = ctx.st.b[j]
j += 1
}
c.pt = j
ctx.pt = j
}
+145
View File
@@ -0,0 +1,145 @@
package _sha3
import "core:encoding/endian"
import "core:math/bits"
init_cshake :: proc(ctx: ^Context, n, s: []byte, sec_strength: int) {
ctx.mdlen = sec_strength / 8
// No domain separator is equivalent to vanilla SHAKE.
if len(n) == 0 && len(s) == 0 {
ctx.dsbyte = DS_SHAKE
init(ctx)
return
}
ctx.dsbyte = DS_CSHAKE
init(ctx)
bytepad(ctx, [][]byte{n, s}, rate_cshake(sec_strength))
}
final_cshake :: proc(ctx: ^Context, dst: []byte, finalize_clone: bool = false) {
ctx := ctx
if finalize_clone {
tmp_ctx: Context
clone(&tmp_ctx, ctx)
ctx = &tmp_ctx
}
defer reset(ctx)
encode_byte_len(ctx, len(dst), false) // right_encode
shake_xof(ctx)
shake_out(ctx, dst)
}
rate_cshake :: #force_inline proc(sec_strength: int) -> int {
switch sec_strength {
case 128:
return RATE_128
case 256:
return RATE_256
}
panic("crypto/sha3: invalid security strength")
}
// right_encode and left_encode are defined to support 0 <= x < 2^2040
// however, the largest value we will ever need to encode is `max(int) * 8`.
//
// This is unfortunate as the extreme upper edge is larger than
// `max(u64)`. While such values are impractical at present,
// they are possible (ie: https://arxiv.org/pdf/quant-ph/9908043.pdf).
//
// Thus we support 0 <= x < 2^128.
@(private)
_PAD: [RATE_128]byte // Biggest possible value of w per spec.
bytepad :: proc(ctx: ^Context, x_strings: [][]byte, w: int) {
// 1. z = left_encode(w) || X.
z_hi: u64
z_lo := left_right_encode(ctx, 0, u64(w), true)
for x in x_strings {
// All uses of bytepad in SP 800-185 use the output from
// one or more encode_string values for `X`.
hi, lo := encode_string(ctx, x)
carry: u64
z_lo, carry = bits.add_u64(z_lo, lo, 0)
z_hi, carry = bits.add_u64(z_hi, hi, carry)
// This isn't actually possible, at least with the currently
// defined SP 800-185 routines.
if carry != 0 {
panic("crypto/sha3: bytepad input length overflow")
}
}
// We skip this step as we are doing a byte-oriented implementation
// rather than a bit oriented one.
//
// 2. while len(z) mod 8 ≠ 0:
// z = z || 0
// 3. while (len(z)/8) mod w ≠ 0:
// z = z || 00000000
z_len := u128(z_hi) << 64 | u128(z_lo)
z_rem := int(z_len % u128(w))
pad := _PAD[:w - z_rem]
// We just add the padding to the state, instead of returning z.
//
// 4. return z.
update(ctx, pad)
}
encode_string :: #force_inline proc(ctx: ^Context, s: []byte) -> (u64, u64) {
l := encode_byte_len(ctx, len(s), true) // left_encode
update(ctx, s)
lo, hi := bits.add_u64(l, u64(len(s)), 0)
return hi, lo
}
encode_byte_len :: #force_inline proc(ctx: ^Context, l: int, is_left: bool) -> u64 {
hi, lo := bits.mul_u64(u64(l), 8)
return left_right_encode(ctx, hi, lo, is_left)
}
@(private)
left_right_encode :: proc(ctx: ^Context, hi, lo: u64, is_left: bool) -> u64 {
HI_OFFSET :: 1
LO_OFFSET :: HI_OFFSET + 8
RIGHT_OFFSET :: LO_OFFSET + 8
BUF_LEN :: RIGHT_OFFSET + 1
buf: [BUF_LEN]byte // prefix + largest uint + postfix
endian.unchecked_put_u64be(buf[HI_OFFSET:], hi)
endian.unchecked_put_u64be(buf[LO_OFFSET:], lo)
// 2. Strip leading `0x00` bytes.
off: int
for off = HI_OFFSET; off < RIGHT_OFFSET - 1; off = off + 1 {// Note: Minimum size is 1, not 0.
if buf[off] != 0 {
break
}
}
n := byte(RIGHT_OFFSET - off)
// 3. Prefix (left_encode) or postfix (right_encode) the length in bytes.
b: []byte
switch is_left {
case true:
buf[off - 1] = n // n | x
b = buf[off - 1:RIGHT_OFFSET]
case false:
buf[RIGHT_OFFSET] = n // x | n
b = buf[off:]
}
update(ctx, b)
return u64(len(b))
}
+34 -102
View File
@@ -1,3 +1,10 @@
/*
package blake2b implements the BLAKE2b hash algorithm.
See:
- https://datatracker.ietf.org/doc/html/rfc7693
- https://www.blake2.net
*/
package blake2b
/*
@@ -6,122 +13,47 @@ package blake2b
List of contributors:
zhibog, dotbmp: Initial implementation.
Interface for the BLAKE2b hashing algorithm.
BLAKE2b and BLAKE2s share the implementation in the _blake2 package.
*/
import "core:io"
import "core:os"
import "../_blake2"
/*
High level API
*/
// DIGEST_SIZE is the BLAKE2b digest size in bytes.
DIGEST_SIZE :: 64
// hash_string will hash the given input and return the
// computed hash
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
return hash_bytes(transmute([]byte)(data))
}
// hash_bytes will hash the given input and return the
// computed hash
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
hash: [DIGEST_SIZE]byte
ctx: Context
cfg: _blake2.Blake2_Config
cfg.size = _blake2.BLAKE2B_SIZE
ctx.cfg = cfg
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer :: proc(data, hash: []byte) {
ctx: Context
cfg: _blake2.Blake2_Config
cfg.size = _blake2.BLAKE2B_SIZE
ctx.cfg = cfg
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream will read the stream in chunks and compute a
// hash from its contents
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
hash: [DIGEST_SIZE]byte
ctx: Context
cfg: _blake2.Blake2_Config
cfg.size = _blake2.BLAKE2B_SIZE
ctx.cfg = cfg
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file will read the file provided by the given handle
// and compute a hash
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
if !load_at_once {
return hash_stream(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes(buf[:]), ok
}
}
return [DIGEST_SIZE]byte{}, false
}
hash :: proc {
hash_stream,
hash_file,
hash_bytes,
hash_string,
hash_bytes_to_buffer,
hash_string_to_buffer,
}
/*
Low level API
*/
// BLOCK_SIZE is the BLAKE2b block size in bytes.
BLOCK_SIZE :: _blake2.BLAKE2B_BLOCK_SIZE
// Context is a BLAKE2b instance.
Context :: _blake2.Blake2b_Context
// init initializes a Context with the default BLAKE2b config.
init :: proc(ctx: ^Context) {
_blake2.init(ctx)
cfg: _blake2.Blake2_Config
cfg.size = _blake2.BLAKE2B_SIZE
_blake2.init(ctx, &cfg)
}
// update adds more data to the Context.
update :: proc(ctx: ^Context, data: []byte) {
_blake2.update(ctx, data)
}
final :: proc(ctx: ^Context, hash: []byte) {
_blake2.final(ctx, hash)
// final finalizes the Context, writes the digest to hash, and calls
// reset on the Context.
//
// Iff finalize_clone is set, final will work on a copy of the Context,
// which is useful for for calculating rolling digests.
final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) {
_blake2.final(ctx, hash, finalize_clone)
}
// clone clones the Context other into ctx.
clone :: proc(ctx, other: ^Context) {
_blake2.clone(ctx, other)
}
// reset sanitizes the Context. The Context must be re-initialized to
// be used again.
reset :: proc(ctx: ^Context) {
_blake2.reset(ctx)
}
+34 -102
View File
@@ -1,3 +1,10 @@
/*
package blake2s implements the BLAKE2s hash algorithm.
See:
- https://datatracker.ietf.org/doc/html/rfc7693
- https://www.blake2.net/
*/
package blake2s
/*
@@ -6,122 +13,47 @@ package blake2s
List of contributors:
zhibog, dotbmp: Initial implementation.
Interface for the BLAKE2s hashing algorithm.
BLAKE2s and BLAKE2b share the implementation in the _blake2 package.
*/
import "core:io"
import "core:os"
import "../_blake2"
/*
High level API
*/
// DIGEST_SIZE is the BLAKE2s digest size in bytes.
DIGEST_SIZE :: 32
// hash_string will hash the given input and return the
// computed hash
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
return hash_bytes(transmute([]byte)(data))
}
// hash_bytes will hash the given input and return the
// computed hash
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
hash: [DIGEST_SIZE]byte
ctx: Context
cfg: _blake2.Blake2_Config
cfg.size = _blake2.BLAKE2S_SIZE
ctx.cfg = cfg
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer :: proc(data, hash: []byte) {
ctx: Context
cfg: _blake2.Blake2_Config
cfg.size = _blake2.BLAKE2S_SIZE
ctx.cfg = cfg
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream will read the stream in chunks and compute a
// hash from its contents
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
hash: [DIGEST_SIZE]byte
ctx: Context
cfg: _blake2.Blake2_Config
cfg.size = _blake2.BLAKE2S_SIZE
ctx.cfg = cfg
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file will read the file provided by the given handle
// and compute a hash
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
if !load_at_once {
return hash_stream(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes(buf[:]), ok
}
}
return [DIGEST_SIZE]byte{}, false
}
hash :: proc {
hash_stream,
hash_file,
hash_bytes,
hash_string,
hash_bytes_to_buffer,
hash_string_to_buffer,
}
/*
Low level API
*/
// BLOCK_SIZE is the BLAKE2s block size in bytes.
BLOCK_SIZE :: _blake2.BLAKE2S_BLOCK_SIZE
// Context is a BLAKE2s instance.
Context :: _blake2.Blake2s_Context
// init initializes a Context with the default BLAKE2s config.
init :: proc(ctx: ^Context) {
_blake2.init(ctx)
cfg: _blake2.Blake2_Config
cfg.size = _blake2.BLAKE2S_SIZE
_blake2.init(ctx, &cfg)
}
// update adds more data to the Context.
update :: proc(ctx: ^Context, data: []byte) {
_blake2.update(ctx, data)
}
final :: proc(ctx: ^Context, hash: []byte) {
_blake2.final(ctx, hash)
// final finalizes the Context, writes the digest to hash, and calls
// reset on the Context.
//
// Iff finalize_clone is set, final will work on a copy of the Context,
// which is useful for for calculating rolling digests.
final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) {
_blake2.final(ctx, hash, finalize_clone)
}
// clone clones the Context other into ctx.
clone :: proc(ctx, other: ^Context) {
_blake2.clone(ctx, other)
}
// reset sanitizes the Context. The Context must be re-initialized to
// be used again.
reset :: proc(ctx: ^Context) {
_blake2.reset(ctx)
}
+33 -15
View File
@@ -1,11 +1,21 @@
/*
package chacha20 implements the ChaCha20 and XChaCha20 stream ciphers.
See:
- https://datatracker.ietf.org/doc/html/rfc8439
- https://datatracker.ietf.org/doc/draft-irtf-cfrg-xchacha/03/
*/
package chacha20
import "core:encoding/endian"
import "core:math/bits"
import "core:mem"
// KEY_SIZE is the (X)ChaCha20 key size in bytes.
KEY_SIZE :: 32
// NONCE_SIZE is the ChaCha20 nonce size in bytes.
NONCE_SIZE :: 12
// XNONCE_SIZE is the XChaCha20 nonce size in bytes.
XNONCE_SIZE :: 24
@(private)
@@ -19,25 +29,26 @@ _STATE_SIZE_U32 :: 16
_ROUNDS :: 20
@(private)
_SIGMA_0 : u32 : 0x61707865
_SIGMA_0: u32 : 0x61707865
@(private)
_SIGMA_1 : u32 : 0x3320646e
_SIGMA_1: u32 : 0x3320646e
@(private)
_SIGMA_2 : u32 : 0x79622d32
_SIGMA_2: u32 : 0x79622d32
@(private)
_SIGMA_3 : u32 : 0x6b206574
_SIGMA_3: u32 : 0x6b206574
// Context is a ChaCha20 or XChaCha20 instance.
Context :: struct {
_s: [_STATE_SIZE_U32]u32,
_buffer: [_BLOCK_SIZE]byte,
_off: int,
_s: [_STATE_SIZE_U32]u32,
_buffer: [_BLOCK_SIZE]byte,
_off: int,
_is_ietf_flavor: bool,
_is_initialized: bool,
}
init :: proc (ctx: ^Context, key, nonce: []byte) {
// init inititializes a Context for ChaCha20 or XChaCha20 with the provided
// key and nonce.
init :: proc(ctx: ^Context, key, nonce: []byte) {
if len(key) != KEY_SIZE {
panic("crypto/chacha20: invalid ChaCha20 key size")
}
@@ -89,7 +100,8 @@ init :: proc (ctx: ^Context, key, nonce: []byte) {
ctx._is_initialized = true
}
seek :: proc (ctx: ^Context, block_nr: u64) {
// seek seeks the (X)ChaCha20 stream counter to the specified block.
seek :: proc(ctx: ^Context, block_nr: u64) {
assert(ctx._is_initialized)
if ctx._is_ietf_flavor {
@@ -103,7 +115,10 @@ seek :: proc (ctx: ^Context, block_nr: u64) {
ctx._off = _BLOCK_SIZE
}
xor_bytes :: proc (ctx: ^Context, dst, src: []byte) {
// xor_bytes XORs each byte in src with bytes taken from the (X)ChaCha20
// keystream, and writes the resulting output to dst. Dst and src MUST
// alias exactly or not at all.
xor_bytes :: proc(ctx: ^Context, dst, src: []byte) {
assert(ctx._is_initialized)
// TODO: Enforcing that dst and src alias exactly or not at all
@@ -147,7 +162,8 @@ xor_bytes :: proc (ctx: ^Context, dst, src: []byte) {
}
}
keystream_bytes :: proc (ctx: ^Context, dst: []byte) {
// keystream_bytes fills dst with the raw (X)ChaCha20 keystream output.
keystream_bytes :: proc(ctx: ^Context, dst: []byte) {
assert(ctx._is_initialized)
dst := dst
@@ -180,7 +196,9 @@ keystream_bytes :: proc (ctx: ^Context, dst: []byte) {
}
}
reset :: proc (ctx: ^Context) {
// reset sanitizes the Context. The Context must be re-initialized to
// be used again.
reset :: proc(ctx: ^Context) {
mem.zero_explicit(&ctx._s, size_of(ctx._s))
mem.zero_explicit(&ctx._buffer, size_of(ctx._buffer))
@@ -188,7 +206,7 @@ reset :: proc (ctx: ^Context) {
}
@(private)
_do_blocks :: proc (ctx: ^Context, dst, src: []byte, nr_blocks: int) {
_do_blocks :: proc(ctx: ^Context, dst, src: []byte, nr_blocks: int) {
// Enforce the maximum consumed keystream per nonce.
//
// While all modern "standard" definitions of ChaCha20 use
@@ -1,3 +1,10 @@
/*
package chacha20poly1305 implements the AEAD_CHACHA20_POLY1305 Authenticated
Encryption with Additional Data algorithm.
See:
- https://www.rfc-editor.org/rfc/rfc8439
*/
package chacha20poly1305
import "core:crypto"
@@ -6,8 +13,11 @@ import "core:crypto/poly1305"
import "core:encoding/endian"
import "core:mem"
// KEY_SIZE is the chacha20poly1305 key size in bytes.
KEY_SIZE :: chacha20.KEY_SIZE
// NONCE_SIZE is the chacha20poly1305 nonce size in bytes.
NONCE_SIZE :: chacha20.NONCE_SIZE
// TAG_SIZE is the chacha20poly1305 tag size in bytes.
TAG_SIZE :: poly1305.TAG_SIZE
@(private)
@@ -49,6 +59,8 @@ _update_mac_pad16 :: #force_inline proc (ctx: ^poly1305.Context, x_len: int) {
}
}
// encrypt encrypts the plaintext and authenticates the aad and ciphertext,
// with the provided key and nonce, stores the output in ciphertext and tag.
encrypt :: proc (ciphertext, tag, key, nonce, aad, plaintext: []byte) {
_validate_common_slice_sizes(tag, key, nonce, aad, plaintext)
if len(ciphertext) != len(plaintext) {
@@ -95,6 +107,11 @@ encrypt :: proc (ciphertext, tag, key, nonce, aad, plaintext: []byte) {
poly1305.final(&mac_ctx, tag) // Implicitly sanitizes context.
}
// decrypt authenticates the aad and ciphertext, and decrypts the ciphertext,
// with the provided key, nonce, and tag, and stores the output in plaintext,
// returning true iff the authentication was successful.
//
// If authentication fails, the destination plaintext buffer will be zeroed.
decrypt :: proc (plaintext, tag, key, nonce, aad, ciphertext: []byte) -> bool {
_validate_common_slice_sizes(tag, key, nonce, aad, ciphertext)
if len(ciphertext) != len(plaintext) {
+62
View File
@@ -0,0 +1,62 @@
/*
package hash provides a generic interface to the supported hash algorithms.
A high-level convenience procedure group `hash` is provided to easily
accomplish common tasks.
- `hash_string` - Hash a given string and return the digest.
- `hash_bytes` - Hash a given byte slice and return the digest.
- `hash_string_to_buffer` - Hash a given string and put the digest in
the third parameter. It requires that the destination buffer
is at least as big as the digest size.
- `hash_bytes_to_buffer` - Hash a given string and put the computed
digest in the third parameter. It requires that the destination
buffer is at least as big as the digest size.
- `hash_stream` - Incrementally fully consume a `io.Stream`, and return
the computed digest.
- `hash_file` - Takes a file handle and returns the computed digest.
A third optional boolean parameter controls if the file is streamed
(default), or or read at once.
```odin
package hash_example
import "core:crypto/hash"
main :: proc() {
input := "Feed the fire."
// Compute the digest, using the high level API.
returned_digest := hash.hash(hash.Algorithm.SHA512_256, input)
defer delete(returned_digest)
// Variant that takes a destination buffer, instead of returning
// the digest.
digest := make([]byte, hash.DIGEST_SIZES[hash.Algorithm.BLAKE2B]) // @note: Destination buffer has to be at least as big as the digest size of the hash.
defer delete(digest)
hash.hash(hash.Algorithm.BLAKE2B, input, digest)
}
```
A generic low level API is provided supporting the init/update/final interface
that is typical with cryptographic hash function implementations.
```odin
package hash_example
import "core:crypto/hash"
main :: proc() {
input := "Let the cinders burn."
// Compute the digest, using the low level API.
ctx: hash.Context
digest := make([]byte, hash.DIGEST_SIZES[hash.Algorithm.SHA3_512])
defer delete(digest)
hash.init(&ctx, hash.Algorithm.SHA3_512)
hash.update(&ctx, transmute([]byte)input)
hash.final(&ctx, digest)
}
```
*/
package crypto_hash
+116
View File
@@ -0,0 +1,116 @@
package crypto_hash
/*
Copyright 2021 zhibog
Made available under the BSD-3 license.
List of contributors:
zhibog, dotbmp: Initial implementation.
*/
import "core:io"
import "core:mem"
import "core:os"
// hash_bytes will hash the given input and return the computed digest
// in a newly allocated slice.
hash_string :: proc(algorithm: Algorithm, data: string, allocator := context.allocator) -> []byte {
return hash_bytes(algorithm, transmute([]byte)(data), allocator)
}
// hash_bytes will hash the given input and return the computed digest
// in a newly allocated slice.
hash_bytes :: proc(algorithm: Algorithm, data: []byte, allocator := context.allocator) -> []byte {
dst := make([]byte, DIGEST_SIZES[algorithm], allocator)
hash_bytes_to_buffer(algorithm, data, dst)
return dst
}
// hash_string_to_buffer will hash the given input and assign the
// computed digest to the third parameter. It requires that the
// destination buffer is at least as big as the digest size.
hash_string_to_buffer :: proc(algorithm: Algorithm, data: string, hash: []byte) {
hash_bytes_to_buffer(algorithm, transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
// computed digest into the third parameter. It requires that the
// destination buffer is at least as big as the digest size.
hash_bytes_to_buffer :: proc(algorithm: Algorithm, data, hash: []byte) {
ctx: Context
init(&ctx, algorithm)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream will incrementally fully consume a stream, and return the
// computed digest in a newly allocated slice.
hash_stream :: proc(
algorithm: Algorithm,
s: io.Stream,
allocator := context.allocator,
) -> (
[]byte,
io.Error,
) {
ctx: Context
buf: [MAX_BLOCK_SIZE * 4]byte
defer mem.zero_explicit(&buf, size_of(buf))
init(&ctx, algorithm)
loop: for {
n, err := io.read(s, buf[:])
if n > 0 {
// XXX/yawning: Can io.read return n > 0 and EOF?
update(&ctx, buf[:n])
}
#partial switch err {
case .None:
case .EOF:
break loop
case:
return nil, err
}
}
dst := make([]byte, DIGEST_SIZES[algorithm], allocator)
final(&ctx, dst)
return dst, io.Error.None
}
// hash_file will read the file provided by the given handle and return the
// computed digest in a newly allocated slice.
hash_file :: proc(
algorithm: Algorithm,
hd: os.Handle,
load_at_once := false,
allocator := context.allocator,
) -> (
[]byte,
io.Error,
) {
if !load_at_once {
return hash_stream(algorithm, os.stream_from_handle(hd), allocator)
}
buf, ok := os.read_entire_file(hd, allocator)
if !ok {
return nil, io.Error.Unknown
}
defer delete(buf, allocator)
return hash_bytes(algorithm, buf, allocator), io.Error.None
}
hash :: proc {
hash_stream,
hash_file,
hash_bytes,
hash_string,
hash_bytes_to_buffer,
hash_string_to_buffer,
}
+353
View File
@@ -0,0 +1,353 @@
package crypto_hash
import "core:crypto/blake2b"
import "core:crypto/blake2s"
import "core:crypto/sha2"
import "core:crypto/sha3"
import "core:crypto/sm3"
import "core:crypto/legacy/keccak"
import "core:crypto/legacy/md5"
import "core:crypto/legacy/sha1"
import "core:reflect"
// MAX_DIGEST_SIZE is the maximum size digest that can be returned by any
// of the Algorithms supported via this package.
MAX_DIGEST_SIZE :: 64
// MAX_BLOCK_SIZE is the maximum block size used by any of Algorithms
// supported by this package.
MAX_BLOCK_SIZE :: sha3.BLOCK_SIZE_224
// Algorithm is the algorithm identifier associated with a given Context.
Algorithm :: enum {
Invalid,
BLAKE2B,
BLAKE2S,
SHA224,
SHA256,
SHA384,
SHA512,
SHA512_256,
SHA3_224,
SHA3_256,
SHA3_384,
SHA3_512,
SM3,
Legacy_KECCAK_224,
Legacy_KECCAK_256,
Legacy_KECCAK_384,
Legacy_KECCAK_512,
Insecure_MD5,
Insecure_SHA1,
}
// ALGORITHM_NAMES is the Algorithm to algorithm name string.
ALGORITHM_NAMES := [Algorithm]string {
.Invalid = "Invalid",
.BLAKE2B = "BLAKE2b",
.BLAKE2S = "BLAKE2s",
.SHA224 = "SHA-224",
.SHA256 = "SHA-256",
.SHA384 = "SHA-384",
.SHA512 = "SHA-512",
.SHA512_256 = "SHA-512/256",
.SHA3_224 = "SHA3-224",
.SHA3_256 = "SHA3-256",
.SHA3_384 = "SHA3-384",
.SHA3_512 = "SHA3-512",
.SM3 = "SM3",
.Legacy_KECCAK_224 = "Keccak-224",
.Legacy_KECCAK_256 = "Keccak-256",
.Legacy_KECCAK_384 = "Keccak-384",
.Legacy_KECCAK_512 = "Keccak-512",
.Insecure_MD5 = "MD5",
.Insecure_SHA1 = "SHA-1",
}
// DIGEST_SIZES is the Algorithm to digest size in bytes.
DIGEST_SIZES := [Algorithm]int {
.Invalid = 0,
.BLAKE2B = blake2b.DIGEST_SIZE,
.BLAKE2S = blake2s.DIGEST_SIZE,
.SHA224 = sha2.DIGEST_SIZE_224,
.SHA256 = sha2.DIGEST_SIZE_256,
.SHA384 = sha2.DIGEST_SIZE_384,
.SHA512 = sha2.DIGEST_SIZE_512,
.SHA512_256 = sha2.DIGEST_SIZE_512_256,
.SHA3_224 = sha3.DIGEST_SIZE_224,
.SHA3_256 = sha3.DIGEST_SIZE_256,
.SHA3_384 = sha3.DIGEST_SIZE_384,
.SHA3_512 = sha3.DIGEST_SIZE_512,
.SM3 = sm3.DIGEST_SIZE,
.Legacy_KECCAK_224 = keccak.DIGEST_SIZE_224,
.Legacy_KECCAK_256 = keccak.DIGEST_SIZE_256,
.Legacy_KECCAK_384 = keccak.DIGEST_SIZE_384,
.Legacy_KECCAK_512 = keccak.DIGEST_SIZE_512,
.Insecure_MD5 = md5.DIGEST_SIZE,
.Insecure_SHA1 = sha1.DIGEST_SIZE,
}
// BLOCK_SIZES is the Algoritm to block size in bytes.
BLOCK_SIZES := [Algorithm]int {
.Invalid = 0,
.BLAKE2B = blake2b.BLOCK_SIZE,
.BLAKE2S = blake2s.BLOCK_SIZE,
.SHA224 = sha2.BLOCK_SIZE_256,
.SHA256 = sha2.BLOCK_SIZE_256,
.SHA384 = sha2.BLOCK_SIZE_512,
.SHA512 = sha2.BLOCK_SIZE_512,
.SHA512_256 = sha2.BLOCK_SIZE_512,
.SHA3_224 = sha3.BLOCK_SIZE_224,
.SHA3_256 = sha3.BLOCK_SIZE_256,
.SHA3_384 = sha3.BLOCK_SIZE_384,
.SHA3_512 = sha3.BLOCK_SIZE_512,
.SM3 = sm3.BLOCK_SIZE,
.Legacy_KECCAK_224 = keccak.BLOCK_SIZE_224,
.Legacy_KECCAK_256 = keccak.BLOCK_SIZE_256,
.Legacy_KECCAK_384 = keccak.BLOCK_SIZE_384,
.Legacy_KECCAK_512 = keccak.BLOCK_SIZE_512,
.Insecure_MD5 = md5.BLOCK_SIZE,
.Insecure_SHA1 = sha1.BLOCK_SIZE,
}
// Context is a concrete instantiation of a specific hash algorithm.
Context :: struct {
_algo: Algorithm,
_impl: union {
blake2b.Context,
blake2s.Context,
sha2.Context_256,
sha2.Context_512,
sha3.Context,
sm3.Context,
keccak.Context,
md5.Context,
sha1.Context,
},
}
@(private)
_IMPL_IDS := [Algorithm]typeid {
.Invalid = nil,
.BLAKE2B = typeid_of(blake2b.Context),
.BLAKE2S = typeid_of(blake2s.Context),
.SHA224 = typeid_of(sha2.Context_256),
.SHA256 = typeid_of(sha2.Context_256),
.SHA384 = typeid_of(sha2.Context_512),
.SHA512 = typeid_of(sha2.Context_512),
.SHA512_256 = typeid_of(sha2.Context_512),
.SHA3_224 = typeid_of(sha3.Context),
.SHA3_256 = typeid_of(sha3.Context),
.SHA3_384 = typeid_of(sha3.Context),
.SHA3_512 = typeid_of(sha3.Context),
.SM3 = typeid_of(sm3.Context),
.Legacy_KECCAK_224 = typeid_of(keccak.Context),
.Legacy_KECCAK_256 = typeid_of(keccak.Context),
.Legacy_KECCAK_384 = typeid_of(keccak.Context),
.Legacy_KECCAK_512 = typeid_of(keccak.Context),
.Insecure_MD5 = typeid_of(md5.Context),
.Insecure_SHA1 = typeid_of(sha1.Context),
}
// init initializes a Context with a specific hash Algorithm.
init :: proc(ctx: ^Context, algorithm: Algorithm) {
if ctx._impl != nil {
reset(ctx)
}
// Directly specialize the union by setting the type ID (save a copy).
reflect.set_union_variant_typeid(
ctx._impl,
_IMPL_IDS[algorithm],
)
switch algorithm {
case .BLAKE2B:
blake2b.init(&ctx._impl.(blake2b.Context))
case .BLAKE2S:
blake2s.init(&ctx._impl.(blake2s.Context))
case .SHA224:
sha2.init_224(&ctx._impl.(sha2.Context_256))
case .SHA256:
sha2.init_256(&ctx._impl.(sha2.Context_256))
case .SHA384:
sha2.init_384(&ctx._impl.(sha2.Context_512))
case .SHA512:
sha2.init_512(&ctx._impl.(sha2.Context_512))
case .SHA512_256:
sha2.init_512_256(&ctx._impl.(sha2.Context_512))
case .SHA3_224:
sha3.init_224(&ctx._impl.(sha3.Context))
case .SHA3_256:
sha3.init_256(&ctx._impl.(sha3.Context))
case .SHA3_384:
sha3.init_384(&ctx._impl.(sha3.Context))
case .SHA3_512:
sha3.init_512(&ctx._impl.(sha3.Context))
case .SM3:
sm3.init(&ctx._impl.(sm3.Context))
case .Legacy_KECCAK_224:
keccak.init_224(&ctx._impl.(keccak.Context))
case .Legacy_KECCAK_256:
keccak.init_256(&ctx._impl.(keccak.Context))
case .Legacy_KECCAK_384:
keccak.init_384(&ctx._impl.(keccak.Context))
case .Legacy_KECCAK_512:
keccak.init_512(&ctx._impl.(keccak.Context))
case .Insecure_MD5:
md5.init(&ctx._impl.(md5.Context))
case .Insecure_SHA1:
sha1.init(&ctx._impl.(sha1.Context))
case .Invalid:
panic("crypto/hash: uninitialized algorithm")
case:
panic("crypto/hash: invalid algorithm")
}
ctx._algo = algorithm
}
// update adds more data to the Context.
update :: proc(ctx: ^Context, data: []byte) {
switch &impl in ctx._impl {
case blake2b.Context:
blake2b.update(&impl, data)
case blake2s.Context:
blake2s.update(&impl, data)
case sha2.Context_256:
sha2.update(&impl, data)
case sha2.Context_512:
sha2.update(&impl, data)
case sha3.Context:
sha3.update(&impl, data)
case sm3.Context:
sm3.update(&impl, data)
case keccak.Context:
keccak.update(&impl, data)
case md5.Context:
md5.update(&impl, data)
case sha1.Context:
sha1.update(&impl, data)
case:
panic("crypto/hash: uninitialized algorithm")
}
}
// final finalizes the Context, writes the digest to hash, and calls
// reset on the Context.
//
// Iff finalize_clone is set, final will work on a copy of the Context,
// which is useful for for calculating rolling digests.
final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) {
switch &impl in ctx._impl {
case blake2b.Context:
blake2b.final(&impl, hash, finalize_clone)
case blake2s.Context:
blake2s.final(&impl, hash, finalize_clone)
case sha2.Context_256:
sha2.final(&impl, hash, finalize_clone)
case sha2.Context_512:
sha2.final(&impl, hash, finalize_clone)
case sha3.Context:
sha3.final(&impl, hash, finalize_clone)
case sm3.Context:
sm3.final(&impl, hash, finalize_clone)
case keccak.Context:
keccak.final(&impl, hash, finalize_clone)
case md5.Context:
md5.final(&impl, hash, finalize_clone)
case sha1.Context:
sha1.final(&impl, hash, finalize_clone)
case:
panic("crypto/hash: uninitialized algorithm")
}
if !finalize_clone {
reset(ctx)
}
}
// clone clones the Context other into ctx.
clone :: proc(ctx, other: ^Context) {
// XXX/yawning: Maybe these cases should panic, because both cases,
// are probably bugs.
if ctx == other {
return
}
if ctx._impl != nil {
reset(ctx)
}
ctx._algo = other._algo
reflect.set_union_variant_typeid(
ctx._impl,
reflect.union_variant_typeid(other._impl),
)
switch &src_impl in other._impl {
case blake2b.Context:
blake2b.clone(&ctx._impl.(blake2b.Context), &src_impl)
case blake2s.Context:
blake2s.clone(&ctx._impl.(blake2s.Context), &src_impl)
case sha2.Context_256:
sha2.clone(&ctx._impl.(sha2.Context_256), &src_impl)
case sha2.Context_512:
sha2.clone(&ctx._impl.(sha2.Context_512), &src_impl)
case sha3.Context:
sha3.clone(&ctx._impl.(sha3.Context), &src_impl)
case sm3.Context:
sm3.clone(&ctx._impl.(sm3.Context), &src_impl)
case keccak.Context:
keccak.clone(&ctx._impl.(keccak.Context), &src_impl)
case md5.Context:
md5.clone(&ctx._impl.(md5.Context), &src_impl)
case sha1.Context:
sha1.clone(&ctx._impl.(sha1.Context), &src_impl)
case:
panic("crypto/hash: uninitialized algorithm")
}
}
// reset sanitizes the Context. The Context must be re-initialized to
// be used again.
reset :: proc(ctx: ^Context) {
switch &impl in ctx._impl {
case blake2b.Context:
blake2b.reset(&impl)
case blake2s.Context:
blake2s.reset(&impl)
case sha2.Context_256:
sha2.reset(&impl)
case sha2.Context_512:
sha2.reset(&impl)
case sha3.Context:
sha3.reset(&impl)
case sm3.Context:
sm3.reset(&impl)
case keccak.Context:
keccak.reset(&impl)
case md5.Context:
md5.reset(&impl)
case sha1.Context:
sha1.reset(&impl)
case:
// Unlike clone, calling reset repeatedly is fine.
}
ctx._algo = .Invalid
ctx._impl = nil
}
// algorithm returns the Algorithm used by a Context instance.
algorithm :: proc(ctx: ^Context) -> Algorithm {
return ctx._algo
}
// digest_size returns the digest size of a Context instance in bytes.
digest_size :: proc(ctx: ^Context) -> int {
return DIGEST_SIZES[ctx._algo]
}
// block_size returns the block size of a Context instance in bytes.
block_size :: proc(ctx: ^Context) -> int {
return BLOCK_SIZES[ctx._algo]
}
+103
View File
@@ -0,0 +1,103 @@
/*
package hkdf implements the HKDF HMAC-based Extract-and-Expand Key
Derivation Function.
See: https://www.rfc-editor.org/rfc/rfc5869
*/
package hkdf
import "core:crypto/hash"
import "core:crypto/hmac"
import "core:mem"
// extract_and_expand derives output keying material (OKM) via the
// HKDF-Extract and HKDF-Expand algorithms, with the specified has
// function, salt, input keying material (IKM), and optional info.
// The dst buffer must be less-than-or-equal to 255 HMAC tags.
extract_and_expand :: proc(algorithm: hash.Algorithm, salt, ikm, info, dst: []byte) {
h_len := hash.DIGEST_SIZES[algorithm]
tmp: [hash.MAX_DIGEST_SIZE]byte
prk := tmp[:h_len]
defer mem.zero_explicit(raw_data(prk), h_len)
extract(algorithm, salt, ikm, prk)
expand(algorithm, prk, info, dst)
}
// extract derives a pseudorandom key (PRK) via the HKDF-Extract algorithm,
// with the specified hash function, salt, and input keying material (IKM).
// It requires that the dst buffer be the HMAC tag size for the specified
// hash function.
extract :: proc(algorithm: hash.Algorithm, salt, ikm, dst: []byte) {
// PRK = HMAC-Hash(salt, IKM)
hmac.sum(algorithm, dst, ikm, salt)
}
// expand derives output keying material (OKM) via the HKDF-Expand algorithm,
// with the specified hash function, pseudorandom key (PRK), and optional
// info. The dst buffer must be less-than-or-equal to 255 HMAC tags.
expand :: proc(algorithm: hash.Algorithm, prk, info, dst: []byte) {
h_len := hash.DIGEST_SIZES[algorithm]
// (<= 255*HashLen)
dk_len := len(dst)
switch {
case dk_len == 0:
return
case dk_len > h_len * 255:
panic("crypto/hkdf: derived key too long")
case:
}
// The output OKM is calculated as follows:
//
// N = ceil(L/HashLen)
// T = T(1) | T(2) | T(3) | ... | T(N)
// OKM = first L octets of T
//
// where:
// T(0) = empty string (zero length)
// T(1) = HMAC-Hash(PRK, T(0) | info | 0x01)
// T(2) = HMAC-Hash(PRK, T(1) | info | 0x02)
// T(3) = HMAC-Hash(PRK, T(2) | info | 0x03)
// ...
n := dk_len / h_len
r := dk_len % h_len
base: hmac.Context
defer hmac.reset(&base)
hmac.init(&base, algorithm, prk)
dst_blk := dst
prev: []byte
for i in 1 ..= n {
_F(&base, prev, info, i, dst_blk[:h_len])
prev = dst_blk[:h_len]
dst_blk = dst_blk[h_len:]
}
if r > 0 {
tmp: [hash.MAX_DIGEST_SIZE]byte
blk := tmp[:h_len]
defer mem.zero_explicit(raw_data(blk), h_len)
_F(&base, prev, info, n + 1, blk)
copy(dst_blk, blk)
}
}
@(private)
_F :: proc(base: ^hmac.Context, prev, info: []byte, i: int, dst_blk: []byte) {
prf: hmac.Context
hmac.clone(&prf, base)
hmac.update(&prf, prev)
hmac.update(&prf, info)
hmac.update(&prf, []byte{u8(i)})
hmac.final(&prf, dst_blk)
}
+174
View File
@@ -0,0 +1,174 @@
/*
package hmac implements the HMAC MAC algorithm.
See:
- https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.198-1.pdf
*/
package hmac
import "core:crypto"
import "core:crypto/hash"
import "core:mem"
// sum will compute the HMAC with the specified algorithm and key
// over msg, and write the computed tag to dst. It requires that
// the dst buffer is the tag size.
sum :: proc(algorithm: hash.Algorithm, dst, msg, key: []byte) {
ctx: Context
init(&ctx, algorithm, key)
update(&ctx, msg)
final(&ctx, dst)
}
// verify will verify the HMAC tag computed with the specified algorithm
// and key over msg and return true iff the tag is valid. It requires
// that the tag is correctly sized.
verify :: proc(algorithm: hash.Algorithm, tag, msg, key: []byte) -> bool {
tag_buf: [hash.MAX_DIGEST_SIZE]byte
derived_tag := tag_buf[:hash.DIGEST_SIZES[algorithm]]
sum(algorithm, derived_tag, msg, key)
return crypto.compare_constant_time(derived_tag, tag) == 1
}
// Context is a concrete instantiation of HMAC with a specific hash
// algorithm.
Context :: struct {
_o_hash: hash.Context, // H(k ^ ipad) (not finalized)
_i_hash: hash.Context, // H(k ^ opad) (not finalized)
_tag_sz: int,
_is_initialized: bool,
}
// init initializes a Context with a specific hash Algorithm and key.
init :: proc(ctx: ^Context, algorithm: hash.Algorithm, key: []byte) {
if ctx._is_initialized {
reset(ctx)
}
_init_hashes(ctx, algorithm, key)
ctx._tag_sz = hash.DIGEST_SIZES[algorithm]
ctx._is_initialized = true
}
// update adds more data to the Context.
update :: proc(ctx: ^Context, data: []byte) {
assert(ctx._is_initialized)
hash.update(&ctx._i_hash, data)
}
// final finalizes the Context, writes the tag to dst, and calls
// reset on the Context.
final :: proc(ctx: ^Context, dst: []byte) {
assert(ctx._is_initialized)
defer (reset(ctx))
if len(dst) != ctx._tag_sz {
panic("crypto/hmac: invalid destination tag size")
}
hash.final(&ctx._i_hash, dst) // H((k ^ ipad) || text)
hash.update(&ctx._o_hash, dst) // H((k ^ opad) || H((k ^ ipad) || text))
hash.final(&ctx._o_hash, dst)
}
// clone clones the Context other into ctx.
clone :: proc(ctx, other: ^Context) {
if ctx == other {
return
}
hash.clone(&ctx._o_hash, &other._o_hash)
hash.clone(&ctx._i_hash, &other._i_hash)
ctx._tag_sz = other._tag_sz
ctx._is_initialized = other._is_initialized
}
// reset sanitizes the Context. The Context must be re-initialized to
// be used again.
reset :: proc(ctx: ^Context) {
if !ctx._is_initialized {
return
}
hash.reset(&ctx._o_hash)
hash.reset(&ctx._i_hash)
ctx._tag_sz = 0
ctx._is_initialized = false
}
// algorithm returns the Algorithm used by a Context instance.
algorithm :: proc(ctx: ^Context) -> hash.Algorithm {
assert(ctx._is_initialized)
return hash.algorithm(&ctx._i_hash)
}
// tag_size returns the tag size of a Context instance in bytes.
tag_size :: proc(ctx: ^Context) -> int {
assert(ctx._is_initialized)
return ctx._tag_sz
}
@(private)
_I_PAD :: 0x36
_O_PAD :: 0x5c
@(private)
_init_hashes :: proc(ctx: ^Context, algorithm: hash.Algorithm, key: []byte) {
K0_buf: [hash.MAX_BLOCK_SIZE]byte
kPad_buf: [hash.MAX_BLOCK_SIZE]byte
kLen := len(key)
B := hash.BLOCK_SIZES[algorithm]
K0 := K0_buf[:B]
defer mem.zero_explicit(raw_data(K0), B)
switch {
case kLen == B, kLen < B:
// If the length of K = B: set K0 = K.
//
// If the length of K < B: append zeros to the end of K to
// create a B-byte string K0 (e.g., if K is 20 bytes in
// length and B = 64, then K will be appended with 44 zero
// bytes x00).
//
// K0 is zero-initialized, so the copy handles both cases.
copy(K0, key)
case kLen > B:
// If the length of K > B: hash K to obtain an L byte string,
// then append (B-L) zeros to create a B-byte string K0
// (i.e., K0 = H(K) || 00...00).
tmpCtx := &ctx._o_hash // Saves allocating a hash.Context.
hash.init(tmpCtx, algorithm)
hash.update(tmpCtx, key)
hash.final(tmpCtx, K0)
}
// Initialize the hashes, and write the padded keys:
// - ctx._i_hash -> H(K0 ^ ipad)
// - ctx._o_hash -> H(K0 ^ opad)
hash.init(&ctx._o_hash, algorithm)
hash.init(&ctx._i_hash, algorithm)
kPad := kPad_buf[:B]
defer mem.zero_explicit(raw_data(kPad), B)
for v, i in K0 {
kPad[i] = v ~ _I_PAD
}
hash.update(&ctx._i_hash, kPad)
for v, i in K0 {
kPad[i] = v ~ _O_PAD
}
hash.update(&ctx._o_hash, kPad)
}
+116
View File
@@ -0,0 +1,116 @@
/*
package kmac implements the KMAC MAC algorithm.
See:
- https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-185.pdf
*/
package kmac
import "../_sha3"
import "core:crypto"
import "core:crypto/shake"
// MIN_KEY_SIZE_128 is the minimum key size for KMAC128 in bytes.
MIN_KEY_SIZE_128 :: 128 / 8
// MIN_KEY_SIZE_256 is the minimum key size for KMAC256 in bytes.
MIN_KEY_SIZE_256 :: 256 / 8
// MIN_TAG_SIZE is the absolute minimum tag size for KMAC in bytes (8.4.2).
// Most callers SHOULD use at least 128-bits if not 256-bits for the tag
// size.
MIN_TAG_SIZE :: 32 / 8
// sum will compute the KMAC with the specified security strength,
// key, and domain separator over msg, and write the computed digest to
// dst.
sum :: proc(sec_strength: int, dst, msg, key, domain_sep: []byte) {
ctx: Context
_init_kmac(&ctx, key, domain_sep, sec_strength)
update(&ctx, msg)
final(&ctx, dst)
}
// verify will verify the KMAC tag computed with the specified security
// strength, key and domain separator over msg and return true iff the
// tag is valid.
verify :: proc(sec_strength: int, tag, msg, key, domain_sep: []byte, allocator := context.temp_allocator) -> bool {
derived_tag := make([]byte, len(tag), allocator)
sum(sec_strength, derived_tag, msg, key, domain_sep)
return crypto.compare_constant_time(derived_tag, tag) == 1
}
// Context is a KMAC instance.
Context :: distinct shake.Context
// init_128 initializes a Context for KMAC28. This routine will panic if
// the key length is less than MIN_KEY_SIZE_128.
init_128 :: proc(ctx: ^Context, key, domain_sep: []byte) {
_init_kmac(ctx, key, domain_sep, 128)
}
// init_256 initializes a Context for KMAC256. This routine will panic if
// the key length is less than MIN_KEY_SIZE_256.
init_256 :: proc(ctx: ^Context, key, domain_sep: []byte) {
_init_kmac(ctx, key, domain_sep, 256)
}
// update adds more data to the Context.
update :: proc(ctx: ^Context, data: []byte) {
assert(ctx.is_initialized)
shake.write(transmute(^shake.Context)(ctx), data)
}
// final finalizes the Context, writes the tag to dst, and calls reset
// on the Context. This routine will panic if the dst length is less than
// MIN_TAG_SIZE.
final :: proc(ctx: ^Context, dst: []byte) {
assert(ctx.is_initialized)
defer reset(ctx)
if len(dst) < MIN_TAG_SIZE {
panic("crypto/kmac: invalid KMAC tag_size, too short")
}
_sha3.final_cshake(transmute(^_sha3.Context)(ctx), dst)
}
// clone clones the Context other into ctx.
clone :: proc(ctx, other: ^Context) {
if ctx == other {
return
}
shake.clone(transmute(^shake.Context)(ctx), transmute(^shake.Context)(other))
}
// reset sanitizes the Context. The Context must be re-initialized to
// be used again.
reset :: proc(ctx: ^Context) {
if !ctx.is_initialized {
return
}
shake.reset(transmute(^shake.Context)(ctx))
}
@(private)
_init_kmac :: proc(ctx: ^Context, key, s: []byte, sec_strength: int) {
if ctx.is_initialized {
reset(ctx)
}
if len(key) < sec_strength / 8 {
panic("crypto/kmac: invalid KMAC key, too short")
}
ctx_ := transmute(^_sha3.Context)(ctx)
_sha3.init_cshake(ctx_, N_KMAC, s, sec_strength)
_sha3.bytepad(ctx_, [][]byte{key}, _sha3.rate_cshake(sec_strength))
}
@(private)
N_KMAC := []byte{'K', 'M', 'A', 'C'}
+59 -341
View File
@@ -1,3 +1,11 @@
/*
package keccak implements the Keccak hash algorithm family.
During the SHA-3 standardization process, the padding scheme was changed
thus Keccac and SHA-3 produce different outputs. Most users should use
SHA-3 and/or SHAKE instead, however the legacy algorithm is provided for
backward compatibility purposes.
*/
package keccak
/*
@@ -6,372 +14,82 @@ package keccak
List of contributors:
zhibog, dotbmp: Initial implementation.
Interface for the Keccak hashing algorithm.
This is done because the padding in the SHA3 standard was changed by the NIST, resulting in a different output.
*/
import "core:io"
import "core:os"
import "../../_sha3"
/*
High level API
*/
// DIGEST_SIZE_224 is the Keccak-224 digest size.
DIGEST_SIZE_224 :: 28
// DIGEST_SIZE_256 is the Keccak-256 digest size.
DIGEST_SIZE_256 :: 32
// DIGEST_SIZE_384 is the Keccak-384 digest size.
DIGEST_SIZE_384 :: 48
// DIGEST_SIZE_512 is the Keccak-512 digest size.
DIGEST_SIZE_512 :: 64
// hash_string_224 will hash the given input and return the
// computed hash
hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte {
return hash_bytes_224(transmute([]byte)(data))
}
// BLOCK_SIZE_224 is the Keccak-224 block size in bytes.
BLOCK_SIZE_224 :: _sha3.RATE_224
// BLOCK_SIZE_256 is the Keccak-256 block size in bytes.
BLOCK_SIZE_256 :: _sha3.RATE_256
// BLOCK_SIZE_384 is the Keccak-384 block size in bytes.
BLOCK_SIZE_384 :: _sha3.RATE_384
// BLOCK_SIZE_512 is the Keccak-512 block size in bytes.
BLOCK_SIZE_512 :: _sha3.RATE_512
// hash_bytes_224 will hash the given input and return the
// computed hash
hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
hash: [DIGEST_SIZE_224]byte
ctx: Context
// Context is a Keccak instance.
Context :: distinct _sha3.Context
// init_224 initializes a Context for Keccak-224.
init_224 :: proc(ctx: ^Context) {
ctx.mdlen = DIGEST_SIZE_224
ctx.is_keccak = true
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
_init(ctx)
}
// hash_string_to_buffer_224 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_224 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_224 :: proc(data, hash: []byte) {
ctx: Context
ctx.mdlen = DIGEST_SIZE_224
ctx.is_keccak = true
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_224 will read the stream in chunks and compute a
// hash from its contents
hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) {
hash: [DIGEST_SIZE_224]byte
ctx: Context
ctx.mdlen = DIGEST_SIZE_224
ctx.is_keccak = true
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_224 will read the file provided by the given handle
// and compute a hash
hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) {
if !load_at_once {
return hash_stream_224(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_224(buf[:]), ok
}
}
return [DIGEST_SIZE_224]byte{}, false
}
hash_224 :: proc {
hash_stream_224,
hash_file_224,
hash_bytes_224,
hash_string_224,
hash_bytes_to_buffer_224,
hash_string_to_buffer_224,
}
// hash_string_256 will hash the given input and return the
// computed hash
hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
return hash_bytes_256(transmute([]byte)(data))
}
// hash_bytes_256 will hash the given input and return the
// computed hash
hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
hash: [DIGEST_SIZE_256]byte
ctx: Context
// init_256 initializes a Context for Keccak-256.
init_256 :: proc(ctx: ^Context) {
ctx.mdlen = DIGEST_SIZE_256
ctx.is_keccak = true
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
_init(ctx)
}
// hash_string_to_buffer_256 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_256 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
ctx: Context
ctx.mdlen = DIGEST_SIZE_256
ctx.is_keccak = true
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_256 will read the stream in chunks and compute a
// hash from its contents
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
hash: [DIGEST_SIZE_256]byte
ctx: Context
ctx.mdlen = DIGEST_SIZE_256
ctx.is_keccak = true
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_256 will read the file provided by the given handle
// and compute a hash
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
if !load_at_once {
return hash_stream_256(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_256(buf[:]), ok
}
}
return [DIGEST_SIZE_256]byte{}, false
}
hash_256 :: proc {
hash_stream_256,
hash_file_256,
hash_bytes_256,
hash_string_256,
hash_bytes_to_buffer_256,
hash_string_to_buffer_256,
}
// hash_string_384 will hash the given input and return the
// computed hash
hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte {
return hash_bytes_384(transmute([]byte)(data))
}
// hash_bytes_384 will hash the given input and return the
// computed hash
hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
hash: [DIGEST_SIZE_384]byte
ctx: Context
// init_384 initializes a Context for Keccak-384.
init_384 :: proc(ctx: ^Context) {
ctx.mdlen = DIGEST_SIZE_384
ctx.is_keccak = true
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
_init(ctx)
}
// hash_string_to_buffer_384 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_384 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_384 :: proc(data, hash: []byte) {
ctx: Context
ctx.mdlen = DIGEST_SIZE_384
ctx.is_keccak = true
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_384 will read the stream in chunks and compute a
// hash from its contents
hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) {
hash: [DIGEST_SIZE_384]byte
ctx: Context
ctx.mdlen = DIGEST_SIZE_384
ctx.is_keccak = true
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_384 will read the file provided by the given handle
// and compute a hash
hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) {
if !load_at_once {
return hash_stream_384(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_384(buf[:]), ok
}
}
return [DIGEST_SIZE_384]byte{}, false
}
hash_384 :: proc {
hash_stream_384,
hash_file_384,
hash_bytes_384,
hash_string_384,
hash_bytes_to_buffer_384,
hash_string_to_buffer_384,
}
// hash_string_512 will hash the given input and return the
// computed hash
hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte {
return hash_bytes_512(transmute([]byte)(data))
}
// hash_bytes_512 will hash the given input and return the
// computed hash
hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
hash: [DIGEST_SIZE_512]byte
ctx: Context
// init_512 initializes a Context for Keccak-512.
init_512 :: proc(ctx: ^Context) {
ctx.mdlen = DIGEST_SIZE_512
ctx.is_keccak = true
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
_init(ctx)
}
// hash_string_to_buffer_512 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_512 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
ctx: Context
ctx.mdlen = DIGEST_SIZE_512
ctx.is_keccak = true
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_512 will read the stream in chunks and compute a
// hash from its contents
hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
hash: [DIGEST_SIZE_512]byte
ctx: Context
ctx.mdlen = DIGEST_SIZE_512
ctx.is_keccak = true
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_512 will read the file provided by the given handle
// and compute a hash
hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
if !load_at_once {
return hash_stream_512(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_512(buf[:]), ok
}
}
return [DIGEST_SIZE_512]byte{}, false
}
hash_512 :: proc {
hash_stream_512,
hash_file_512,
hash_bytes_512,
hash_string_512,
hash_bytes_to_buffer_512,
hash_string_to_buffer_512,
}
/*
Low level API
*/
Context :: _sha3.Sha3_Context
init :: proc(ctx: ^Context) {
ctx.is_keccak = true
_sha3.init(ctx)
@(private)
_init :: proc(ctx: ^Context) {
ctx.dsbyte = _sha3.DS_KECCAK
_sha3.init(transmute(^_sha3.Context)(ctx))
}
// update adds more data to the Context.
update :: proc(ctx: ^Context, data: []byte) {
_sha3.update(ctx, data)
_sha3.update(transmute(^_sha3.Context)(ctx), data)
}
final :: proc(ctx: ^Context, hash: []byte) {
_sha3.final(ctx, hash)
// final finalizes the Context, writes the digest to hash, and calls
// reset on the Context.
//
// Iff finalize_clone is set, final will work on a copy of the Context,
// which is useful for for calculating rolling digests.
final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) {
_sha3.final(transmute(^_sha3.Context)(ctx), hash, finalize_clone)
}
// clone clones the Context other into ctx.
clone :: proc(ctx, other: ^Context) {
_sha3.clone(transmute(^_sha3.Context)(ctx), transmute(^_sha3.Context)(other))
}
// reset sanitizes the Context. The Context must be re-initialized to
// be used again.
reset :: proc(ctx: ^Context) {
_sha3.reset(transmute(^_sha3.Context)(ctx))
}
+52 -100
View File
@@ -1,3 +1,13 @@
/*
package md5 implements the MD5 hash algorithm.
WARNING: The MD5 algorithm is known to be insecure and should only be
used for interoperating with legacy applications.
See:
- https://eprint.iacr.org/2005/075
- https://datatracker.ietf.org/doc/html/rfc1321
*/
package md5
/*
@@ -6,103 +16,29 @@ package md5
List of contributors:
zhibog, dotbmp: Initial implementation.
Implementation of the MD5 hashing algorithm, as defined in RFC 1321 <https://datatracker.ietf.org/doc/html/rfc1321>
*/
import "core:encoding/endian"
import "core:io"
import "core:math/bits"
import "core:mem"
import "core:os"
/*
High level API
*/
// DIGEST_SIZE is the MD5 digest size in bytes.
DIGEST_SIZE :: 16
// hash_string will hash the given input and return the
// computed hash
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
return hash_bytes(transmute([]byte)(data))
// BLOCK_SIZE is the MD5 block size in bytes.
BLOCK_SIZE :: 64
// Context is a MD5 instance.
Context :: struct {
data: [BLOCK_SIZE]byte,
state: [4]u32,
bitlen: u64,
datalen: u32,
is_initialized: bool,
}
// hash_bytes will hash the given input and return the
// computed hash
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
hash: [DIGEST_SIZE]byte
ctx: Context
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer :: proc(data, hash: []byte) {
ctx: Context
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream will read the stream in chunks and compute a
// hash from its contents
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
hash: [DIGEST_SIZE]byte
ctx: Context
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file will read the file provided by the given handle
// and compute a hash
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
if !load_at_once {
return hash_stream(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes(buf[:]), ok
}
}
return [DIGEST_SIZE]byte{}, false
}
hash :: proc {
hash_stream,
hash_file,
hash_bytes,
hash_string,
hash_bytes_to_buffer,
hash_string_to_buffer,
}
/*
Low level API
*/
// init initializes a Context.
init :: proc(ctx: ^Context) {
ctx.state[0] = 0x67452301
ctx.state[1] = 0xefcdab89
@@ -115,6 +51,7 @@ init :: proc(ctx: ^Context) {
ctx.is_initialized = true
}
// update adds more data to the Context.
update :: proc(ctx: ^Context, data: []byte) {
assert(ctx.is_initialized)
@@ -129,13 +66,26 @@ update :: proc(ctx: ^Context, data: []byte) {
}
}
final :: proc(ctx: ^Context, hash: []byte) {
// final finalizes the Context, writes the digest to hash, and calls
// reset on the Context.
//
// Iff finalize_clone is set, final will work on a copy of the Context,
// which is useful for for calculating rolling digests.
final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) {
assert(ctx.is_initialized)
if len(hash) < DIGEST_SIZE {
panic("crypto/md5: invalid destination digest size")
}
ctx := ctx
if finalize_clone {
tmp_ctx: Context
clone(&tmp_ctx, ctx)
ctx = &tmp_ctx
}
defer(reset(ctx))
i := ctx.datalen
if ctx.datalen < 56 {
@@ -163,25 +113,27 @@ final :: proc(ctx: ^Context, hash: []byte) {
for i = 0; i < DIGEST_SIZE / 4; i += 1 {
endian.unchecked_put_u32le(hash[i * 4:], ctx.state[i])
}
}
ctx.is_initialized = false
// clone clones the Context other into ctx.
clone :: proc(ctx, other: ^$T) {
ctx^ = other^
}
// reset sanitizes the Context. The Context must be re-initialized to
// be used again.
reset :: proc(ctx: ^$T) {
if !ctx.is_initialized {
return
}
mem.zero_explicit(ctx, size_of(ctx^))
}
/*
MD5 implementation
*/
BLOCK_SIZE :: 64
Context :: struct {
data: [BLOCK_SIZE]byte,
state: [4]u32,
bitlen: u64,
datalen: u32,
is_initialized: bool,
}
/*
@note(zh): F, G, H and I, as mentioned in the RFC, have been inlined into FF, GG, HH
and II respectively, instead of declaring them separately.
+54 -101
View File
@@ -1,3 +1,14 @@
/*
package sha1 implements the SHA1 hash algorithm.
WARNING: The SHA1 algorithm is known to be insecure and should only be
used for interoperating with legacy applications.
See:
- https://eprint.iacr.org/2017/190
- https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
- https://datatracker.ietf.org/doc/html/rfc3174
*/
package sha1
/*
@@ -6,103 +17,30 @@ package sha1
List of contributors:
zhibog, dotbmp: Initial implementation.
Implementation of the SHA1 hashing algorithm, as defined in RFC 3174 <https://datatracker.ietf.org/doc/html/rfc3174>
*/
import "core:encoding/endian"
import "core:io"
import "core:math/bits"
import "core:mem"
import "core:os"
/*
High level API
*/
// DIGEST_SIZE is the SHA1 digest size in bytes.
DIGEST_SIZE :: 20
// hash_string will hash the given input and return the
// computed hash
hash_string :: proc(data: string) -> [DIGEST_SIZE]byte {
return hash_bytes(transmute([]byte)(data))
// BLOCK_SIZE is the SHA1 block size in bytes.
BLOCK_SIZE :: 64
// Context is a SHA1 instance.
Context :: struct {
data: [BLOCK_SIZE]byte,
state: [5]u32,
k: [4]u32,
bitlen: u64,
datalen: u32,
is_initialized: bool,
}
// hash_bytes will hash the given input and return the
// computed hash
hash_bytes :: proc(data: []byte) -> [DIGEST_SIZE]byte {
hash: [DIGEST_SIZE]byte
ctx: Context
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer :: proc(data, hash: []byte) {
ctx: Context
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream will read the stream in chunks and compute a
// hash from its contents
hash_stream :: proc(s: io.Stream) -> ([DIGEST_SIZE]byte, bool) {
hash: [DIGEST_SIZE]byte
ctx: Context
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file will read the file provided by the given handle
// and compute a hash
hash_file :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE]byte, bool) {
if !load_at_once {
return hash_stream(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes(buf[:]), ok
}
}
return [DIGEST_SIZE]byte{}, false
}
hash :: proc {
hash_stream,
hash_file,
hash_bytes,
hash_string,
hash_bytes_to_buffer,
hash_string_to_buffer,
}
/*
Low level API
*/
// init initializes a Context.
init :: proc(ctx: ^Context) {
ctx.state[0] = 0x67452301
ctx.state[1] = 0xefcdab89
@@ -120,6 +58,7 @@ init :: proc(ctx: ^Context) {
ctx.is_initialized = true
}
// update adds more data to the Context.
update :: proc(ctx: ^Context, data: []byte) {
assert(ctx.is_initialized)
@@ -134,13 +73,26 @@ update :: proc(ctx: ^Context, data: []byte) {
}
}
final :: proc(ctx: ^Context, hash: []byte) {
// final finalizes the Context, writes the digest to hash, and calls
// reset on the Context.
//
// Iff finalize_clone is set, final will work on a copy of the Context,
// which is useful for for calculating rolling digests.
final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) {
assert(ctx.is_initialized)
if len(hash) < DIGEST_SIZE {
panic("crypto/sha1: invalid destination digest size")
}
ctx := ctx
if finalize_clone {
tmp_ctx: Context
clone(&tmp_ctx, ctx)
ctx = &tmp_ctx
}
defer(reset(ctx))
i := ctx.datalen
if ctx.datalen < 56 {
@@ -168,26 +120,27 @@ final :: proc(ctx: ^Context, hash: []byte) {
for i = 0; i < DIGEST_SIZE / 4; i += 1 {
endian.unchecked_put_u32be(hash[i * 4:], ctx.state[i])
}
}
ctx.is_initialized = false
// clone clones the Context other into ctx.
clone :: proc(ctx, other: ^$T) {
ctx^ = other^
}
// reset sanitizes the Context. The Context must be re-initialized to
// be used again.
reset :: proc(ctx: ^$T) {
if !ctx.is_initialized {
return
}
mem.zero_explicit(ctx, size_of(ctx^))
}
/*
SHA1 implementation
*/
BLOCK_SIZE :: 64
Context :: struct {
data: [BLOCK_SIZE]byte,
datalen: u32,
bitlen: u64,
state: [5]u32,
k: [4]u32,
is_initialized: bool,
}
@(private)
transform :: proc "contextless" (ctx: ^Context, data: []byte) {
a, b, c, d, e, i, t: u32
+122
View File
@@ -0,0 +1,122 @@
/*
package pbkdf2 implements the PBKDF2 password-based key derivation function.
See: https://www.rfc-editor.org/rfc/rfc2898
*/
package pbkdf2
import "core:crypto/hash"
import "core:crypto/hmac"
import "core:encoding/endian"
import "core:mem"
// derive invokes PBKDF2-HMAC with the specified hash algorithm, password,
// salt, iteration count, and outputs the derived key to dst.
derive :: proc(
hmac_hash: hash.Algorithm,
password: []byte,
salt: []byte,
iterations: u32,
dst: []byte,
) {
h_len := hash.DIGEST_SIZES[hmac_hash]
// 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long"
// and stop.
dk_len := len(dst)
switch {
case dk_len == 0:
return
case u64(dk_len) > u64(max(u32)) * u64(h_len):
// This is so beyond anything that is practical or reasonable,
// so just panic instead of returning an error.
panic("crypto/pbkdf2: derived key too long")
case:
}
// 2. Let l be the number of hLen-octet blocks in the derived key,
// rounding up, and let r be the number of octets in the last block.
l := dk_len / h_len // Don't need to round up.
r := dk_len % h_len
// 3. For each block of the derived key apply the function F defined
// below to the password P, the salt S, the iteration count c, and
// the block index to compute the block.
//
// 4. Concatenate the blocks and extract the first dkLen octets to
// produce a derived key DK.
//
// 5. Output the derived key DK.
// Each iteration of F is always `PRF (P, ...)`, so instantiate the
// PRF, and clone since memcpy is faster than having to re-initialize
// HMAC repeatedly.
base: hmac.Context
defer hmac.reset(&base)
hmac.init(&base, hmac_hash, password)
// Process all of the blocks that will be written directly to dst.
dst_blk := dst
for i in 1 ..= l { // F expects i starting at 1.
_F(&base, salt, iterations, u32(i), dst_blk[:h_len])
dst_blk = dst_blk[h_len:]
}
// Instead of rounding l up, just proceass the one extra block iff
// r != 0.
if r > 0 {
tmp: [hash.MAX_DIGEST_SIZE]byte
blk := tmp[:h_len]
defer mem.zero_explicit(raw_data(blk), h_len)
_F(&base, salt, iterations, u32(l + 1), blk)
copy(dst_blk, blk)
}
}
@(private)
_F :: proc(base: ^hmac.Context, salt: []byte, c: u32, i: u32, dst_blk: []byte) {
h_len := len(dst_blk)
tmp: [hash.MAX_DIGEST_SIZE]byte
u := tmp[:h_len]
defer mem.zero_explicit(raw_data(u), h_len)
// F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c
//
// where
//
// U_1 = PRF (P, S || INT (i)) ,
// U_2 = PRF (P, U_1) ,
// ...
// U_c = PRF (P, U_{c-1}) .
//
// Here, INT (i) is a four-octet encoding of the integer i, most
// significant octet first.
prf: hmac.Context
// U_1: PRF (P, S || INT (i))
hmac.clone(&prf, base)
hmac.update(&prf, salt)
endian.unchecked_put_u32be(u, i) // Use u as scratch space.
hmac.update(&prf, u[:4])
hmac.final(&prf, u)
copy(dst_blk, u)
// U_2 ... U_c: U_n = PRF (P, U_(n-1))
for _ in 1 ..< c {
hmac.clone(&prf, base)
hmac.update(&prf, u)
hmac.final(&prf, u)
// XOR dst_blk and u.
for v, i in u {
dst_blk[i] ~= v
}
}
}
+53 -28
View File
@@ -1,17 +1,31 @@
/*
package poly1305 implements the Poly1305 one-time MAC algorithm.
See:
- https://datatracker.ietf.org/doc/html/rfc8439
*/
package poly1305
import "core:crypto"
import field "core:crypto/_fiat/field_poly1305"
import "core:encoding/endian"
import "core:math/bits"
import "core:mem"
// KEY_SIZE is the Poly1305 key size in bytes.
KEY_SIZE :: 32
// TAG_SIZE is the Poly1305 tag size in bytes.
TAG_SIZE :: 16
@(private)
_BLOCK_SIZE :: 16
sum :: proc (dst, msg, key: []byte) {
// sum will compute the Poly1305 MAC with the key over msg, and write
// the computed tag to dst. It requires that the dst buffer is the tag
// size.
//
// The key SHOULD be unique and MUST be unpredictable for each invocation.
sum :: proc(dst, msg, key: []byte) {
ctx: Context = ---
init(&ctx, key)
@@ -19,13 +33,12 @@ sum :: proc (dst, msg, key: []byte) {
final(&ctx, dst)
}
verify :: proc (tag, msg, key: []byte) -> bool {
// verify will verify the Poly1305 tag computed with the key over msg and
// return true iff the tag is valid. It requires that the tag is correctly
// sized.
verify :: proc(tag, msg, key: []byte) -> bool {
ctx: Context = ---
derived_tag: [16]byte = ---
if len(tag) != TAG_SIZE {
panic("crypto/poly1305: invalid tag size")
}
derived_tag: [TAG_SIZE]byte = ---
init(&ctx, key)
update(&ctx, msg)
@@ -34,18 +47,19 @@ verify :: proc (tag, msg, key: []byte) -> bool {
return crypto.compare_constant_time(derived_tag[:], tag) == 1
}
// Context is a Poly1305 instance.
Context :: struct {
_r: field.Tight_Field_Element,
_a: field.Tight_Field_Element,
_s: field.Tight_Field_Element,
_buffer: [_BLOCK_SIZE]byte,
_leftover: int,
_r: field.Tight_Field_Element,
_a: field.Tight_Field_Element,
_s: [2]u64,
_buffer: [_BLOCK_SIZE]byte,
_leftover: int,
_is_initialized: bool,
}
init :: proc (ctx: ^Context, key: []byte) {
// init initializes a Context with the specified key. The key SHOULD be
// unique and MUST be unpredictable for each invocation.
init :: proc(ctx: ^Context, key: []byte) {
if len(key) != KEY_SIZE {
panic("crypto/poly1305: invalid key size")
}
@@ -53,11 +67,12 @@ init :: proc (ctx: ^Context, key: []byte) {
// r = le_bytes_to_num(key[0..15])
// r = clamp(r) (r &= 0xffffffc0ffffffc0ffffffc0fffffff)
tmp_lo := endian.unchecked_get_u64le(key[0:]) & 0x0ffffffc0fffffff
tmp_hi := endian.unchecked_get_u64le(key[8:]) & 0xffffffc0ffffffc
tmp_hi := endian.unchecked_get_u64le(key[8:]) & 0x0ffffffc0ffffffc
field.fe_from_u64s(&ctx._r, tmp_lo, tmp_hi)
// s = le_bytes_to_num(key[16..31])
field.fe_from_bytes(&ctx._s, key[16:32], 0)
ctx._s[0] = endian.unchecked_get_u64le(key[16:])
ctx._s[1] = endian.unchecked_get_u64le(key[24:])
// a = 0
field.fe_zero(&ctx._a)
@@ -68,7 +83,8 @@ init :: proc (ctx: ^Context, key: []byte) {
ctx._is_initialized = true
}
update :: proc (ctx: ^Context, data: []byte) {
// update adds more data to the Context.
update :: proc(ctx: ^Context, data: []byte) {
assert(ctx._is_initialized)
msg := data
@@ -105,8 +121,11 @@ update :: proc (ctx: ^Context, data: []byte) {
}
}
final :: proc (ctx: ^Context, dst: []byte) {
// final finalizes the Context, writes the tag to dst, and calls
// reset on the Context.
final :: proc(ctx: ^Context, dst: []byte) {
assert(ctx._is_initialized)
defer reset(ctx)
if len(dst) != TAG_SIZE {
panic("poly1305: invalid destination tag size")
@@ -121,19 +140,25 @@ final :: proc (ctx: ^Context, dst: []byte) {
_blocks(ctx, ctx._buffer[:], true)
}
// a += s
field.fe_add(field.fe_relax_cast(&ctx._a), &ctx._a, &ctx._s) // _a unreduced
field.fe_carry(&ctx._a, field.fe_relax_cast(&ctx._a)) // _a reduced
// return num_to_16_le_bytes(a)
// a += s (NOT mod p)
tmp: [32]byte = ---
field.fe_to_bytes(&tmp, &ctx._a)
copy_slice(dst, tmp[0:16])
reset(ctx)
c: u64
lo := endian.unchecked_get_u64le(tmp[0:])
hi := endian.unchecked_get_u64le(tmp[8:])
lo, c = bits.add_u64(lo, ctx._s[0], 0)
hi, _ = bits.add_u64(hi, ctx._s[1], c)
// return num_to_16_le_bytes(a)
endian.unchecked_put_u64le(dst[0:], lo)
endian.unchecked_put_u64le(dst[8:], hi)
}
reset :: proc (ctx: ^Context) {
// reset sanitizes the Context. The Context must be re-initialized to
// be used again.
reset :: proc(ctx: ^Context) {
mem.zero_explicit(&ctx._r, size_of(ctx._r))
mem.zero_explicit(&ctx._a, size_of(ctx._a))
mem.zero_explicit(&ctx._s, size_of(ctx._s))
@@ -143,7 +168,7 @@ reset :: proc (ctx: ^Context) {
}
@(private)
_blocks :: proc (ctx: ^Context, msg: []byte, final := false) {
_blocks :: proc(ctx: ^Context, msg: []byte, final := false) {
n: field.Tight_Field_Element = ---
final_byte := byte(!final)
+12
View File
@@ -0,0 +1,12 @@
//+build freebsd, openbsd
package crypto
foreign import libc "system:c"
foreign libc {
arc4random_buf :: proc(buf: [^]byte, nbytes: uint) ---
}
_rand_bytes :: proc(dst: []byte) {
arc4random_buf(raw_data(dst), len(dst))
}
+12
View File
@@ -0,0 +1,12 @@
package crypto
import "core:fmt"
import "core:sys/darwin"
_rand_bytes :: proc(dst: []byte) {
res := darwin.SecRandomCopyBytes(count=len(dst), bytes=raw_data(dst))
if res != .Success {
msg := darwin.CFStringCopyToOdinString(darwin.SecCopyErrorMessageString(res))
panic(fmt.tprintf("crypto/rand_bytes: SecRandomCopyBytes returned non-zero result: %v %s", res, msg))
}
}
+8 -4
View File
@@ -1,7 +1,11 @@
//+build !linux
//+build !windows
//+build !openbsd
//+build !freebsd
//+build !darwin
//+build !js
package crypto
when ODIN_OS != .Linux && ODIN_OS != .OpenBSD && ODIN_OS != .Windows && ODIN_OS != .JS {
_rand_bytes :: proc(dst: []byte) {
unimplemented("crypto: rand_bytes not supported on this OS")
}
_rand_bytes :: proc(dst: []byte) {
unimplemented("crypto: rand_bytes not supported on this OS")
}
-12
View File
@@ -1,12 +0,0 @@
package crypto
import "core:c"
foreign import libc "system:c"
foreign libc {
arc4random_buf :: proc "c" (buf: rawptr, nbytes: c.size_t) ---
}
_rand_bytes :: proc (dst: []byte) {
arc4random_buf(raw_data(dst), len(dst))
}
+92 -429
View File
@@ -1,3 +1,10 @@
/*
package sha2 implements the SHA2 hash algorithm family.
See:
- https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf
- https://datatracker.ietf.org/doc/html/rfc3874
*/
package sha2
/*
@@ -6,431 +13,83 @@ package sha2
List of contributors:
zhibog, dotbmp: Initial implementation.
Implementation of the SHA2 hashing algorithm, as defined in <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf>
and in RFC 3874 <https://datatracker.ietf.org/doc/html/rfc3874>
*/
import "core:encoding/endian"
import "core:io"
import "core:math/bits"
import "core:os"
/*
High level API
*/
import "core:mem"
// DIGEST_SIZE_224 is the SHA-224 digest size in bytes.
DIGEST_SIZE_224 :: 28
// DIGEST_SIZE_256 is the SHA-256 digest size in bytes.
DIGEST_SIZE_256 :: 32
// DIGEST_SIZE_384 is the SHA-384 digest size in bytes.
DIGEST_SIZE_384 :: 48
// DIGEST_SIZE_512 is the SHA-512 digest size in bytes.
DIGEST_SIZE_512 :: 64
// DIGEST_SIZE_512_256 is the SHA-512/256 digest size in bytes.
DIGEST_SIZE_512_256 :: 32
// hash_string_224 will hash the given input and return the
// computed hash
hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte {
return hash_bytes_224(transmute([]byte)(data))
// BLOCK_SIZE_256 is the SHA-224 and SHA-256 block size in bytes.
BLOCK_SIZE_256 :: 64
// BLOCK_SIZE_512 is the SHA-384, SHA-512, and SHA-512/256 block size
// in bytes.
BLOCK_SIZE_512 :: 128
// Context_256 is a SHA-224 or SHA-256 instance.
Context_256 :: struct {
block: [BLOCK_SIZE_256]byte,
h: [8]u32,
bitlength: u64,
length: u64,
md_bits: int,
is_initialized: bool,
}
// hash_bytes_224 will hash the given input and return the
// computed hash
hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
hash: [DIGEST_SIZE_224]byte
ctx: Context_256
// Context_512 is a SHA-384, SHA-512 or SHA-512/256 instance.
Context_512 :: struct {
block: [BLOCK_SIZE_512]byte,
h: [8]u64,
bitlength: u64,
length: u64,
md_bits: int,
is_initialized: bool,
}
// init_224 initializes a Context_256 for SHA-224.
init_224 :: proc(ctx: ^Context_256) {
ctx.md_bits = 224
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
_init(ctx)
}
// hash_string_to_buffer_224 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_224 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_224 :: proc(data, hash: []byte) {
ctx: Context_256
ctx.md_bits = 224
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_224 will read the stream in chunks and compute a
// hash from its contents
hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) {
hash: [DIGEST_SIZE_224]byte
ctx: Context_256
ctx.md_bits = 224
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_224 will read the file provided by the given handle
// and compute a hash
hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) {
if !load_at_once {
return hash_stream_224(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_224(buf[:]), ok
}
}
return [DIGEST_SIZE_224]byte{}, false
}
hash_224 :: proc {
hash_stream_224,
hash_file_224,
hash_bytes_224,
hash_string_224,
hash_bytes_to_buffer_224,
hash_string_to_buffer_224,
}
// hash_string_256 will hash the given input and return the
// computed hash
hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
return hash_bytes_256(transmute([]byte)(data))
}
// hash_bytes_256 will hash the given input and return the
// computed hash
hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
hash: [DIGEST_SIZE_256]byte
ctx: Context_256
// init_256 initializes a Context_256 for SHA-256.
init_256 :: proc(ctx: ^Context_256) {
ctx.md_bits = 256
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
_init(ctx)
}
// hash_string_to_buffer_256 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_256 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
ctx: Context_256
ctx.md_bits = 256
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_256 will read the stream in chunks and compute a
// hash from its contents
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
hash: [DIGEST_SIZE_256]byte
ctx: Context_256
ctx.md_bits = 256
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_256 will read the file provided by the given handle
// and compute a hash
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
if !load_at_once {
return hash_stream_256(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_256(buf[:]), ok
}
}
return [DIGEST_SIZE_256]byte{}, false
}
hash_256 :: proc {
hash_stream_256,
hash_file_256,
hash_bytes_256,
hash_string_256,
hash_bytes_to_buffer_256,
hash_string_to_buffer_256,
}
// hash_string_384 will hash the given input and return the
// computed hash
hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte {
return hash_bytes_384(transmute([]byte)(data))
}
// hash_bytes_384 will hash the given input and return the
// computed hash
hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
hash: [DIGEST_SIZE_384]byte
ctx: Context_512
// init_384 initializes a Context_512 for SHA-384.
init_384 :: proc(ctx: ^Context_512) {
ctx.md_bits = 384
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
_init(ctx)
}
// hash_string_to_buffer_384 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_384 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_384 :: proc(data, hash: []byte) {
ctx: Context_512
ctx.md_bits = 384
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_384 will read the stream in chunks and compute a
// hash from its contents
hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) {
hash: [DIGEST_SIZE_384]byte
ctx: Context_512
ctx.md_bits = 384
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_384 will read the file provided by the given handle
// and compute a hash
hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) {
if !load_at_once {
return hash_stream_384(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_384(buf[:]), ok
}
}
return [DIGEST_SIZE_384]byte{}, false
}
hash_384 :: proc {
hash_stream_384,
hash_file_384,
hash_bytes_384,
hash_string_384,
hash_bytes_to_buffer_384,
hash_string_to_buffer_384,
}
// hash_string_512 will hash the given input and return the
// computed hash
hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte {
return hash_bytes_512(transmute([]byte)(data))
}
// hash_bytes_512 will hash the given input and return the
// computed hash
hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
hash: [DIGEST_SIZE_512]byte
ctx: Context_512
// init_512 initializes a Context_512 for SHA-512.
init_512 :: proc(ctx: ^Context_512) {
ctx.md_bits = 512
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
_init(ctx)
}
// hash_string_to_buffer_512 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_512 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
ctx: Context_512
ctx.md_bits = 512
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_512 will read the stream in chunks and compute a
// hash from its contents
hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
hash: [DIGEST_SIZE_512]byte
ctx: Context_512
ctx.md_bits = 512
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_512 will read the file provided by the given handle
// and compute a hash
hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
if !load_at_once {
return hash_stream_512(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_512(buf[:]), ok
}
}
return [DIGEST_SIZE_512]byte{}, false
}
hash_512 :: proc {
hash_stream_512,
hash_file_512,
hash_bytes_512,
hash_string_512,
hash_bytes_to_buffer_512,
hash_string_to_buffer_512,
}
// hash_string_512_256 will hash the given input and return the
// computed hash
hash_string_512_256 :: proc(data: string) -> [DIGEST_SIZE_512_256]byte {
return hash_bytes_512_256(transmute([]byte)(data))
}
// hash_bytes_512_256 will hash the given input and return the
// computed hash
hash_bytes_512_256 :: proc(data: []byte) -> [DIGEST_SIZE_512_256]byte {
hash: [DIGEST_SIZE_512_256]byte
ctx: Context_512
// init_512_256 initializes a Context_512 for SHA-512/256.
init_512_256 :: proc(ctx: ^Context_512) {
ctx.md_bits = 256
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
_init(ctx)
}
// hash_string_to_buffer_512_256 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_512_256 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_512_256(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_512_256 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_512_256 :: proc(data, hash: []byte) {
ctx: Context_512
ctx.md_bits = 256
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_512_256 will read the stream in chunks and compute a
// hash from its contents
hash_stream_512_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512_256]byte, bool) {
hash: [DIGEST_SIZE_512_256]byte
ctx: Context_512
ctx.md_bits = 256
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_512_256 will read the file provided by the given handle
// and compute a hash
hash_file_512_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512_256]byte, bool) {
if !load_at_once {
return hash_stream_512_256(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_512_256(buf[:]), ok
}
}
return [DIGEST_SIZE_512_256]byte{}, false
}
hash_512_256 :: proc {
hash_stream_512_256,
hash_file_512_256,
hash_bytes_512_256,
hash_string_512_256,
hash_bytes_to_buffer_512_256,
hash_string_to_buffer_512_256,
}
/*
Low level API
*/
init :: proc(ctx: ^$T) {
@(private)
_init :: proc(ctx: ^$T) {
when T == Context_256 {
switch ctx.md_bits {
case 224:
@@ -497,13 +156,14 @@ init :: proc(ctx: ^$T) {
ctx.is_initialized = true
}
// update adds more data to the Context.
update :: proc(ctx: ^$T, data: []byte) {
assert(ctx.is_initialized)
when T == Context_256 {
CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE
CURR_BLOCK_SIZE :: BLOCK_SIZE_256
} else when T == Context_512 {
CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE
CURR_BLOCK_SIZE :: BLOCK_SIZE_512
}
data := data
@@ -528,21 +188,34 @@ update :: proc(ctx: ^$T, data: []byte) {
}
}
final :: proc(ctx: ^$T, hash: []byte) {
// final finalizes the Context, writes the digest to hash, and calls
// reset on the Context.
//
// Iff finalize_clone is set, final will work on a copy of the Context,
// which is useful for for calculating rolling digests.
final :: proc(ctx: ^$T, hash: []byte, finalize_clone: bool = false) {
assert(ctx.is_initialized)
if len(hash) * 8 < ctx.md_bits {
panic("crypto/sha2: invalid destination digest size")
}
ctx := ctx
if finalize_clone {
tmp_ctx: T
clone(&tmp_ctx, ctx)
ctx = &tmp_ctx
}
defer(reset(ctx))
length := ctx.length
raw_pad: [SHA512_BLOCK_SIZE]byte
raw_pad: [BLOCK_SIZE_512]byte
when T == Context_256 {
CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE
CURR_BLOCK_SIZE :: BLOCK_SIZE_256
pm_len := 8 // 64-bits for length
} else when T == Context_512 {
CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE
CURR_BLOCK_SIZE :: BLOCK_SIZE_512
pm_len := 16 // 128-bits for length
}
pad := raw_pad[:CURR_BLOCK_SIZE]
@@ -576,37 +249,27 @@ final :: proc(ctx: ^$T, hash: []byte) {
endian.unchecked_put_u64be(hash[i * 8:], ctx.h[i])
}
}
}
ctx.is_initialized = false
// clone clones the Context other into ctx.
clone :: proc(ctx, other: ^$T) {
ctx^ = other^
}
// reset sanitizes the Context. The Context must be re-initialized to
// be used again.
reset :: proc(ctx: ^$T) {
if !ctx.is_initialized {
return
}
mem.zero_explicit(ctx, size_of(ctx^))
}
/*
SHA2 implementation
*/
SHA256_BLOCK_SIZE :: 64
SHA512_BLOCK_SIZE :: 128
Context_256 :: struct {
block: [SHA256_BLOCK_SIZE]byte,
h: [8]u32,
bitlength: u64,
length: u64,
md_bits: int,
is_initialized: bool,
}
Context_512 :: struct {
block: [SHA512_BLOCK_SIZE]byte,
h: [8]u64,
bitlength: u64,
length: u64,
md_bits: int,
is_initialized: bool,
}
@(private)
sha256_k := [64]u32 {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
@@ -737,12 +400,12 @@ sha2_transf :: proc "contextless" (ctx: ^$T, data: []byte) {
w: [64]u32
wv: [8]u32
t1, t2: u32
CURR_BLOCK_SIZE :: SHA256_BLOCK_SIZE
CURR_BLOCK_SIZE :: BLOCK_SIZE_256
} else when T == Context_512 {
w: [80]u64
wv: [8]u64
t1, t2: u64
CURR_BLOCK_SIZE :: SHA512_BLOCK_SIZE
CURR_BLOCK_SIZE :: BLOCK_SIZE_512
}
data := data
+61 -328
View File
@@ -1,3 +1,13 @@
/*
package sha3 implements the SHA3 hash algorithm family.
The SHAKE XOF can be found in crypto/shake. While discouraged if the
pre-standardization Keccak algorithm is required, it can be found in
crypto/legacy/keccak.
See:
- https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf
*/
package sha3
/*
@@ -6,359 +16,82 @@ package sha3
List of contributors:
zhibog, dotbmp: Initial implementation.
Interface for the SHA3 hashing algorithm. The SHAKE functionality can be found in package shake.
If you wish to compute a Keccak hash, you can use the keccak package, it will use the original padding.
*/
import "core:io"
import "core:os"
import "../_sha3"
/*
High level API
*/
// DIGEST_SIZE_224 is the SHA3-224 digest size.
DIGEST_SIZE_224 :: 28
// DIGEST_SIZE_256 is the SHA3-256 digest size.
DIGEST_SIZE_256 :: 32
// DIGEST_SIZE_384 is the SHA3-384 digest size.
DIGEST_SIZE_384 :: 48
// DIGEST_SIZE_512 is the SHA3-512 digest size.
DIGEST_SIZE_512 :: 64
// hash_string_224 will hash the given input and return the
// computed hash
hash_string_224 :: proc(data: string) -> [DIGEST_SIZE_224]byte {
return hash_bytes_224(transmute([]byte)(data))
}
// BLOCK_SIZE_224 is the SHA3-224 block size in bytes.
BLOCK_SIZE_224 :: _sha3.RATE_224
// BLOCK_SIZE_256 is the SHA3-256 block size in bytes.
BLOCK_SIZE_256 :: _sha3.RATE_256
// BLOCK_SIZE_384 is the SHA3-384 block size in bytes.
BLOCK_SIZE_384 :: _sha3.RATE_384
// BLOCK_SIZE_512 is the SHA3-512 block size in bytes.
BLOCK_SIZE_512 :: _sha3.RATE_512
// hash_bytes_224 will hash the given input and return the
// computed hash
hash_bytes_224 :: proc(data: []byte) -> [DIGEST_SIZE_224]byte {
hash: [DIGEST_SIZE_224]byte
ctx: Context
// Context is a SHA3 instance.
Context :: distinct _sha3.Context
// init_224 initializes a Context for SHA3-224.
init_224 :: proc(ctx: ^Context) {
ctx.mdlen = DIGEST_SIZE_224
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
_init(ctx)
}
// hash_string_to_buffer_224 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_224 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_224(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_224 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_224 :: proc(data, hash: []byte) {
ctx: Context
ctx.mdlen = DIGEST_SIZE_224
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_224 will read the stream in chunks and compute a
// hash from its contents
hash_stream_224 :: proc(s: io.Stream) -> ([DIGEST_SIZE_224]byte, bool) {
hash: [DIGEST_SIZE_224]byte
ctx: Context
ctx.mdlen = DIGEST_SIZE_224
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_224 will read the file provided by the given handle
// and compute a hash
hash_file_224 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_224]byte, bool) {
if !load_at_once {
return hash_stream_224(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_224(buf[:]), ok
}
}
return [DIGEST_SIZE_224]byte{}, false
}
hash_224 :: proc {
hash_stream_224,
hash_file_224,
hash_bytes_224,
hash_string_224,
hash_bytes_to_buffer_224,
hash_string_to_buffer_224,
}
// hash_string_256 will hash the given input and return the
// computed hash
hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
return hash_bytes_256(transmute([]byte)(data))
}
// hash_bytes_256 will hash the given input and return the
// computed hash
hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
hash: [DIGEST_SIZE_256]byte
ctx: Context
// init_256 initializes a Context for SHA3-256.
init_256 :: proc(ctx: ^Context) {
ctx.mdlen = DIGEST_SIZE_256
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
_init(ctx)
}
// hash_string_to_buffer_256 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_256 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
ctx: Context
ctx.mdlen = DIGEST_SIZE_256
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_256 will read the stream in chunks and compute a
// hash from its contents
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
hash: [DIGEST_SIZE_256]byte
ctx: Context
ctx.mdlen = DIGEST_SIZE_256
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_256 will read the file provided by the given handle
// and compute a hash
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
if !load_at_once {
return hash_stream_256(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_256(buf[:]), ok
}
}
return [DIGEST_SIZE_256]byte{}, false
}
hash_256 :: proc {
hash_stream_256,
hash_file_256,
hash_bytes_256,
hash_string_256,
hash_bytes_to_buffer_256,
hash_string_to_buffer_256,
}
// hash_string_384 will hash the given input and return the
// computed hash
hash_string_384 :: proc(data: string) -> [DIGEST_SIZE_384]byte {
return hash_bytes_384(transmute([]byte)(data))
}
// hash_bytes_384 will hash the given input and return the
// computed hash
hash_bytes_384 :: proc(data: []byte) -> [DIGEST_SIZE_384]byte {
hash: [DIGEST_SIZE_384]byte
ctx: Context
// init_384 initializes a Context for SHA3-384.
init_384 :: proc(ctx: ^Context) {
ctx.mdlen = DIGEST_SIZE_384
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
_init(ctx)
}
// hash_string_to_buffer_384 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_384 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_384(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_384 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_384 :: proc(data, hash: []byte) {
ctx: Context
ctx.mdlen = DIGEST_SIZE_384
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_384 will read the stream in chunks and compute a
// hash from its contents
hash_stream_384 :: proc(s: io.Stream) -> ([DIGEST_SIZE_384]byte, bool) {
hash: [DIGEST_SIZE_384]byte
ctx: Context
ctx.mdlen = DIGEST_SIZE_384
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_384 will read the file provided by the given handle
// and compute a hash
hash_file_384 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_384]byte, bool) {
if !load_at_once {
return hash_stream_384(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_384(buf[:]), ok
}
}
return [DIGEST_SIZE_384]byte{}, false
}
hash_384 :: proc {
hash_stream_384,
hash_file_384,
hash_bytes_384,
hash_string_384,
hash_bytes_to_buffer_384,
hash_string_to_buffer_384,
}
// hash_string_512 will hash the given input and return the
// computed hash
hash_string_512 :: proc(data: string) -> [DIGEST_SIZE_512]byte {
return hash_bytes_512(transmute([]byte)(data))
}
// hash_bytes_512 will hash the given input and return the
// computed hash
hash_bytes_512 :: proc(data: []byte) -> [DIGEST_SIZE_512]byte {
hash: [DIGEST_SIZE_512]byte
ctx: Context
// init_512 initializes a Context for SHA3-512.
init_512 :: proc(ctx: ^Context) {
ctx.mdlen = DIGEST_SIZE_512
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
_init(ctx)
}
// hash_string_to_buffer_512 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_512 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_512(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_512 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_512 :: proc(data, hash: []byte) {
ctx: Context
ctx.mdlen = DIGEST_SIZE_512
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
}
// hash_stream_512 will read the stream in chunks and compute a
// hash from its contents
hash_stream_512 :: proc(s: io.Stream) -> ([DIGEST_SIZE_512]byte, bool) {
hash: [DIGEST_SIZE_512]byte
ctx: Context
ctx.mdlen = DIGEST_SIZE_512
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_512 will read the file provided by the given handle
// and compute a hash
hash_file_512 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_512]byte, bool) {
if !load_at_once {
return hash_stream_512(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_512(buf[:]), ok
}
}
return [DIGEST_SIZE_512]byte{}, false
}
hash_512 :: proc {
hash_stream_512,
hash_file_512,
hash_bytes_512,
hash_string_512,
hash_bytes_to_buffer_512,
hash_string_to_buffer_512,
}
/*
Low level API
*/
Context :: _sha3.Sha3_Context
init :: proc(ctx: ^Context) {
_sha3.init(ctx)
@(private)
_init :: proc(ctx: ^Context) {
ctx.dsbyte = _sha3.DS_SHA3
_sha3.init(transmute(^_sha3.Context)(ctx))
}
// update adds more data to the Context.
update :: proc(ctx: ^Context, data: []byte) {
_sha3.update(ctx, data)
_sha3.update(transmute(^_sha3.Context)(ctx), data)
}
final :: proc(ctx: ^Context, hash: []byte) {
_sha3.final(ctx, hash)
// final finalizes the Context, writes the digest to hash, and calls
// reset on the Context.
//
// Iff finalize_clone is set, final will work on a copy of the Context,
// which is useful for for calculating rolling digests.
final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) {
_sha3.final(transmute(^_sha3.Context)(ctx), hash, finalize_clone)
}
// clone clones the Context other into ctx.
clone :: proc(ctx, other: ^Context) {
_sha3.clone(transmute(^_sha3.Context)(ctx), transmute(^_sha3.Context)(other))
}
// reset sanitizes the Context. The Context must be re-initialized to
// be used again.
reset :: proc(ctx: ^Context) {
_sha3.reset(transmute(^_sha3.Context)(ctx))
}
+44 -178
View File
@@ -1,3 +1,12 @@
/*
package shake implements the SHAKE and cSHAKE XOF algorithm families.
The SHA3 hash algorithm can be found in the crypto/sha3.
See:
- https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.202.pdf
- https://nvlpubs.nist.gov/nistpubs/specialpublications/nist.sp.800-185.pdf
*/
package shake
/*
@@ -6,201 +15,58 @@ package shake
List of contributors:
zhibog, dotbmp: Initial implementation.
Interface for the SHAKE hashing algorithm.
The SHA3 functionality can be found in package sha3.
TODO: This should provide an incremental squeeze interface, in addition
to the one-shot final call.
*/
import "core:io"
import "core:os"
import "../_sha3"
/*
High level API
*/
// Context is a SHAKE128, SHAKE256, cSHAKE128, or cSHAKE256 instance.
Context :: distinct _sha3.Context
DIGEST_SIZE_128 :: 16
DIGEST_SIZE_256 :: 32
// hash_string_128 will hash the given input and return the
// computed hash
hash_string_128 :: proc(data: string) -> [DIGEST_SIZE_128]byte {
return hash_bytes_128(transmute([]byte)(data))
// init_128 initializes a Context for SHAKE128.
init_128 :: proc(ctx: ^Context) {
_sha3.init_cshake(transmute(^_sha3.Context)(ctx), nil, nil, 128)
}
// hash_bytes_128 will hash the given input and return the
// computed hash
hash_bytes_128 :: proc(data: []byte) -> [DIGEST_SIZE_128]byte {
hash: [DIGEST_SIZE_128]byte
ctx: Context
ctx.mdlen = DIGEST_SIZE_128
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
// init_256 initializes a Context for SHAKE256.
init_256 :: proc(ctx: ^Context) {
_sha3.init_cshake(transmute(^_sha3.Context)(ctx), nil, nil, 256)
}
// hash_string_to_buffer_128 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_128 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_128(transmute([]byte)(data), hash)
// init_cshake_128 initializes a Context for cSHAKE128.
init_cshake_128 :: proc(ctx: ^Context, domain_sep: []byte) {
_sha3.init_cshake(transmute(^_sha3.Context)(ctx), nil, domain_sep, 128)
}
// hash_bytes_to_buffer_128 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_128 :: proc(data, hash: []byte) {
ctx: Context
ctx.mdlen = DIGEST_SIZE_128
init(&ctx)
update(&ctx, data)
final(&ctx, hash)
// init_cshake_256 initializes a Context for cSHAKE256.
init_cshake_256 :: proc(ctx: ^Context, domain_sep: []byte) {
_sha3.init_cshake(transmute(^_sha3.Context)(ctx), nil, domain_sep, 256)
}
// hash_stream_128 will read the stream in chunks and compute a
// hash from its contents
hash_stream_128 :: proc(s: io.Stream) -> ([DIGEST_SIZE_128]byte, bool) {
hash: [DIGEST_SIZE_128]byte
ctx: Context
ctx.mdlen = DIGEST_SIZE_128
init(&ctx)
// write writes more data into the SHAKE instance. This MUST not be called
// after any reads have been done, and attempts to do so will panic.
write :: proc(ctx: ^Context, data: []byte) {
_sha3.update(transmute(^_sha3.Context)(ctx), data)
}
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
// read reads output from the SHAKE instance. There is no practical upper
// limit to the amount of data that can be read from SHAKE. After read has
// been called one or more times, further calls to write will panic.
read :: proc(ctx: ^Context, dst: []byte) {
ctx_ := transmute(^_sha3.Context)(ctx)
if !ctx.is_finalized {
_sha3.shake_xof(ctx_)
}
final(&ctx, hash[:])
return hash, true
_sha3.shake_out(ctx_, dst)
}
// hash_file_128 will read the file provided by the given handle
// and compute a hash
hash_file_128 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_128]byte, bool) {
if !load_at_once {
return hash_stream_128(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_128(buf[:]), ok
}
}
return [DIGEST_SIZE_128]byte{}, false
// clone clones the Context other into ctx.
clone :: proc(ctx, other: ^Context) {
_sha3.clone(transmute(^_sha3.Context)(ctx), transmute(^_sha3.Context)(other))
}
hash_128 :: proc {
hash_stream_128,
hash_file_128,
hash_bytes_128,
hash_string_128,
hash_bytes_to_buffer_128,
hash_string_to_buffer_128,
}
// hash_string_256 will hash the given input and return the
// computed hash
hash_string_256 :: proc(data: string) -> [DIGEST_SIZE_256]byte {
return hash_bytes_256(transmute([]byte)(data))
}
// hash_bytes_256 will hash the given input and return the
// computed hash
hash_bytes_256 :: proc(data: []byte) -> [DIGEST_SIZE_256]byte {
hash: [DIGEST_SIZE_256]byte
ctx: Context
ctx.mdlen = DIGEST_SIZE_256
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
return hash
}
// hash_string_to_buffer_256 will hash the given input and assign the
// computed hash to the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_string_to_buffer_256 :: proc(data: string, hash: []byte) {
hash_bytes_to_buffer_256(transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer_256 will hash the given input and write the
// computed hash into the second parameter.
// It requires that the destination buffer is at least as big as the digest size
hash_bytes_to_buffer_256 :: proc(data, hash: []byte) {
ctx: Context
ctx.mdlen = DIGEST_SIZE_256
init(&ctx)
update(&ctx, data)
final(&ctx, hash[:])
}
// hash_stream_256 will read the stream in chunks and compute a
// hash from its contents
hash_stream_256 :: proc(s: io.Stream) -> ([DIGEST_SIZE_256]byte, bool) {
hash: [DIGEST_SIZE_256]byte
ctx: Context
ctx.mdlen = DIGEST_SIZE_256
init(&ctx)
buf := make([]byte, 512)
defer delete(buf)
read := 1
for read > 0 {
read, _ = io.read(s, buf)
if read > 0 {
update(&ctx, buf[:read])
}
}
final(&ctx, hash[:])
return hash, true
}
// hash_file_256 will read the file provided by the given handle
// and compute a hash
hash_file_256 :: proc(hd: os.Handle, load_at_once := false) -> ([DIGEST_SIZE_256]byte, bool) {
if !load_at_once {
return hash_stream_256(os.stream_from_handle(hd))
} else {
if buf, ok := os.read_entire_file(hd); ok {
return hash_bytes_256(buf[:]), ok
}
}
return [DIGEST_SIZE_256]byte{}, false
}
hash_256 :: proc {
hash_stream_256,
hash_file_256,
hash_bytes_256,
hash_string_256,
hash_bytes_to_buffer_256,
hash_string_to_buffer_256,
}
/*
Low level API
*/
Context :: _sha3.Sha3_Context
init :: proc(ctx: ^Context) {
_sha3.init(ctx)
}
update :: proc(ctx: ^Context, data: []byte) {
_sha3.update(ctx, data)
}
final :: proc(ctx: ^Context, hash: []byte) {
_sha3.shake_xof(ctx)
_sha3.shake_out(ctx, hash[:])
// reset sanitizes the Context. The Context must be re-initialized to
// be used again.
reset :: proc(ctx: ^Context) {
_sha3.reset(transmute(^_sha3.Context)(ctx))
}

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