• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37527

pending completion
#37527

push

local

web-flow
make `IRShow.method_name` inferrable (#49607)

18 of 18 new or added lines in 3 files covered. (100.0%)

68710 of 81829 relevant lines covered (83.97%)

33068903.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

47.89
/base/util.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
## printing with color ##
4

5
const text_colors = Dict{Union{Symbol,Int},String}(
6
    :black         => "\033[30m",
7
    :red           => "\033[31m",
8
    :green         => "\033[32m",
9
    :yellow        => "\033[33m",
10
    :blue          => "\033[34m",
11
    :magenta       => "\033[35m",
12
    :cyan          => "\033[36m",
13
    :white         => "\033[37m",
14
    :light_black   => "\033[90m", # gray
15
    :light_red     => "\033[91m",
16
    :light_green   => "\033[92m",
17
    :light_yellow  => "\033[93m",
18
    :light_blue    => "\033[94m",
19
    :light_magenta => "\033[95m",
20
    :light_cyan    => "\033[96m",
21
    :light_white   => "\033[97m",
22
    :normal        => "\033[0m",
23
    :default       => "\033[39m",
24
    :bold          => "\033[1m",
25
    :italic        => "\033[3m",
26
    :underline     => "\033[4m",
27
    :blink         => "\033[5m",
28
    :reverse       => "\033[7m",
29
    :hidden        => "\033[8m",
30
    :nothing       => "",
31
)
32

33
for i in 0:255
34
    text_colors[i] = "\033[38;5;$(i)m"
35
end
36

37
const disable_text_style = Dict{Symbol,String}(
38
    :bold      => "\033[22m",
39
    :italic    => "\033[23m",
40
    :underline => "\033[24m",
41
    :blink     => "\033[25m",
42
    :reverse   => "\033[27m",
43
    :hidden    => "\033[28m",
44
    :normal    => "",
45
    :default   => "",
46
    :nothing   => "",
47
)
48

49
# Create a docstring with an automatically generated list
50
# of colors.
51
let color_syms = collect(Iterators.filter(x -> !isa(x, Integer), keys(text_colors))),
×
52
    formatting_syms = [:normal, :bold, :italic, :default]
53
    global const available_text_colors = cat(
54
        sort!(intersect(color_syms, formatting_syms), rev=true),
55
        sort!(setdiff(  color_syms, formatting_syms));
56
        dims=1)
57
end
58

59
const available_text_colors_docstring =
60
    string(join([string("`:", key,"`")
61
                 for key in available_text_colors], ",\n", ", or \n"))
62

63
"""Dictionary of color codes for the terminal.
64

65
Available colors are: $available_text_colors_docstring as well as the integers 0 to 255 inclusive.
66

67
The color `:default` will print text in the default color while the color `:normal`
68
will print text with all text properties (like boldness) reset.
69
Printing with the color `:nothing` will print the string without modifications.
70
"""
71
text_colors
72

73
function with_output_color(@nospecialize(f::Function), color::Union{Int, Symbol}, io::IO, args...;
160,431✔
74
        bold::Bool = false, italic::Bool = false, underline::Bool = false, blink::Bool = false,
75
        reverse::Bool = false, hidden::Bool = false)
76
    buf = IOBuffer()
80,183✔
77
    iscolor = get(io, :color, false)::Bool
150,010✔
78
    try f(IOContext(buf, io), args...)
160,366✔
79
    finally
80
        str = String(take!(buf))
80,183✔
81
        if !iscolor
79,384✔
82
            print(io, str)
71,753✔
83
        else
84
            bold && color === :bold && (color = :nothing)
8,430✔
85
            italic && color === :italic && (color = :nothing)
8,430✔
86
            underline && color === :underline && (color = :nothing)
8,430✔
87
            blink && color === :blink && (color = :nothing)
8,430✔
88
            reverse && color === :reverse && (color = :nothing)
8,430✔
89
            hidden && color === :hidden && (color = :nothing)
8,430✔
90
            enable_ansi  = get(text_colors, color, text_colors[:default]) *
16,860✔
91
                               (bold ? text_colors[:bold] : "") *
92
                               (italic ? text_colors[:italic] : "") *
93
                               (underline ? text_colors[:underline] : "") *
94
                               (blink ? text_colors[:blink] : "") *
95
                               (reverse ? text_colors[:reverse] : "") *
96
                               (hidden ? text_colors[:hidden] : "")
97

98
            disable_ansi = (hidden ? disable_text_style[:hidden] : "") *
11,499✔
99
                           (reverse ? disable_text_style[:reverse] : "") *
100
                           (blink ? disable_text_style[:blink] : "") *
101
                           (underline ? disable_text_style[:underline] : "") *
102
                           (bold ? disable_text_style[:bold] : "") *
103
                           (italic ? disable_text_style[:italic] : "") *
104
                               get(disable_text_style, color, text_colors[:default])
105
            first = true
3,167✔
106
            for line in eachsplit(str, '\n')
16,860✔
107
                first || print(buf, '\n')
13,372✔
108
                first = false
5,178✔
109
                isempty(line) && continue
10,901✔
110
                print(buf, enable_ansi, line, disable_ansi)
8,126✔
111
            end
13,372✔
112
            print(io, String(take!(buf)))
88,612✔
113
        end
114
    end
115
end
116

117
"""
118
    printstyled([io], xs...; bold::Bool=false, italic::Bool=false, underline::Bool=false, blink::Bool=false, reverse::Bool=false, hidden::Bool=false, color::Union{Symbol,Int}=:normal)
119

120
Print `xs` in a color specified as a symbol or integer, optionally in bold.
121

122
Keyword `color` may take any of the values $(Base.available_text_colors_docstring)
123
or an integer between 0 and 255 inclusive. Note that not all terminals support 256 colors.
124

125
Keywords `bold=true`, `italic=true`, `underline=true`, `blink=true` are self-explanatory.
126
Keyword `reverse=true` prints with foreground and background colors exchanged,
127
and `hidden=true` should be invisible in the terminal but can still be copied.
128
These properties can be used in any combination.
129

130
See also [`print`](@ref), [`println`](@ref), [`show`](@ref).
131

132
!!! note
133
    Not all terminals support italic output. Some terminals interpret italic as reverse or
134
    blink.
135

136
!!! compat "Julia 1.7"
137
    Keywords except `color` and `bold` were added in Julia 1.7.
138
!!! compat "Julia 1.9"
139
    Support for italic output was added in Julia 1.9.
140
"""
141
@constprop :none printstyled(io::IO, msg...; bold::Bool=false, italic::Bool=false, underline::Bool=false, blink::Bool=false, reverse::Bool=false, hidden::Bool=false, color::Union{Int,Symbol}=:normal) =
160,106✔
142
    with_output_color(print, color, io, msg...; bold=bold, italic=italic, underline=underline, blink=blink, reverse=reverse, hidden=hidden)
143
@constprop :none printstyled(msg...; bold::Bool=false, italic::Bool=false, underline::Bool=false, blink::Bool=false, reverse::Bool=false, hidden::Bool=false, color::Union{Int,Symbol}=:normal) =
5,400✔
144
    printstyled(stdout, msg...; bold=bold, italic=italic, underline=underline, blink=blink, reverse=reverse, hidden=hidden, color=color)
145

146
"""
147
    Base.julia_cmd(juliapath=joinpath(Sys.BINDIR, julia_exename()); cpu_target)
148

149
Return a julia command similar to the one of the running process.
150
Propagates any of the `--cpu-target`, `--sysimage`, `--compile`, `--sysimage-native-code`,
151
`--compiled-modules`, `--pkgimages`, `--inline`, `--check-bounds`, `--optimize`, `--min-optlevel`, `-g`,
152
`--code-coverage`, `--track-allocation`, `--color`, `--startup-file`, and `--depwarn`
153
command line arguments that are not at their default values.
154

155
Among others, `--math-mode`, `--warn-overwrite`, and `--trace-compile` are notably not propagated currently.
156

157
To get the julia command without propagated command line arguments, `julia_cmd()[1]` can be used.
158

159
!!! compat "Julia 1.1"
160
    Only the `--cpu-target`, `--sysimage`, `--depwarn`, `--compile` and `--check-bounds` flags were propagated before Julia 1.1.
161

162
!!! compat "Julia 1.5"
163
    The flags `--color` and `--startup-file` were added in Julia 1.5.
164

165
!!! compat "Julia 1.9"
166
    The keyword argument `cpu_target` was added.
167

168
    The flag `--pkgimages` was added in Julia 1.9.
169
"""
170
function julia_cmd(julia=joinpath(Sys.BINDIR, julia_exename()); cpu_target::Union{Nothing,String} = nothing)
1,223✔
171
    opts = JLOptions()
394✔
172
    if cpu_target === nothing
394✔
173
        cpu_target = unsafe_string(opts.cpu_target)
394✔
174
    end
175
    image_file = unsafe_string(opts.image_file)
394✔
176
    addflags = String[]
394✔
177
    let compile = if opts.compile_enabled == 0
394✔
178
                      "no"
×
179
                  elseif opts.compile_enabled == 2
394✔
180
                      "all"
×
181
                  elseif opts.compile_enabled == 3
394✔
182
                      "min"
×
183
                  else
184
                      "" # default = "yes"
1,182✔
185
                  end
186
        isempty(compile) || push!(addflags, "--compile=$compile")
394✔
187
    end
188
    let depwarn = if opts.depwarn == 1
394✔
189
                      "yes"
×
190
                  elseif opts.depwarn == 2
394✔
191
                      "error"
204✔
192
                  else
193
                      "" # default = "no"
788✔
194
                  end
195
        isempty(depwarn) || push!(addflags, "--depwarn=$depwarn")
598✔
196
    end
197
    let check_bounds = if opts.check_bounds == 1
394✔
198
                      "yes" # on
198✔
199
                  elseif opts.check_bounds == 2
196✔
200
                      "no" # off
×
201
                  else
202
                      "" # default = "auto"
590✔
203
                  end
204
        isempty(check_bounds) || push!(addflags, "--check-bounds=$check_bounds")
592✔
205
    end
206
    opts.can_inline == 0 && push!(addflags, "--inline=no")
394✔
207
    opts.use_compiled_modules == 0 && push!(addflags, "--compiled-modules=no")
394✔
208
    opts.opt_level == 2 || push!(addflags, "-O$(opts.opt_level)")
412✔
209
    opts.opt_level_min == 0 || push!(addflags, "--min-optlevel=$(opts.opt_level_min)")
394✔
210
    push!(addflags, "-g$(opts.debug_level)")
394✔
211
    if opts.code_coverage != 0
394✔
212
        # Forward the code-coverage flag only if applicable (if the filename is pid-dependent)
213
        coverage_file = (opts.output_code_coverage != C_NULL) ?  unsafe_string(opts.output_code_coverage) : ""
394✔
214
        if isempty(coverage_file) || occursin("%p", coverage_file)
788✔
215
            if opts.code_coverage == 1
394✔
216
                push!(addflags, "--code-coverage=user")
×
217
            elseif opts.code_coverage == 2
394✔
218
                push!(addflags, "--code-coverage=all")
394✔
219
            elseif opts.code_coverage == 3
×
220
                push!(addflags, "--code-coverage=@$(unsafe_string(opts.tracked_path))")
×
221
            end
222
            isempty(coverage_file) || push!(addflags, "--code-coverage=$coverage_file")
788✔
223
        end
224
    end
225
    if opts.malloc_log == 1
394✔
226
        push!(addflags, "--track-allocation=user")
×
227
    elseif opts.malloc_log == 2
394✔
228
        push!(addflags, "--track-allocation=all")
×
229
    elseif opts.malloc_log == 3
394✔
230
        push!(addflags, "--track-allocation=@$(unsafe_string(opts.tracked_path))")
×
231
    end
232
    if opts.color == 1
394✔
233
        push!(addflags, "--color=yes")
10✔
234
    elseif opts.color == 2
384✔
235
        push!(addflags, "--color=no")
×
236
    end
237
    if opts.startupfile == 2
394✔
238
        push!(addflags, "--startup-file=no")
217✔
239
    end
240
    if opts.use_sysimage_native_code == 0
394✔
241
        push!(addflags, "--sysimage-native-code=no")
394✔
242
    end
243
    if opts.use_pkgimages == 0
394✔
244
        push!(addflags, "--pkgimages=no")
394✔
245
    else
246
        # If pkgimage is set, malloc_log and code_coverage should not
247
        @assert opts.malloc_log == 0 && opts.code_coverage == 0
×
248
    end
249
    return `$julia -C$cpu_target -J$image_file $addflags`
394✔
250
end
251

252
function julia_exename()
254✔
253
    if !Base.isdebugbuild()
630✔
254
        return @static Sys.iswindows() ? "julia.exe" : "julia"
630✔
255
    else
256
        return @static Sys.iswindows() ? "julia-debug.exe" : "julia-debug"
×
257
    end
258
end
259

260
"""
261
    securezero!(o)
262

263
`securezero!` fills the memory associated with an object `o` with zeros.
264
Unlike `fill!(o,0)` and similar code, which might be optimized away by
265
the compiler for objects about to be discarded, the `securezero!` function
266
will always be called.
267
"""
268
function securezero! end
269
@noinline securezero!(a::AbstractArray{<:Number}) = fill!(a, 0)
130✔
270
@noinline unsafe_securezero!(p::Ptr{T}, len::Integer=1) where {T} =
1✔
271
    ccall(:memset, Ptr{T}, (Ptr{T}, Cint, Csize_t), p, 0, len*sizeof(T))
272
unsafe_securezero!(p::Ptr{Cvoid}, len::Integer=1) = Ptr{Cvoid}(unsafe_securezero!(Ptr{UInt8}(p), len))
×
273

274
"""
275
    Base.getpass(message::AbstractString) -> Base.SecretBuffer
276

277
Display a message and wait for the user to input a secret, returning an `IO`
278
object containing the secret.
279

280
!!! info "Windows"
281
    Note that on Windows, the secret might be displayed as it is typed; see
282
    `Base.winprompt` for securely retrieving username/password pairs from a
283
    graphical interface.
284
"""
285
function getpass end
286

287
# Note, this helper only works within `with_raw_tty()` on POSIX platforms!
288
function _getch()
×
289
    @static if Sys.iswindows()
×
290
        return UInt8(ccall(:_getch, Cint, ()))
×
291
    else
292
        return read(stdin, UInt8)
×
293
    end
294
end
295

296
const termios_size = Int(ccall(:jl_termios_size, Cint, ()))
297
make_termios() = zeros(UInt8, termios_size)
×
298

299
# These values seem to hold on all OSes we care about:
300
# glibc Linux, musl Linux, macOS, FreeBSD
301
@enum TCSETATTR_FLAGS TCSANOW=0 TCSADRAIN=1 TCSAFLUSH=2
302

303
function tcgetattr(fd::RawFD, termios)
×
304
    ret = ccall(:tcgetattr, Cint, (Cint, Ptr{Cvoid}), fd, termios)
×
305
    if ret != 0
×
306
        throw(IOError("tcgetattr failed", ret))
×
307
    end
308
end
309
function tcsetattr(fd::RawFD, termios, mode::TCSETATTR_FLAGS = TCSADRAIN)
×
310
    ret = ccall(:tcsetattr, Cint, (Cint, Cint, Ptr{Cvoid}), fd, Cint(mode), termios)
×
311
    if ret != 0
×
312
        throw(IOError("tcsetattr failed", ret))
×
313
    end
314
end
315
cfmakeraw(termios) = ccall(:cfmakeraw, Cvoid, (Ptr{Cvoid},), termios)
×
316

317
function with_raw_tty(f::Function, input::TTY)
×
318
    input === stdin || throw(ArgumentError("with_raw_tty only works for stdin"))
×
319
    fd = RawFD(0)
×
320

321
    # If we're on windows, we do nothing, as we have access to `_getch()` quite easily
322
    @static if Sys.iswindows()
×
323
        return f()
×
324
    end
325

326
    # Get the current terminal mode
327
    old_termios = make_termios()
×
328
    tcgetattr(fd, old_termios)
×
329
    try
×
330
        # Set a new, raw, terminal mode
331
        new_termios = copy(old_termios)
×
332
        cfmakeraw(new_termios)
×
333
        tcsetattr(fd, new_termios)
×
334

335
        # Call the user-supplied callback
336
        f()
×
337
    finally
338
        # Always restore the terminal mode
339
        tcsetattr(fd, old_termios)
×
340
    end
341
end
342

343
function getpass(input::TTY, output::IO, prompt::AbstractString)
×
344
    input === stdin || throw(ArgumentError("getpass only works for stdin"))
×
345
    with_raw_tty(stdin) do
×
346
        print(output, prompt, ": ")
×
347
        flush(output)
×
348
        s = SecretBuffer()
×
349
        plen = 0
×
350
        while true
×
351
            c = _getch()
×
352
            if c == 0xff || c == UInt8('\n') || c == UInt8('\r') || c == 0x04
×
353
                break # EOF or return
×
354
            elseif c == 0x00 || c == 0xe0
×
355
                _getch() # ignore function/arrow keys
×
356
            elseif c == UInt8('\b') && plen > 0
×
357
                plen -= 1 # delete last character on backspace
×
358
            elseif !iscntrl(Char(c)) && plen < 128
×
359
                write(s, c)
×
360
            end
361
        end
×
362
        return seekstart(s)
×
363
    end
364
end
365

366
# allow new getpass methods to be defined if stdin has been
367
# redirected to some custom stream, e.g. in IJulia.
368
getpass(prompt::AbstractString) = getpass(stdin, stdout, prompt)
1✔
369

370
"""
371
    prompt(message; default="") -> Union{String, Nothing}
372

373
Displays the `message` then waits for user input. Input is terminated when a newline (\\n)
374
is encountered or EOF (^D) character is entered on a blank line. If a `default` is provided
375
then the user can enter just a newline character to select the `default`.
376

377
See also `Base.winprompt` (for Windows) and `Base.getpass` for secure entry of passwords.
378

379
# Example
380

381
```julia-repl
382
julia> your_name = Base.prompt("Enter your name");
383
Enter your name: Logan
384

385
julia> your_name
386
"Logan"
387
```
388
"""
389
function prompt(input::IO, output::IO, message::AbstractString; default::AbstractString="")
2✔
390
    msg = !isempty(default) ? "$message [$default]: " : "$message: "
1✔
391
    print(output, msg)
1✔
392
    uinput = readline(input, keep=true)
1✔
393
    isempty(uinput) && return nothing  # Encountered an EOF
1✔
394
    uinput = chomp(uinput)
1✔
395
    isempty(uinput) ? default : uinput
1✔
396
end
397

398
# allow new prompt methods to be defined if stdin has been
399
# redirected to some custom stream, e.g. in IJulia.
400
prompt(message::AbstractString; default::AbstractString="") = prompt(stdin, stdout, message, default=default)
2✔
401

402
# Windows authentication prompt
403
if Sys.iswindows()
404
    struct CREDUI_INFO
405
        cbSize::UInt32
406
        parent::Ptr{Cvoid}
407
        pszMessageText::Ptr{UInt16}
408
        pszCaptionText::Ptr{UInt16}
409
        banner::Ptr{Cvoid}
410
    end
411

412
    const CREDUIWIN_GENERIC                 = 0x0001
413
    const CREDUIWIN_IN_CRED_ONLY            = 0x0020
414
    const CREDUIWIN_ENUMERATE_CURRENT_USER  = 0x0200
415

416
    const CRED_PACK_GENERIC_CREDENTIALS     = 0x0004
417

418
    const ERROR_SUCCESS                     = 0x0000
419
    const ERROR_CANCELLED                   = 0x04c7
420

421
    function winprompt(message, caption, default_username; prompt_username = true)
×
422
        # Step 1: Create an encrypted username/password bundle that will be used to set
423
        #         the default username (in theory could also provide a default password)
424
        credbuf = Vector{UInt8}(undef, 1024)
×
425
        credbufsize = Ref{UInt32}(sizeof(credbuf))
×
426
        succeeded = ccall((:CredPackAuthenticationBufferW, "credui.dll"), stdcall, Bool,
×
427
            (UInt32, Cwstring, Cwstring, Ptr{UInt8}, Ptr{UInt32}),
428
             CRED_PACK_GENERIC_CREDENTIALS, default_username, "", credbuf, credbufsize)
429
        if !succeeded
×
430
            credbuf = resize!(credbuf, credbufsize[])
×
431
            succeeded = ccall((:CredPackAuthenticationBufferW, "credui.dll"), stdcall, Bool,
×
432
                (UInt32, Cwstring, Cwstring, Ptr{UInt8}, Ptr{UInt32}),
433
                 CRED_PACK_GENERIC_CREDENTIALS, default_username, "", credbuf, credbufsize)
434
            @assert succeeded
×
435
        end
436

437
        # Step 2: Create the actual dialog
438
        #      2.1: Set up the window
439
        messageArr = Base.cwstring(message)
×
440
        captionArr = Base.cwstring(caption)
×
441
        pfSave = Ref{Bool}(false)
×
442
        cred = Ref{CREDUI_INFO}(CREDUI_INFO(sizeof(CREDUI_INFO), C_NULL, pointer(messageArr), pointer(captionArr), C_NULL))
×
443
        dwflags = CREDUIWIN_GENERIC | CREDUIWIN_ENUMERATE_CURRENT_USER
×
444
        if !prompt_username
×
445
            # Disable setting anything other than default_username
446
            dwflags |= CREDUIWIN_IN_CRED_ONLY
×
447
        end
448
        authPackage = Ref{Culong}(0)
×
449
        outbuf_data = Ref{Ptr{Cvoid}}(C_NULL)
×
450
        outbuf_size = Ref{Culong}(0)
×
451

452
        #      2.2: Do the actual request
453
        code = ccall((:CredUIPromptForWindowsCredentialsW, "credui.dll"), stdcall, UInt32, (Ptr{CREDUI_INFO}, UInt32, Ptr{Culong},
×
454
            Ptr{Cvoid}, Culong, Ptr{Ptr{Cvoid}}, Ptr{Culong}, Ptr{Bool}, UInt32), cred, 0, authPackage, credbuf, credbufsize[],
455
            outbuf_data, outbuf_size, pfSave, dwflags)
456

457
        #      2.3: If that failed for any reason other than the user canceling, error out.
458
        #           If the user canceled, just return nothing
459
        code == ERROR_CANCELLED && return nothing
×
460
        windowserror(:winprompt, code != ERROR_SUCCESS)
×
461

462
        # Step 3: Convert encrypted credentials back to plain text
463
        passbuf = Vector{UInt16}(undef, 1024)
×
464
        passlen = Ref{UInt32}(length(passbuf))
×
465
        usernamebuf = Vector{UInt16}(undef, 1024)
×
466
        usernamelen = Ref{UInt32}(length(usernamebuf))
×
467
        # Need valid buffers for domain, even though we don't care
468
        dummybuf = Vector{UInt16}(undef, 1024)
×
469
        succeeded = ccall((:CredUnPackAuthenticationBufferW, "credui.dll"), Bool,
×
470
            (UInt32, Ptr{Cvoid}, UInt32, Ptr{UInt16}, Ptr{UInt32}, Ptr{UInt16}, Ptr{UInt32}, Ptr{UInt16}, Ptr{UInt32}),
471
            0, outbuf_data[], outbuf_size[], usernamebuf, usernamelen, dummybuf, Ref{UInt32}(1024), passbuf, passlen)
472
        windowserror(:winprompt, !succeeded)
×
473

474
        # Step 4: Free the encrypted buffer
475
        # ccall(:SecureZeroMemory, Ptr{Cvoid}, (Ptr{Cvoid}, Csize_t), outbuf_data[], outbuf_size[]) - not an actual function
476
        unsafe_securezero!(outbuf_data[], outbuf_size[])
×
477
        ccall((:CoTaskMemFree, "ole32.dll"), Cvoid, (Ptr{Cvoid},), outbuf_data[])
×
478

479
        # Done.
480
        passbuf_ = passbuf[1:passlen[]-1]
×
481
        result = (String(transcode(UInt8, usernamebuf[1:usernamelen[]-1])),
×
482
                  SecretBuffer!(transcode(UInt8, passbuf_)))
483
        securezero!(passbuf_)
×
484
        securezero!(passbuf)
×
485

486
        return result
×
487
    end
488

489
end
490

491
unsafe_crc32c(a, n, crc) = ccall(:jl_crc32c, UInt32, (UInt32, Ptr{UInt8}, Csize_t), crc, a, n)
88,127✔
492

493
_crc32c(a::NTuple{<:Any, UInt8}, crc::UInt32=0x00000000) =
57,757✔
494
    unsafe_crc32c(Ref(a), length(a) % Csize_t, crc)
495
_crc32c(a::Union{Array{UInt8},FastContiguousSubArray{UInt8,N,<:Array{UInt8}} where N}, crc::UInt32=0x00000000) =
2,990✔
496
    unsafe_crc32c(a, length(a) % Csize_t, crc)
497

498
function _crc32c(s::Union{String, SubString{String}}, crc::UInt32=0x00000000)
130✔
499
    unsafe_crc32c(s, sizeof(s) % Csize_t, crc)
405✔
500
end
501

502
function _crc32c(io::IO, nb::Integer, crc::UInt32=0x00000000)
577✔
503
    nb < 0 && throw(ArgumentError("number of bytes to checksum must be ≥ 0, got $nb"))
1,036✔
504
    # use block size 24576=8192*3, since that is the threshold for
505
    # 3-way parallel SIMD code in the underlying jl_crc32c C function.
506
    buf = Vector{UInt8}(undef, min(nb, 24576))
577✔
507
    while !eof(io) && nb > 24576
28,228✔
508
        n = readbytes!(io, buf)
27,651✔
509
        crc = unsafe_crc32c(buf, n, crc)
27,651✔
510
        nb -= n
27,651✔
511
    end
27,651✔
512
    return unsafe_crc32c(buf, readbytes!(io, buf, min(nb, length(buf))), crc)
577✔
513
end
514
_crc32c(io::IO, crc::UInt32=0x00000000) = _crc32c(io, typemax(Int64), crc)
×
515
_crc32c(io::IOStream, crc::UInt32=0x00000000) = _crc32c(io, filesize(io)-position(io), crc)
225✔
516
_crc32c(uuid::UUID, crc::UInt32=0x00000000) = _crc32c(uuid.value, crc)
116,550✔
517
_crc32c(x::UInt128, crc::UInt32=0x00000000) =
58,275✔
518
    ccall(:jl_crc32c, UInt32, (UInt32, Ref{UInt128}, Csize_t), crc, x, 16)
519
_crc32c(x::UInt64, crc::UInt32=0x00000000) =
55✔
520
    ccall(:jl_crc32c, UInt32, (UInt32, Ref{UInt64}, Csize_t), crc, x, 8)
521
_crc32c(x::UInt32, crc::UInt32=0x00000000) =
×
522
    ccall(:jl_crc32c, UInt32, (UInt32, Ref{UInt32}, Csize_t), crc, x, 4)
523
_crc32c(x::UInt16, crc::UInt32=0x00000000) =
×
524
    ccall(:jl_crc32c, UInt32, (UInt32, Ref{UInt16}, Csize_t), crc, x, 2)
525
_crc32c(x::UInt8, crc::UInt32=0x00000000) =
55✔
526
    ccall(:jl_crc32c, UInt32, (UInt32, Ref{UInt8}, Csize_t), crc, x, 1)
527

528
"""
529
    @kwdef typedef
530

531
This is a helper macro that automatically defines a keyword-based constructor for the type
532
declared in the expression `typedef`, which must be a `struct` or `mutable struct`
533
expression. The default argument is supplied by declaring fields of the form `field::T =
534
default` or `field = default`. If no default is provided then the keyword argument becomes
535
a required keyword argument in the resulting type constructor.
536

537
Inner constructors can still be defined, but at least one should accept arguments in the
538
same form as the default inner constructor (i.e. one positional argument per field) in
539
order to function correctly with the keyword outer constructor.
540

541
!!! compat "Julia 1.1"
542
    `Base.@kwdef` for parametric structs, and structs with supertypes
543
    requires at least Julia 1.1.
544

545
!!! compat "Julia 1.9"
546
    This macro is exported as of Julia 1.9.
547

548
# Examples
549
```jldoctest
550
julia> @kwdef struct Foo
551
           a::Int = 1         # specified default
552
           b::String          # required keyword
553
       end
554
Foo
555

556
julia> Foo(b="hi")
557
Foo(1, "hi")
558

559
julia> Foo()
560
ERROR: UndefKeywordError: keyword argument `b` not assigned
561
Stacktrace:
562
[...]
563
```
564
"""
565
macro kwdef(expr)
566
    expr = macroexpand(__module__, expr) # to expand @static
567
    isexpr(expr, :struct) || error("Invalid usage of @kwdef")
568
    T = expr.args[2]
569
    if T isa Expr && T.head === :<:
570
        T = T.args[1]
571
    end
572

573
    params_ex = Expr(:parameters)
574
    call_args = Any[]
575

576
    _kwdef!(expr.args[3], params_ex.args, call_args)
577
    # Only define a constructor if the type has fields, otherwise we'll get a stack
578
    # overflow on construction
579
    if !isempty(params_ex.args)
580
        if T isa Symbol
581
            sig = :(($(esc(T)))($params_ex))
582
            call = :(($(esc(T)))($(call_args...)))
583
            body = Expr(:block, __source__, call)
584
            kwdefs = Expr(:function, sig, body)
585
        elseif isexpr(T, :curly)
586
            # if T == S{A<:AA,B<:BB}, define two methods
587
            #   S(...) = ...
588
            #   S{A,B}(...) where {A<:AA,B<:BB} = ...
589
            S = T.args[1]
590
            P = T.args[2:end]
591
            Q = Any[isexpr(U, :<:) ? U.args[1] : U for U in P]
592
            SQ = :($S{$(Q...)})
593
            body1 = Expr(:block, __source__, :(($(esc(S)))($(call_args...))))
594
            sig1 = :(($(esc(S)))($params_ex))
595
            def1 = Expr(:function, sig1, body1)
596
            body2 = Expr(:block, __source__, :(($(esc(SQ)))($(call_args...))))
597
            sig2 = :(($(esc(SQ)))($params_ex) where {$(esc.(P)...)})
598
            def2 = Expr(:function, sig2, body2)
599
            kwdefs = Expr(:block, def1, def2)
600
        else
601
            error("Invalid usage of @kwdef")
602
        end
603
    else
604
        kwdefs = nothing
605
    end
606
    return quote
607
        Base.@__doc__ $(esc(expr))
608
        $kwdefs
609
    end
610
end
611

612
# @kwdef helper function
613
# mutates arguments inplace
614
function _kwdef!(blk, params_args, call_args)
×
615
    for i in eachindex(blk.args)
×
616
        ei = blk.args[i]
×
617
        if ei isa Symbol
×
618
            #  var
619
            push!(params_args, ei)
×
620
            push!(call_args, ei)
×
621
        elseif ei isa Expr
×
622
            is_atomic = ei.head === :atomic
×
623
            ei = is_atomic ? first(ei.args) : ei # strip "@atomic" and add it back later
×
624
            is_const = ei.head === :const
×
625
            ei = is_const ? first(ei.args) : ei # strip "const" and add it back later
×
626
            # Note: `@atomic const ..` isn't valid, but reconstruct it anyway to serve a nice error
627
            if ei isa Symbol
×
628
                # const var
629
                push!(params_args, ei)
×
630
                push!(call_args, ei)
×
631
            elseif ei.head === :(=)
×
632
                lhs = ei.args[1]
×
633
                if lhs isa Symbol
×
634
                    #  var = defexpr
635
                    var = lhs
×
636
                elseif lhs isa Expr && lhs.head === :(::) && lhs.args[1] isa Symbol
×
637
                    #  var::T = defexpr
638
                    var = lhs.args[1]
×
639
                else
640
                    # something else, e.g. inline inner constructor
641
                    #   F(...) = ...
642
                    continue
×
643
                end
644
                defexpr = ei.args[2]  # defexpr
×
645
                push!(params_args, Expr(:kw, var, esc(defexpr)))
×
646
                push!(call_args, var)
×
647
                lhs = is_const ? Expr(:const, lhs) : lhs
×
648
                lhs = is_atomic ? Expr(:atomic, lhs) : lhs
×
649
                blk.args[i] = lhs # overrides arg
×
650
            elseif ei.head === :(::) && ei.args[1] isa Symbol
×
651
                # var::Typ
652
                var = ei.args[1]
×
653
                push!(params_args, var)
×
654
                push!(call_args, var)
×
655
            elseif ei.head === :block
×
656
                # can arise with use of @static inside type decl
657
                _kwdef!(ei, params_args, call_args)
×
658
            end
659
        end
660
    end
×
661
    blk
×
662
end
663

664
# testing
665

666
"""
667
    Base.runtests(tests=["all"]; ncores=ceil(Int, Sys.CPU_THREADS / 2),
668
                  exit_on_error=false, revise=false, [seed])
669

670
Run the Julia unit tests listed in `tests`, which can be either a string or an array of
671
strings, using `ncores` processors. If `exit_on_error` is `false`, when one test
672
fails, all remaining tests in other files will still be run; they are otherwise discarded,
673
when `exit_on_error == true`.
674
If `revise` is `true`, the `Revise` package is used to load any modifications to `Base` or
675
to the standard libraries before running the tests.
676
If a seed is provided via the keyword argument, it is used to seed the
677
global RNG in the context where the tests are run; otherwise the seed is chosen randomly.
678
"""
679
function runtests(tests = ["all"]; ncores::Int = ceil(Int, Sys.CPU_THREADS / 2),
4✔
680
                  exit_on_error::Bool=false,
681
                  revise::Bool=false,
682
                  seed::Union{BitInteger,Nothing}=nothing)
683
    if isa(tests,AbstractString)
2✔
684
        tests = split(tests)
×
685
    end
686
    exit_on_error && push!(tests, "--exit-on-error")
2✔
687
    revise && push!(tests, "--revise")
2✔
688
    seed !== nothing && push!(tests, "--seed=0x$(string(seed % UInt128, base=16))") # cast to UInt128 to avoid a minus sign
2✔
689
    ENV2 = copy(ENV)
2✔
690
    ENV2["JULIA_CPU_THREADS"] = "$ncores"
2✔
691
    pathsep = Sys.iswindows() ? ";" : ":"
2✔
692
    ENV2["JULIA_DEPOT_PATH"] = string(mktempdir(; cleanup = true), pathsep) # make sure the default depots can be loaded
2✔
693
    delete!(ENV2, "JULIA_LOAD_PATH")
2✔
694
    delete!(ENV2, "JULIA_PROJECT")
2✔
695
    try
2✔
696
        run(setenv(`$(julia_cmd()) $(joinpath(Sys.BINDIR,
2✔
697
            Base.DATAROOTDIR, "julia", "test", "runtests.jl")) $tests`, ENV2))
698
        nothing
2✔
699
    catch
700
        buf = PipeBuffer()
2✔
701
        original_load_path = copy(Base.LOAD_PATH); empty!(Base.LOAD_PATH); pushfirst!(Base.LOAD_PATH, "@stdlib")
6✔
702
        Base.require(Base, :InteractiveUtils).versioninfo(buf)
2✔
703
        empty!(Base.LOAD_PATH); append!(Base.LOAD_PATH, original_load_path)
4✔
704
        error("A test has failed. Please submit a bug report (https://github.com/JuliaLang/julia/issues)\n" *
2✔
705
              "including error messages above and the output of versioninfo():\n$(read(buf, String))")
706
    end
707
end
708

709
"""
710
    isdebugbuild()
711

712
Return `true` if julia is a debug version.
713
"""
714
function isdebugbuild()
8✔
715
    return ccall(:jl_is_debugbuild, Cint, ()) != 0
638✔
716
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc