-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgcode.go
More file actions
63 lines (63 loc) · 2.61 KB
/
gcode.go
File metadata and controls
63 lines (63 loc) · 2.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
// Package gcode provides streaming read and write of G-code, the control
// language used by CNC machines and 3D printers.
//
// G-code files commonly run to hundreds of megabytes. The package is
// designed around streaming: a [Reader] decodes one [Line] at a time
// from an [io.Reader], and a [Writer] encodes lines to an [io.Writer].
// Neither holds the whole program in memory.
//
// The data model is intentionally uniform across classic G/M/T codes
// and Klipper-style extended commands. A [Command] carries a canonical
// string Name ("G28", "G92.1", "EXCLUDE_OBJECT_DEFINE") and a slice of
// keyed [Argument] values. See [Argument] for the value representation.
//
// Dialects ([Dialect]) describe which commands a particular firmware
// understands. Built-in dialects live in subpackages — see
// [github.com/lestrrat-go/gcode/dialects/marlin],
// [github.com/lestrrat-go/gcode/dialects/reprap], and
// [github.com/lestrrat-go/gcode/dialects/klipper].
//
// A typical streaming pipeline looks like:
//
// r := gcode.NewReader(in)
// w := gcode.NewWriter(out)
// var line gcode.Line
// for {
// if err := r.Read(&line); err == io.EOF {
// break
// } else if err != nil {
// return err
// }
// // ... inspect or mutate line ...
// if err := w.Write(line); err != nil {
// return err
// }
// }
// if err := w.Flush(); err != nil {
// return err
// }
//
// # Buffer ownership
//
// The [Reader] is optimised for zero per-line allocation. Every
// string field on the [Line] it produces — Raw, Command.Name, each
// Argument.Key, each Argument.Raw, Comment.Text — and the
// Command.Args slice itself ALIAS the Reader's internal buffer. They
// are valid only until the next call to [Reader.Read]. Storing any
// of those aliases past that point produces SILENTLY wrong output:
// the Go runtime treats the strings as immutable but the underlying
// bytes have been overwritten. Read-then-act loops are safe; once
// any field needs to outlive the iteration, copy it with
// [Line.Clone], [Command.Clone], [Argument.Clone], or [strings.Clone]
// from the stdlib for an isolated field. See [Reader.Read] for the
// full contract and concrete examples.
//
// # Untrusted input
//
// The Reader's default per-line cap is 16 MiB — enough to absorb the
// longest Klipper extended commands observed in practice. Callers that
// stream G-code from an untrusted source (network upload, third-party
// file) should tighten this with [WithMaxLineSize] to bound worst-case
// allocation. The Reader does no other input-size validation; the rest
// of the file size budget is the caller's responsibility.
package gcode